Merge remote-tracking branch 'upstream/master' into hints_clicking

* upstream/master: (22 commits)
  Regenerate authors.
  Only run geolocation tests on CI
  Switch to flake8-docstrings with pydocstyle
  Fix lint
  Move pylint plugins to an installed package.
  Include pytest-xvfb properly in frozen tests
  tests: Handle trailing / in wait_for_load_finished.
  Fix lint.
  tox: Upgrade hypothesis to 3.0.2.
  tests: Add first end-to-end test for hints.
  hints: Log the used hint chars
  bdd: use quteproc.wait_for_load_finished.
  Remove xvfbwrapper from freeze_tests.py.
  Regenerate authors.
  Combine launch/crash time into one section.
  Split long lines.
  Switch to pytest-xvfb. Fixes #1309.
  no ellipsis is inserted in big windows
  Regenerate authors.
  fixes #1308
  ...
This commit is contained in:
Jakub Klinkovský 2016-02-23 17:40:02 +01:00
commit 58d2d92d67
26 changed files with 138 additions and 76 deletions

View File

@ -3,10 +3,10 @@
[MASTER] [MASTER]
ignore=resources.py ignore=resources.py
extension-pkg-whitelist=PyQt5,sip extension-pkg-whitelist=PyQt5,sip
load-plugins=pylint_checkers.config, load-plugins=qute_pylint.config,
pylint_checkers.modeline, qute_pylint.modeline,
pylint_checkers.openencoding, qute_pylint.openencoding,
pylint_checkers.settrace qute_pylint.settrace
[MESSAGES CONTROL] [MESSAGES CONTROL]
enable=all enable=all

View File

@ -16,7 +16,6 @@ env:
- TESTENV=unittests-nodisp - TESTENV=unittests-nodisp
- TESTENV=misc - TESTENV=misc
- TESTENV=vulture - TESTENV=vulture
- TESTENV=pydocstyle
- TESTENV=flake8 - TESTENV=flake8
- TESTENV=pyroma - TESTENV=pyroma
- TESTENV=check-manifest - TESTENV=check-manifest
@ -52,8 +51,6 @@ matrix:
env: TESTENV=misc env: TESTENV=misc
- os: osx - os: osx
env: TESTENV=vulture env: TESTENV=vulture
- os: osx
env: TESTENV=pydocstyle
- os: osx - os: osx
env: TESTENV=flake8 env: TESTENV=flake8
- os: osx - os: osx

View File

@ -147,9 +147,9 @@ Contributors, sorted by the number of commits in descending order:
* Bruno Oliveira * Bruno Oliveira
* Alexander Cogneau * Alexander Cogneau
* Martin Tournoij * Martin Tournoij
* Felix Van der Jeugt
* Raphael Pierzina * Raphael Pierzina
* Joel Torstensson * Joel Torstensson
* Felix Van der Jeugt
* Claude * Claude
* Patric Schmitz * Patric Schmitz
* meles5 * meles5
@ -184,6 +184,7 @@ Contributors, sorted by the number of commits in descending order:
* Link * Link
* Larry Hynes * Larry Hynes
* Johannes Altmanninger * Johannes Altmanninger
* avk
* Samir Benmendil * Samir Benmendil
* Regina Hug * Regina Hug
* Mathias Fussenegger * Mathias Fussenegger

View File

@ -9,13 +9,14 @@ markers =
osx: Tests which only can run on OS X. osx: Tests which only can run on OS X.
not_osx: Tests which can not run on OS X. not_osx: Tests which can not run on OS X.
not_frozen: Tests which can't be run if sys.frozen is True. not_frozen: Tests which can't be run if sys.frozen is True.
not_xvfb: Tests which can't be run with Xvfb. no_xvfb: Tests which can't be run with Xvfb.
frozen: Tests which can only be run if sys.frozen is True. frozen: Tests which can only be run if sys.frozen is True.
integration: Tests which test a bigger portion of code, run without coverage. integration: Tests which test a bigger portion of code, run without coverage.
skip: Always skipped test. skip: Always skipped test.
pyqt531_or_newer: Needs PyQt 5.3.1 or newer. pyqt531_or_newer: Needs PyQt 5.3.1 or newer.
xfail_norun: xfail the test with out running it xfail_norun: xfail the test with out running it
flaky: Tests which are flaky and should be rerun flaky: Tests which are flaky and should be rerun
ci: Tests which should only run on CI.
qt_log_level_fail = WARNING qt_log_level_fail = WARNING
qt_log_ignore = qt_log_ignore =
^SpellCheck: .* ^SpellCheck: .*

View File

@ -714,6 +714,7 @@ class HintManager(QObject):
if not elems: if not elems:
raise cmdexc.CommandError("No elements found.") raise cmdexc.CommandError("No elements found.")
hints = self._hint_strings(elems) hints = self._hint_strings(elems)
log.hints.debug("hints: {}".format(', '.join(hints)))
for e, hint in zip(elems, hints): for e, hint in zip(elems, hints):
label = self._draw_label(e, hint) label = self._draw_label(e, hint)
self._context.elems[hint] = ElemTuple(e, label) self._context.elems[hint] = ElemTuple(e, label)

View File

@ -26,6 +26,7 @@ import html
import getpass import getpass
import fnmatch import fnmatch
import traceback import traceback
import datetime
import pkg_resources import pkg_resources
from PyQt5.QtCore import pyqtSlot, Qt, QSize, qVersion from PyQt5.QtCore import pyqtSlot, Qt, QSize, qVersion
@ -236,7 +237,9 @@ class _CrashDialog(QDialog):
try: try:
application = QApplication.instance() application = QApplication.instance()
launch_time = application.launch_time.ctime() launch_time = application.launch_time.ctime()
self._crash_info.append(('Launch time', launch_time)) crash_time = datetime.datetime.now().ctime()
text = 'Launch: {}\nCrash: {}'.format(launch_time, crash_time)
self._crash_info.append(('Timestamps', text))
except Exception: except Exception:
self._crash_info.append(("Launch time", traceback.format_exc())) self._crash_info.append(("Launch time", traceback.format_exc()))
try: try:

View File

@ -51,10 +51,11 @@ else:
colorama.deinit() colorama.deinit()
# Log formats to use. # Log formats to use.
SIMPLE_FMT = '{levelname}: {message}' SIMPLE_FMT = '{asctime:8} {levelname}: {message}'
EXTENDED_FMT = ('{asctime:8} {levelname:8} {name:10} {module}:{funcName}:' EXTENDED_FMT = ('{asctime:8} {levelname:8} {name:10} {module}:{funcName}:'
'{lineno} {message}') '{lineno} {message}')
SIMPLE_FMT_COLORED = '%(log_color)s%(levelname)s%(reset)s: %(message)s' SIMPLE_FMT_COLORED = ('%(green)s%(asctime)-8s%(reset)s '
'%(log_color)s%(levelname)s%(reset)s: %(message)s')
EXTENDED_FMT_COLORED = ( EXTENDED_FMT_COLORED = (
'%(green)s%(asctime)-8s%(reset)s ' '%(green)s%(asctime)-8s%(reset)s '
'%(log_color)s%(levelname)-8s%(reset)s ' '%(log_color)s%(levelname)-8s%(reset)s '

View File

@ -55,8 +55,7 @@ def get_build_exe_options():
opts = freeze.get_build_exe_options(skip_html=True) opts = freeze.get_build_exe_options(skip_html=True)
opts['includes'] += pytest.freeze_includes() # pylint: disable=no-member opts['includes'] += pytest.freeze_includes() # pylint: disable=no-member
opts['includes'] += ['unittest.mock', 'PyQt5.QtTest', 'hypothesis', 'bs4', opts['includes'] += ['unittest.mock', 'PyQt5.QtTest', 'hypothesis', 'bs4',
'httpbin', 'jinja2.ext', 'xvfbwrapper', 'httpbin', 'jinja2.ext', 'cherrypy.wsgiserver',
'cherrypy.wsgiserver',
'cherrypy.wsgiserver.wsgiserver3', 'pstats'] 'cherrypy.wsgiserver.wsgiserver3', 'pstats']
httpbin_dir = os.path.dirname(httpbin.__file__) httpbin_dir = os.path.dirname(httpbin.__file__)

View File

@ -0,0 +1,25 @@
#!/usr/bin/env python3
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""This is only here so we can install those plugins in tox.ini easily."""
from setuptools import setup
setup(name='qute_pylint', packages=['qute_pylint'])

View File

@ -28,7 +28,8 @@ import pytest_mock
import pytest_catchlog import pytest_catchlog
import pytest_instafail import pytest_instafail
import pytest_faulthandler import pytest_faulthandler
import pytest_xvfb
sys.exit(pytest.main(plugins=[pytestqt.plugin, pytest_mock, sys.exit(pytest.main(plugins=[pytestqt.plugin, pytest_mock,
pytest_catchlog, pytest_instafail, pytest_catchlog, pytest_instafail,
pytest_faulthandler])) pytest_faulthandler, pytest_xvfb]))

View File

@ -60,7 +60,7 @@ def main():
] ]
toxinidir = sys.argv[1] toxinidir = sys.argv[1]
pythonpath = os.environ['PYTHONPATH'].split(os.pathsep) + [ pythonpath = os.environ.get('PYTHONPATH', '').split(os.pathsep) + [
toxinidir, toxinidir,
] ]

View File

@ -34,7 +34,6 @@ from helpers.messagemock import message_mock
from helpers.fixtures import * # pylint: disable=wildcard-import from helpers.fixtures import * # pylint: disable=wildcard-import
from PyQt5.QtCore import PYQT_VERSION from PyQt5.QtCore import PYQT_VERSION
import xvfbwrapper
# Set hypothesis settings # Set hypothesis settings
@ -55,11 +54,10 @@ def _apply_platform_markers(item):
"Can't be run when frozen"), "Can't be run when frozen"),
('frozen', not getattr(sys, 'frozen', False), ('frozen', not getattr(sys, 'frozen', False),
"Can only run when frozen"), "Can only run when frozen"),
('not_xvfb', item.config.xvfb_display is not None,
"Can't be run with Xvfb."),
('skip', True, "Always skipped."), ('skip', True, "Always skipped."),
('pyqt531_or_newer', PYQT_VERSION < 0x050301, ('pyqt531_or_newer', PYQT_VERSION < 0x050301,
"Needs PyQt 5.3.1 or newer"), "Needs PyQt 5.3.1 or newer"),
('ci', 'CI' not in os.environ, "Only runs on CI."),
] ]
for searched_marker, condition, default_reason in markers: for searched_marker, condition, default_reason in markers:
@ -147,41 +145,18 @@ def fail_tests_on_warnings():
def pytest_addoption(parser): def pytest_addoption(parser):
parser.addoption('--no-xvfb', action='store_true', default=False,
help='Disable xvfb in tests.')
parser.addoption('--qute-delay', action='store', default=0, type=int, parser.addoption('--qute-delay', action='store', default=0, type=int,
help="Delay between qutebrowser commands.") help="Delay between qutebrowser commands.")
parser.addoption('--qute-profile-subprocs', action='store_true', parser.addoption('--qute-profile-subprocs', action='store_true',
default=False, help="Run cProfile for subprocesses.") default=False, help="Run cProfile for subprocesses.")
def pytest_configure(config): @pytest.fixture(scope='session', autouse=True)
"""Start Xvfb if we're on Linux, not on a CI and Xvfb is available. def prevent_xvfb_on_buildbot(request):
if (not request.config.getoption('--no-xvfb') and
This is a lot nicer than having windows popping up. 'QUTE_BUILDBOT' in os.environ and
""" request.config.xvfb is not None):
config.xvfb_display = None raise Exception("Xvfb is running on buildbot!")
if os.environ.get('DISPLAY', None) == '':
# xvfbwrapper doesn't handle DISPLAY="" correctly
del os.environ['DISPLAY']
if (sys.platform.startswith('linux') and
not config.getoption('--no-xvfb') and
'QUTE_NO_DISPLAY' not in os.environ):
assert 'QUTE_BUILDBOT' not in os.environ
try:
disp = xvfbwrapper.Xvfb(width=800, height=600, colordepth=16)
disp.start()
except FileNotFoundError:
# We run without Xvfb if it's unavailable.
pass
else:
config.xvfb_display = disp
def pytest_unconfigure(config):
if config.xvfb_display is not None:
config.xvfb_display.stop()
@pytest.hookimpl(tryfirst=True, hookwrapper=True) @pytest.hookimpl(tryfirst=True, hookwrapper=True)

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<!-- target: hello.txt -->
<html>
<head>
<meta charset="utf-8">
<title>Simple link</title>
</head>
<body>
<a href="/data/hello.txt">Follow me!</a>
</body>
</html>

View File

@ -212,12 +212,7 @@ def path_should_be_loaded(quteproc, path):
This is usally the better check compared to "should be requested" as the This is usally the better check compared to "should be requested" as the
page could be loaded from local cache. page could be loaded from local cache.
""" """
url = quteproc.path_to_url(path) quteproc.wait_for_load_finished(path)
pattern = re.compile(
r"load status for <qutebrowser\.browser\.webview\.WebView "
r"tab_id=\d+ url='{url}/?'>: LoadStatus\.success".format(
url=re.escape(url)))
quteproc.wait_for(message=pattern)
@bdd.then(bdd.parsers.parse("{path} should be requested")) @bdd.then(bdd.parsers.parse("{path} should be requested"))

View File

@ -113,7 +113,7 @@ Feature: Keyboard input
Then the javascript message "key press: 88" should be logged Then the javascript message "key press: 88" should be logged
And the javascript message "key release: 88" should be logged And the javascript message "key release: 88" should be logged
@not_xvfb @posix @no_xvfb @posix
Scenario: :fake-key sending key to the website with other window focused Scenario: :fake-key sending key to the website with other window focused
When I open data/keyinput/log.html When I open data/keyinput/log.html
And I set general -> developer-extras to true And I set general -> developer-extras to true

View File

@ -108,7 +108,7 @@ Feature: Various utility commands.
And I run :inspector And I run :inspector
Then the error "Please enable developer-extras before using the webinspector!" should be shown Then the error "Please enable developer-extras before using the webinspector!" should be shown
@not_xvfb @posix @no_xvfb @posix
Scenario: Inspector smoke test Scenario: Inspector smoke test
When I set general -> developer-extras to true When I set general -> developer-extras to true
And I run :inspector And I run :inspector
@ -124,7 +124,7 @@ Feature: Various utility commands.
Then the error "Please enable developer-extras before using the webinspector!" should be shown Then the error "Please enable developer-extras before using the webinspector!" should be shown
# Different code path as an inspector got created now # Different code path as an inspector got created now
@not_xvfb @posix @no_xvfb @posix
Scenario: Inspector smoke test 2 Scenario: Inspector smoke test 2
When I set general -> developer-extras to true When I set general -> developer-extras to true
And I run :inspector And I run :inspector
@ -202,7 +202,7 @@ Feature: Various utility commands.
# :debug-console # :debug-console
@not_xvfb @no_xvfb
Scenario: :debug-console smoke test Scenario: :debug-console smoke test
When I run :debug-console When I run :debug-console
And I wait for "Focus object changed: <qutebrowser.misc.consolewidget.ConsoleLineEdit *>" in the log And I wait for "Focus object changed: <qutebrowser.misc.consolewidget.ConsoleLineEdit *>" in the log

View File

@ -122,12 +122,14 @@ Feature: Prompts
And I click the button And I click the button
Then the javascript message "geolocation permission denied" should be logged Then the javascript message "geolocation permission denied" should be logged
@ci
Scenario: Always accepting geolocation Scenario: Always accepting geolocation
When I set content -> geolocation to true When I set content -> geolocation to true
And I open data/prompt/geolocation.html in a new tab And I open data/prompt/geolocation.html in a new tab
And I click the button And I click the button
Then the javascript message "geolocation permission denied" should not be logged Then the javascript message "geolocation permission denied" should not be logged
@ci
Scenario: geolocation with ask -> true Scenario: geolocation with ask -> true
When I set content -> geolocation to ask When I set content -> geolocation to ask
And I open data/prompt/geolocation.html in a new tab And I open data/prompt/geolocation.html in a new tab

View File

@ -380,7 +380,7 @@ class QuteProc(testprocess.Process):
url = utils.elide(QUrl(url).toDisplayString(QUrl.EncodeUnicode), 100) url = utils.elide(QUrl(url).toDisplayString(QUrl.EncodeUnicode), 100)
pattern = re.compile( pattern = re.compile(
r"(load status for <qutebrowser\.browser\.webview\.WebView " r"(load status for <qutebrowser\.browser\.webview\.WebView "
r"tab_id=\d+ url='{url}'>: LoadStatus\.{load_status}|fetch: " r"tab_id=\d+ url='{url}/?'>: LoadStatus\.{load_status}|fetch: "
r"PyQt5\.QtCore\.QUrl\('{url}'\) -> .*)".format( r"PyQt5\.QtCore\.QUrl\('{url}'\) -> .*)".format(
load_status=re.escape(load_status), url=re.escape(url))) load_status=re.escape(load_status), url=re.escape(url)))
self.wait_for(message=pattern, timeout=timeout) self.wait_for(message=pattern, timeout=timeout)

View File

@ -0,0 +1,56 @@
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
#
# This file is part of qutebrowser.
#
# qutebrowser is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# qutebrowser is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
"""Test hints based on html files with special comments."""
import os
import os.path
import yaml
import pytest
import bs4
def collect_tests():
basedir = os.path.dirname(__file__)
datadir = os.path.join(basedir, 'data', 'hints', 'html')
files = os.listdir(datadir)
return files
@pytest.mark.parametrize('test_name', collect_tests())
def test_hints(test_name, quteproc):
file_path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'data', 'hints', 'html', test_name)
url_path = 'data/hints/html/{}'.format(test_name)
quteproc.open_path(url_path)
quteproc.wait_for_load_finished(url_path)
with open(file_path, 'r', encoding='utf-8') as html:
soup = bs4.BeautifulSoup(html, 'html.parser')
comment = soup.find(text=lambda text: isinstance(text, bs4.Comment))
parsed = yaml.load(comment)
assert set(parsed.keys()) == {'target'}
quteproc.send_cmd(':hint links normal')
quteproc.wait_for(message='hints: a', category='hints')
quteproc.send_cmd(':follow-hint a')
quteproc.wait_for_load_finished('data/' + parsed['target'])

View File

@ -46,7 +46,7 @@ def test_elided_text(qtbot, elidemode, check):
""" """
label = TextBase(elidemode=elidemode) label = TextBase(elidemode=elidemode)
qtbot.add_widget(label) qtbot.add_widget(label)
long_string = 'Hello world! ' * 20 long_string = 'Hello world! ' * 100
label.setText(long_string) label.setText(long_string)
label.resize(100, 50) label.resize(100, 50)
label.show() label.show()

24
tox.ini
View File

@ -4,7 +4,7 @@
# and then run "tox" from this directory. # and then run "tox" from this directory.
[tox] [tox]
envlist = py34,py35-cov,misc,vulture,pydocstyle,flake8,pylint,pyroma,check-manifest envlist = py34,py35-cov,misc,vulture,flake8,pylint,pyroma,check-manifest
[testenv] [testenv]
# https://bitbucket.org/hpk42/tox/issue/246/ - only needed for Windows though # https://bitbucket.org/hpk42/tox/issue/246/ - only needed for Windows though
@ -20,7 +20,7 @@ deps =
Flask==0.10.1 Flask==0.10.1
glob2==0.4.1 glob2==0.4.1
httpbin==0.4.1 httpbin==0.4.1
hypothesis==2.0.0 hypothesis==3.0.2
itsdangerous==0.24 itsdangerous==0.24
Mako==1.0.3 Mako==1.0.3
parse==1.6.6 parse==1.6.6
@ -38,12 +38,12 @@ deps =
pytest-travis-fold==1.2.0 pytest-travis-fold==1.2.0
pytest-repeat==0.2 pytest-repeat==0.2
pytest-rerunfailures==1.0.1 pytest-rerunfailures==1.0.1
pytest-xvfb==0.1.0
six==1.10.0 six==1.10.0
termcolor==1.1.0 termcolor==1.1.0
vulture==0.8.1 vulture==0.8.1
Werkzeug==0.11.4 Werkzeug==0.11.4
wheel==0.29.0 wheel==0.29.0
xvfbwrapper==0.2.8
cherrypy==5.0.1 cherrypy==5.0.1
commands = commands =
{envpython} scripts/link_pyqt.py --tox {envdir} {envpython} scripts/link_pyqt.py --tox {envdir}
@ -122,8 +122,6 @@ commands =
[testenv:pylint] [testenv:pylint]
basepython = python3 basepython = python3
ignore_errors = true ignore_errors = true
skip_install = true
setenv = PYTHONPATH={toxinidir}/scripts/dev
passenv = passenv =
deps = deps =
{[testenv]deps} {[testenv]deps}
@ -131,6 +129,7 @@ deps =
astroid==1.4.4 astroid==1.4.4
pylint==1.5.4 pylint==1.5.4
requests==2.9.1 requests==2.9.1
./scripts/dev/pylint_checkers
commands = commands =
{envpython} scripts/link_pyqt.py --tox {envdir} {envpython} scripts/link_pyqt.py --tox {envdir}
{envpython} -m pylint scripts qutebrowser --output-format=colorized --reports=no {envpython} -m pylint scripts qutebrowser --output-format=colorized --reports=no
@ -138,26 +137,18 @@ commands =
[testenv:pylint-tip] [testenv:pylint-tip]
basepython = python3 basepython = python3
skip_install = true
setenv = {[testenv:pylint]setenv}
passenv = {[testenv:pylint]passenv} passenv = {[testenv:pylint]passenv}
deps = deps =
{[testenv]deps} {[testenv]deps}
{[testenv:misc]deps} {[testenv:misc]deps}
hg+https://bitbucket.org/logilab/astroid hg+https://bitbucket.org/logilab/astroid
hg+https://bitbucket.org/logilab/pylint hg+https://bitbucket.org/logilab/pylint
./scripts/dev/pylint_checkers
commands = commands =
{envpython} scripts/link_pyqt.py --tox {envdir} {envpython} scripts/link_pyqt.py --tox {envdir}
{envpython} -m pylint scripts qutebrowser --output-format=colorized --reports=no {envpython} -m pylint scripts qutebrowser --output-format=colorized --reports=no
{envpython} scripts/dev/run_pylint_on_tests.py --output-format=colorized --reports=no {envpython} scripts/dev/run_pylint_on_tests.py --output-format=colorized --reports=no
[testenv:pydocstyle]
basepython = python3
skip_install = true
passenv = PYTHON LANG
deps = pydocstyle==1.0.0
commands = {envpython} -m pydocstyle scripts tests qutebrowser
[testenv:flake8] [testenv:flake8]
basepython = python3 basepython = python3
passenv = passenv =
@ -176,8 +167,9 @@ deps =
flake8-deprecated==0.2 flake8-deprecated==0.2
flake8-mock==0.2 flake8-mock==0.2
flake8-pep3101==0.2 flake8-pep3101==0.2
flake8-pep257==1.0.5 flake8-docstrings==0.2.5
pep257==0.7.0 pep257==0.7.0 # still needed by flake8-docstrings but ignored
pydocstyle==1.0.0
commands = commands =
{envpython} -m flake8 {envpython} -m flake8