Compare commits

...

70 Commits

Author SHA1 Message Date
Florian Bruhin
e9e411311a Remove unused import 2017-10-09 10:08:45 +02:00
Florian Bruhin
33b71ee937 Use develop branch of PyInstaller
https://github.com/pyinstaller/pyinstaller/pull/2519 was merged.
Fixes #2880

(cherry picked from commit ba04822388)
2017-10-09 08:46:31 +02:00
Florian Bruhin
d166587f3d Release v0.11.1 2017-10-09 08:30:18 +02:00
Florian Bruhin
dd663df35f Update changelog from master 2017-10-09 08:30:03 +02:00
Florian Bruhin
9d292128d2 Remove test_upgrade_version
This is the last v0.11.x release
2017-10-09 08:24:56 +02:00
Florian Bruhin
f3eb5dbb66 Revert "Only emit perc_changed signal when the percentage actually changed"
This reverts commit 3eaad092b8.
This breaks various end2end test relying on getting log messages for scrolling.
2017-10-06 10:17:13 +02:00
Florian Bruhin
3eaad092b8 Only emit perc_changed signal when the percentage actually changed
QtWebEngine emits scrollPositionChanged a lot during smooth scrolling, and
there's no reason we need to update percentages when they didn't *actually*
change.

This reduces the updates with a single spacebar press from 6-7 to 2-3 on my
machine, which might not be enough though.

See #2233

(cherry picked from commit 1d50c2c39a)
2017-10-06 08:54:52 +02:00
Florian Bruhin
38bccd4fdd Remove unused import
(cherry picked from commit 629f6a6876)
2017-10-04 11:16:18 +02:00
Florian Bruhin
9a5668f7a0 Fix test_version after OpenGL removal 2017-10-04 09:32:33 +02:00
Florian Bruhin
48023e7b1d Use ctypes instead of PyOpenGL for QtWebEngine Nvidia workaround
Normally a dependency change like this wouldn't appear on a stable branch, but
it looks like multiple people have issues with importing PyOpenGL:

Traceback (most recent call last):
  ...
  File "/usr/lib/python3/dist-packages/qutebrowser/browser/webengine/webenginesettings.py", line 208, in init
    from OpenGL import GL  # pylint: disable=unused-variable
  File "/usr/lib/python3/dist-packages/OpenGL/GL/__init__.py", line 3, in <module>
    from OpenGL.GL.VERSION.GL_1_1 import *
  File "/usr/lib/python3/dist-packages/OpenGL/GL/VERSION/GL_1_1.py", line 10, in <module>
    from OpenGL import platform, constants, constant, arrays
  File "/usr/lib/python3/dist-packages/OpenGL/arrays/__init__.py", line 22, in <module>
    formathandler.FormatHandler.loadAll()
  File "/usr/lib/python3/dist-packages/OpenGL/arrays/formathandler.py", line 28, in loadAll
    cls.loadPlugin( entrypoint )
  File "/usr/lib/python3/dist-packages/OpenGL/arrays/formathandler.py", line 35, in loadPlugin
    plugin_class = entrypoint.load()
  File "/usr/lib/python3/dist-packages/OpenGL/plugins.py", line 14, in load
    return importByName( self.import_path )
  File "/usr/lib/python3/dist-packages/OpenGL/plugins.py", line 28, in importByName
    module = __import__( ".".join(moduleName), {}, {}, moduleName)
  File "/usr/lib/python3/dist-packages/OpenGL/arrays/vbo.py", line 430, in <module>
    def mapVBO( vbo, access=GL.GL_READ_WRITE ):
AttributeError: module 'OpenGL.GL' has no attribute 'GL_READ_WRITE'

Fixes #2821

(cherry picked from commit a942613d7f)
2017-10-04 06:54:08 +02:00
Florian Bruhin
74e1b1ec26 Make userscripts work on both Python 2 and 3
(cherry picked from commit dca962ca03)
2017-09-29 13:39:09 +02:00
Florian Bruhin
cfe7386f20 eslint: Turn off function-paren-newline 2017-09-10 12:50:25 +02:00
Jay Kamat
12b00dad44 Enforce a minimum size for non-pinned tabs
Closes #2826
2017-09-10 01:52:55 +02:00
Jay Kamat
ccf3cb6d7c Restructure minimum tab size behavior 2017-09-10 01:52:55 +02:00
Jay Kamat
fcd8be5b68 Test for saving a session with --only-active-window 2017-08-28 07:58:32 +02:00
cryzed
259d08ba29 :save-session --only-active-window implies --with-private for private windows 2017-08-28 07:58:32 +02:00
Florian Bruhin
9d65039b35 Ignore a new Geoclue error during tests 2017-08-08 22:01:36 +02:00
Florian Bruhin
e50b7b65a4 version.distribution(): Handle Funtoo 2017-08-08 21:29:07 +02:00
Florian Bruhin
1aefaaf7c7 Fix tests for QProcess changes 2017-07-23 22:11:01 +02:00
Florian Bruhin
4da89139d1 Disallow :spawn -u -d
(cherry picked from commit efe6719f4f354348e7db6f77dc22c319850de5d4)
2017-07-23 21:34:56 +02:00
Florian Bruhin
3f04c94047 Fix error message with :spawn -d
(cherry picked from commit c951b71307e666cb6a02c1c0e9f54131ac61266a)
2017-07-23 21:34:50 +02:00
Florian Bruhin
00f456fd7f Fix the "try again" button on error pages
Fixes #2810

(cherry picked from commit 5c367e7ab2)
2017-07-13 17:28:06 +02:00
Jay Kamat
00d5aa6b22 Refactor tab_close_prompt_if_pinned
Now it lives in tabbedbrowser.py as method instead of a static function

(cherry picked from commit 7dfca60893)
2017-07-13 11:03:28 +02:00
Jay Kamat
91c5eff2c9 Prompt when closing a pinned tab via the mouse
Closes #2761

(cherry picked from commit 4d1dbe11e8)
2017-07-13 11:03:22 +02:00
Florian Bruhin
0d704043ec Fix printing on macOS
Fixes #2798

(cherry picked from commit 53620ecce4)
2017-07-12 07:43:18 +02:00
Florian Bruhin
b11abb028b Remove unused import
(cherry picked from commit cfb169b5f0)
2017-07-09 12:40:30 +02:00
Florian Bruhin
474e904409 Move OpenGL workaround import
OpenGL.GL gets imported in earlyinit already anyways, so we can move everything
there.

(cherry picked from commit 9e7f2e470f)
2017-07-09 11:57:48 +02:00
Florian Bruhin
cc05cb1c67 Recommend QT_XCB_FORCE_SOFTWARE_OPENGL
This won't disable OpenGL for stuff started from qutebrowser.

See #2368.

(cherry picked from commit fcf5158258)
2017-07-08 17:37:44 +02:00
Florian Bruhin
e10ce420ab Improve earlyinit check for PyOpenGL
Importing OpenGL alone doesn't actually load libgl, it only checks that the
package is here. If libgl is missing, we'd later get an exception.

(cherry picked from commit b81474d2fd)
2017-07-08 17:34:41 +02:00
Florian Bruhin
5b5adc1a00 Fix :restart with private browsing mode
(cherry picked from commit 0de0bbfa71)
2017-07-08 10:46:57 +02:00
Florian Bruhin
63fa412882 Fix build_release.py 2017-07-07 15:18:14 +02:00
Florian Bruhin
47ad8f212e build_release: Fail GitHub uploads early 2017-07-07 14:28:44 +02:00
Florian Bruhin
7ac27fdd85 Add Gentoo instructions to backend warning 2017-07-06 00:40:58 +02:00
Florian Bruhin
d4baeb2ada Merge branch 'pr/2747' into v0.11.x 2017-07-05 22:15:23 +02:00
Florian Bruhin
eaecfe5882 build_release: Adjust Windows installer names 2017-07-04 22:27:17 +02:00
Florian Bruhin
725d4a44f0 build_release: Don't fail if hdiutil detach fails 2017-07-04 22:16:21 +02:00
Florian Bruhin
c424a745d8 build_release: Add comment about missing 3rdparty upgrade 2017-07-04 21:36:20 +02:00
Florian Bruhin
3cbe419cee Update Python version for Windows in release checklist 2017-07-04 21:36:20 +02:00
Florian Bruhin
8f03a36862 build_release: Use correct path when copying dirs 2017-07-04 21:31:53 +02:00
Florian Bruhin
7ecdd6c1c5 build_release: Print some more information about copied files 2017-07-04 21:04:08 +02:00
Florian Bruhin
d96403fe93 build_release: Clean up before doing stuff
So we can inspect the results later.
2017-07-04 21:03:55 +02:00
Florian Bruhin
2df9508e44 Add PyQt5 OpenGL module to PyInstaller hiddenimports 2017-07-04 21:03:34 +02:00
Florian Bruhin
defe140d98 build_release: Run tox with -vv 2017-07-04 19:56:54 +02:00
Florian Bruhin
28410b8533 Release v0.11.0 2017-07-04 18:02:34 +02:00
Florian Bruhin
378914b327 Ignore another new geoclue error during tests 2017-07-04 18:01:24 +02:00
Florian Bruhin
023bf82638 Update for PyQt 5.9.1 2017-07-04 17:31:09 +02:00
Florian Bruhin
45b1285402 Merge pull request #2765 from jgkamat/jay/tab-crashes
Refactor set_tab_pinned to take a tab widget.
2017-07-04 17:24:10 +02:00
Florian Bruhin
629038632c Add proxy support for QtWebEngine and Qt 5.7.1
This used to give us crashes in libproxy:
https://github.com/libproxy/libproxy/issues/45
https://bugreports.qt.io/browse/QTBUG-56852

However, trying again with Qt 5.7.1 on Debian and from PyPI, this doesn't happen
anymore, so it was probably something with how Archlinux handled things.

See #2082, #2775.
Reverts fd29528e4f
2017-07-03 10:29:28 +02:00
Florian Bruhin
3b53ec1cb6 Skip tests with permission changes if they didn't work
This e.g. wouldn't work inside of a Docker container otherwise.
2017-07-03 10:07:40 +02:00
Florian Bruhin
2f26490536 Remove FIXME 2017-07-02 14:03:38 +02:00
Florian Bruhin
69337ed264 Update tox default envlist 2017-07-02 13:07:13 +02:00
Jay Kamat
2fbadc46d2 Remove error when count is invalid to :tab-pin 2017-06-30 09:57:39 -07:00
Florian Bruhin
9cedaa60bc Check for PyQt5.QtQml in earlyinit 2017-06-30 14:56:02 +02:00
Florian Bruhin
e4a054d34e Stop marking QtWebEngine as experimental 2017-06-30 10:42:33 +02:00
Jay Kamat
596dee69d6 Clean up pin_tab
Also add a test case for :pin-tab with an invalid count
2017-06-29 20:04:02 -07:00
Florian Bruhin
0d5a33ef2a Update changelog 2017-06-29 23:21:10 +02:00
Florian Bruhin
d132b6ed71 Fix :scroll-page with --bottom-navigate on QtWebEngine
There were two issues here:

- The comparison was backwards, causing scroller.at_bottom() to always return
  true.
- When zoomed in, jsret['px']['y'] can be a float, which means we can be
  slightly off when checking the difference - math.ceil() fixes that.
2017-06-29 22:39:48 +02:00
Jay Kamat
302961a86a Refactor set_tab_pinned to take a tab widget.
See #2759
2017-06-28 22:22:33 -07:00
Florian Bruhin
f136f78802 Fix :undo documentation
See #2759
2017-06-28 22:41:08 +02:00
Florian Bruhin
a98a6ac0c8 travis: Write a sane sources.list
Also updates nodejs
2017-06-28 21:42:50 +02:00
Florian Bruhin
5ec94f96fd Allow a trailing % for :zoom 2017-06-26 21:51:35 +02:00
Florian Bruhin
92d5f6c41d Ignore _remove_tab for crashed deleted tabs 2017-06-26 20:50:17 +02:00
Florian Bruhin
24caaea54d Handle OSError in SessionManager.delete 2017-06-26 19:52:07 +02:00
Florian Bruhin
130be2aedc Handle OSError when trying to delete autosave session 2017-06-26 19:47:54 +02:00
Florian Bruhin
736dd77a6e Regenerate authors 2017-06-26 18:05:25 +02:00
Florian Bruhin
8a7610206e Merge branch 'master' of https://github.com/jupart/qutebrowser 2017-06-26 18:04:57 +02:00
pyup-bot
78c93e1225 Update pytest-rerunfailures from 2.1.0 to 2.2 2017-06-26 15:47:14 +02:00
pyup-bot
e8dac08a35 Update cheroot from 5.5.2 to 5.7.0 2017-06-26 15:47:13 +02:00
pyup-bot
6d1775fcd6 Update pylint from 1.7.1 to 1.7.2 2017-06-26 15:47:11 +02:00
Justin Partain
cb67a911fa Remove recommendation to use '-c' command line argument, which doesn't exist 2017-06-21 10:56:25 -04:00
51 changed files with 626 additions and 235 deletions

View File

@@ -23,14 +23,18 @@ matrix:
language: python
python: 3.6
env: TESTENV=py36-pyqt571
- os: linux
language: python
python: 3.6
env: TESTENV=py36-pyqt58
- os: linux
language: python
python: 3.5
env: TESTENV=py35-pyqt58
env: TESTENV=py35-pyqt59
- os: linux
language: python
python: 3.6
env: TESTENV=py36-pyqt58
env: TESTENV=py36-pyqt59
- os: osx
env: TESTENV=py36 OSX=elcapitan
osx_image: xcode7.3

View File

@@ -14,8 +14,22 @@ This project adheres to http://semver.org/[Semantic Versioning].
// `Fixed` for any bug fixes.
// `Security` to invite users to upgrade in case of vulnerabilities.
v0.11.0 (unreleased)
--------------------
v0.11.1
-------
Fixes
~~~~~
- Fixed empty space being shown after tabs in the tabbar in some cases.
- Fixed `:restart` in private browsing mode.
- Fixed printing on macOS.
- Closing a pinned tab via mouse now also prompts for confirmation.
- The "try again" button on error pages works correctly again.
- :spawn -u -d is now disallowed.
- :spawn -d shows error messages correctly now.
v0.11.0
-------
New dependencies
~~~~~~~~~~~~~~~~
@@ -28,7 +42,10 @@ New dependencies
Added
~~~~~
- New `-p` flag for `:open` to open a private window.
- Private browsing is now implemented for QtWebEngine, *and changed its
behavior*: The `general -> private-browsing` setting now only applies to newly
opened windows, and you can use the `-p` flag to `:open` to open a private
window.
- New "pinned tabs" feature, with a new `:tab-pin` command (bound
to `<Ctrl-p>` by default).
- (QtWebEngine) Implemented `:follow-selected`.
@@ -45,6 +62,8 @@ Added
customize statusbar colors for private windows.
- New `{private}` field displaying `[Private Mode]` for
`ui -> window-title-format` and `tabs -> title-format`.
- (QtWebEngine) Proxy support with Qt 5.7.1 (already was supported for 5.8 and
newer)
Changed
~~~~~~~
@@ -52,62 +71,51 @@ Changed
- To prevent elaborate phishing attacks, the Punycode version (`xn--*`) is now
shown in addition to the decoded version for international domain names
(IDN).
- Private browsing is now implemented for QtWebEngine, and changed it's
behavior: The `general -> private-browsing` setting now only applies to newly
opened windows, and you can use the `-p` flag to `:open` to open a private
window.
- Improved `qute://history` page (with lazy loading)
- Starting with legacy QtWebKit now shows a warning message once.
- Crash reports are not public anymore.
- Paths like `C:` are now treated as absolute paths on Windows for downloads,
and invalid paths are handled properly.
- PAC on QtWebKit now supports SOCKS5 as type.
- Comments in the config file are now before the individual options instead of
being before sections.
- Messages are now hidden when clicked.
- stdin is now closed immediately for processes spawned from qutebrowser.
- When `ui -> message-timeout` is set to 0, messages are now never cleared.
- Middle/right-clicking the blank parts of the tab bar (when vertical) now
closes the current tab.
- (QtWebEngine) With Qt 5.9, `content -> cookies-store` can now be set without
a restart.
- (QtWebEngine) With Qt 5.9, better error messages are now shown for failed
downloads.
- The adblocker now also blocks non-GET requests (e.g. POST).
- `javascript:` links can now be hinted.
- `:view-source`, `:tab-clone` and `:navigate --tab` now don't open the tab as
"explicit" anymore, i.e. (with the default settings) open it next to the
active tab.
- (QtWebEngine) The underlying Chromium version is now shown in the version
info.
- `qute:*` pages now use `qute://*` instead (e.g. `qute://version` instead of
`qute:version`), but the old versions are automatically redirected.
- Starting with legacy QtWebKit now shows a warning message.
*With the next release, support for it will be removed.*
- The Windows releases are redone from scratch, which means:
- They now use the new QtWebEngine backend
- The bundled Qt is updated from 5.5 to 5.9
- The bundled Python is updated from 3.4 to 3.6
- They are now generated with PyInstaller instead of cx_Freeze
- The installer is now generated using NSIS instead of being a MSI
- Improved `qute://history` page (with lazy loading)
- Crash reports are not public anymore.
- Paths like `C:` are now treated as absolute paths on Windows for downloads,
and invalid paths are handled properly.
- Comments in the config file are now placed before the individual options
instead of being before sections.
- Messages are now hidden when clicked.
- stdin is now closed immediately for processes spawned from qutebrowser.
- When `ui -> message-timeout` is set to 0, messages are now never cleared.
- Middle/right-clicking the blank parts of the tab bar (when vertical) now
closes the current tab.
- The adblocker now also blocks non-GET requests (e.g. POST).
- `javascript:` links can now be hinted.
- `:view-source`, `:tab-clone` and `:navigate --tab` now don't open the tab as
"explicit" anymore, i.e. (with the default settings) open it next to the
active tab.
- `qute:*` pages now use `qute://*` instead (e.g. `qute://version` instead of
`qute:version`), but the old versions are automatically redirected.
- Texts in prompts are now selectable.
- Renderer process crashes now show an error page.
- (QtWebKit) storage -> offline-web-application-storage` got renamed to `...-cache`
- The default level for `:messages` is now `info`, not `error`
- Trying to focus the currently focused tab with `:tab-focus` now focuses the
last viewed tab.
- (QtWebEngine) With Qt 5.9, `content -> cookies-store` can now be set without
a restart.
- (QtWebEngine) With Qt 5.9, better error messages are now shown for failed
downloads.
- (QtWebEngine) The underlying Chromium version is now shown in the version
info.
- (QtWebKit) Renderer process crashes now show an error page on Qt 5.9 or newer.
- (QtWebKit) storage -> offline-web-application-storage` got renamed to `...-cache`
- (QtWebKit) PAC now supports SOCKS5 as type.
Fixed
~~~~~
- The macOS .dmg is now built against Qt 5.9 which fixes various
important issues (such as not being able to type dead keys).
- (QtWebEngine) Added a workaround for a black screen with some setups
(the workaround requires PyOpenGL to be installed, but it's optional)
- (QtWebEngine) Starting with Nouveau graphics now shows an error message
instead of crashing in Qt. This adds a new dependency on `PyQt5.QtOpenGL`.
- (QtWebEngine) Retrying downloads now shows an error instead of crashing.
- (QtWebEngine) Cloning a view-source tab now doesn't crash anymore.
- (QtWebKit) The HTTP cache is disabled on Qt 5.7.1 and 5.8 now as it leads to
frequent crashes due to a Qt bug.
- Fixed crash with `:download` on PyQt 5.9.
- Cloning a page without history doesn't crash anymore.
- When a download results in a HTTP error, it now shows the error correctly
@@ -117,7 +125,6 @@ Fixed
- Fixed crash when unbinding an unbound key in the key config.
- Fixed crash when using `:debug-log-filter` when `--filter` wasn't given on startup.
- Fixed crash with some invalid setting values.
- (QtWebKit) Fixed Crash when a PAC file returns an invalid value.
- Continuing a search after clearing it now works correctly.
- The tabbar and completion should now be more consistently and correctly
styled with various system styles.
@@ -125,18 +132,27 @@ Fixed
- The validation for colors in stylesheets is now less strict,
allowing for all valid Qt values.
- `data:` URLs now aren't added to the history anymore.
- (QtWebEngine) `window.navigator.userAgent` is now set correctly when
customizing the user agent.
- Accidentally starting with Python 2 now shows a proper error message again.
- (QtWebEngine) HTML fullscreen is now tracked for each tab separately, which
means it's not possible anymore to accidentally get stuck in fullscreen state
by closing a tab with a fullscreen video.
- For some people, running some userscripts crashed - this should now be fixed.
- Various other rare crashes should now be fixed.
- The settings documentation was truncated with v0.10.1 which should now be
fixed.
- Scrolling to an anchor in a background tab now works correctly, and javascript
gets the correct window size for background tabs.
- (QtWebEngine) Added a workaround for a black screen with some setups
- (QtWebEngine) Starting with Nouveau graphics now shows an error message
instead of crashing in Qt.
- (QtWebEngine) Retrying downloads now shows an error instead of crashing.
- (QtWebEngine) Cloning a view-source tab now doesn't crash anymore.
- (QtWebEngine) `window.navigator.userAgent` is now set correctly when
customizing the user agent.
- (QtWebEngine) HTML fullscreen is now tracked for each tab separately, which
means it's not possible anymore to accidentally get stuck in fullscreen state
by closing a tab with a fullscreen video.
- (QtWebEngine) `:scroll-page` with `--bottom-navigate` now works correctly.
- (QtWebKit) The HTTP cache is disabled on Qt 5.7.1 and 5.8 now as it leads to
frequent crashes due to a Qt bug.
- (QtWebKit) Fixed Crash when a PAC file returns an invalid value.
v0.10.1
-------
@@ -181,7 +197,7 @@ Added
- Open tabs are now auto-saved on each successful load and restored in case of a crash
- `:jseval` now has a `--file` flag so you can pass a javascript file
- `:session-save` now has a `--only-active-window` flag to only save the active window
- OS X builds are back, and built with QtWebEngine
- macOS builds are back, and built with QtWebEngine
Changed
~~~~~~~
@@ -483,7 +499,7 @@ Fixed
- Fix crash when pressing enter without a command
- Adjust error message to point out QtWebEngine is unsupported with the OS
X .app currently.
- Hide Harfbuzz warning with the OS X .app
- Hide Harfbuzz warning with the macOS .app
v0.8.0
------
@@ -846,7 +862,7 @@ Fixed
- Fixed scrolling to the very left/right with `:scroll-perc`.
- Using an external editor should now work correctly with some funny chars
(U+2028/U+2029/BOM).
- Movements in caret mode now should work correctly on OS X and Windows.
- Movements in caret mode now should work correctly on macOS and Windows.
- Fixed upgrade from earlier config versions.
- Fixed crash when killing a running userscript.
- Fixed characters being passed through when shifted with
@@ -921,7 +937,7 @@ Changed
- The completion widget doesn't show a border anymore.
- The tabbar doesn't display ugly arrows anymore if there isn't enough space
for all tabs.
- Some insignificant Qt warnings which were printed on OS X are now hidden.
- Some insignificant Qt warnings which were printed on macOS are now hidden.
- Better support for Qt 5.5 and Python 3.5.
Fixed
@@ -1032,7 +1048,7 @@ Fixed
- Fixed AssertionError when closing many windows quickly.
- Various fixes for deprecated key bindings and auto-migrations.
- Workaround for qutebrowser not starting when there are NUL-bytes in the history (because of a currently unknown bug).
- Fixed handling of keybindings containing Ctrl/Meta on OS X.
- Fixed handling of keybindings containing Ctrl/Meta on macOS.
- Fixed crash when downloading a URL without filename (e.g. magnet links) via "Save as...".
- Fixed exception when starting qutebrowser with `:set` as argument.
- Fixed horrible completion performance when the `shrink` option was set.
@@ -1130,7 +1146,7 @@ Changed
- Add a `:search` command in addition to `/foo` so it's more visible and can be used from scripts.
- Various improvements to documentation, logging, and the crash reporter.
- Expand `~` to the users home directory with `:run-userscript`.
- Improve the userscript runner on Linux/OS X by using `QSocketNotifier`.
- Improve the userscript runner on Linux/macOS by using `QSocketNotifier`.
- Add luakit-like `gt`/`gT` keybindings to cycle through tabs.
- Show default value for config values in the completion.
- Clone tab icon, tab text and zoom level when cloning tabs.
@@ -1150,7 +1166,7 @@ Changed
* `init_venv.py` and `run_checks.py` have been replaced by http://tox.readthedocs.org/[tox]. Install tox and run `tox -e mkvenv` instead.
* The tests now use http://pytest.org/[pytest]
* Many new tests added
* Mac Mini buildbot to run the tests on OS X.
* Mac Mini buildbot to run the tests on macOS.
* Coverage recording via http://nedbatchelder.com/code/coverage/[coverage.py].
* New `--pdb-postmortem argument` to drop into the pdb debugger on exceptions.
* Use https://github.com/ionelmc/python-hunter[hunter] for line tracing instead of a selfmade solution.
@@ -1286,7 +1302,7 @@ Fixed
* Fix rare exception when a key is pressed shortly after opening a window
* Fix exception with certain invalid URLs like `http:foo:0`
* Work around Qt bug which renders checkboxes on OS X unusable
* Work around Qt bug which renders checkboxes on macOS unusable
* Fix exception when a local files can't be read in `:adblock-update`
* Hide 2 more Qt warnings.
* Add `!important` to hint CSS so websites don't override the hint look
@@ -1322,7 +1338,7 @@ Changes
* Set zoom to default instead of 100% with `:zoom`/`=`.
* Adjust page zoom if default zoom changed.
* Force tabs to be focused on `:undo`.
* Replace manual installation instructions on OS X with homebrew/macports.
* Replace manual installation instructions on macOS with homebrew/macports.
* Allow min-/maximizing of print preview on Windows.
* Various documentation improvements.
* Various other small improvements and cleanups.

View File

@@ -682,8 +682,9 @@ qutebrowser release
* Add newest config to `tests/unit/config/old_configs` and update `test_upgrade_version`
- `python -m qutebrowser --basedir conf :quit`
- `sed '/^#/d' conf/config/qutebrowser.conf > tests/unit/config/old_configs/qutebrowser-v0.x.y.conf`
- `sed '/^#/d' conf/config/qutebrowser.conf > tests/unit/config/old_configs/qutebrowser-v0.$x.$y.conf`
- `rm -r conf`
- git add
- commit
* Adjust `__version_info__` in `qutebrowser/__init__.py`.
* Update changelog (remove *(unreleased)*)
@@ -698,7 +699,7 @@ qutebrowser release
as closed.
* Linux: Run `python3 scripts/dev/build_release.py --upload v0.$x.$y`
* Windows: Run `C:\Python34_x32\python scripts\dev\build_release.py --asciidoc C:\Python27\python C:\asciidoc-8.6.9\asciidoc.py --upload v0.X.Y` (replace X/Y by hand)
* Windows: Run `C:\Python36-32\python scripts\dev\build_release.py --asciidoc C:\Python27\python C:\asciidoc-8.6.9\asciidoc.py --upload v0.X.Y` (replace X/Y by hand)
* OS X: Run `python3 scripts/dev/build_release.py --upload v0.X.Y` (replace X/Y by hand)
* On server: Run `python3 scripts/dev/download_release.py v0.X.Y` (replace X/Y by hand)
* Update `qutebrowser-git` PKGBUILD if dependencies/install changed

View File

@@ -371,14 +371,6 @@ your `$PATH` (e.g. `/usr/local/bin/qutebrowser` or `~/bin/qutebrowser`):
~/path/to/qutebrowser/.venv/bin/python3 -m qutebrowser "$@"
----
If you are developing on qutebrowser, you may want to redirect it to a local
config:
----
#!/bin/bash
~/path/to/qutebrowser/.venv/bin/python3 -m qutebrowser -c .qutebrowser-local "$@"
----
Updating
~~~~~~~~

View File

@@ -99,16 +99,15 @@ Requirements
The following software and libraries are required to run qutebrowser:
* http://www.python.org/[Python] 3.4 or newer (3.5 recommended)
* http://qt.io/[Qt] 5.2.0 or newer (5.9.0 recommended)
* http://qt.io/[Qt] 5.2.0 or newer (5.9 recommended)
* QtWebKit (old or link:https://github.com/annulen/webkit/wiki[reloaded]/NG) or QtWebEngine
* http://www.riverbankcomputing.com/software/pyqt/intro[PyQt] 5.2.0 or newer
(5.8.1 recommended) for Python 3
(5.9 recommended) for Python 3
* https://pypi.python.org/pypi/setuptools/[pkg_resources/setuptools]
* http://fdik.org/pyPEG/[pyPEG2]
* http://jinja.pocoo.org/[jinja2]
* http://pygments.org/[pygments]
* http://pyyaml.org/wiki/PyYAML[PyYAML]
* http://pyopengl.sourceforge.net/[PyOpenGL] when using QtWebEngine
The following libraries are optional and provide a better user experience:
@@ -281,6 +280,7 @@ Contributors, sorted by the number of commits in descending order:
* Lazlow Carmichael
* Kevin Wang
* Ján Kobezda
* Justin Partain
* Johannes Martinsson
* Jean-Christophe Petkovich
* Helen Sherwood-Taylor

View File

@@ -85,7 +85,7 @@ It is possible to run or bind multiple commands by separating them with `;;`.
|<<tab-pin,tab-pin>>|Pin/Unpin the current/[count]th tab.
|<<tab-prev,tab-prev>>|Switch to the previous tab, or switch [count] tabs back.
|<<unbind,unbind>>|Unbind a keychain.
|<<undo,undo>>|Re-open a closed tab (optionally skipping [count] closed tabs).
|<<undo,undo>>|Re-open a closed tab.
|<<view-source,view-source>>|Show the source of the current page in a new tab.
|<<window-only,window-only>>|Close all windows except for the current one.
|<<wq,wq>>|Save open pages and quit.
@@ -936,7 +936,7 @@ Unbind a keychain.
[[undo]]
=== undo
Re-open a closed tab (optionally skipping [count] closed tabs).
Re-open a closed tab.
[[view-source]]
=== view-source

View File

@@ -789,8 +789,6 @@ The proxy to use.
In addition to the listed values, you can use a `socks://...` or `http://...` URL.
This setting only works with Qt 5.8 or newer when using the QtWebEngine backend.
Valid values:
* +system+: Use the system wide proxy.

View File

@@ -57,7 +57,7 @@ show it.
How URLs should be opened if there is already a qutebrowser instance running.
*--backend* '{webkit,webengine}'::
Which backend to use (webengine backend is EXPERIMENTAL!).
Which backend to use.
*--enable-webengine-inspector*::
Enable the web inspector for QtWebEngine. Note that this is a SECURITY RISK and you should not visit untrusted websites with the inspector turned on. See https://bugreports.qt.io/browse/QTBUG-50725 for more details.

View File

@@ -41,7 +41,7 @@ a = Analysis(['../qutebrowser/__main__.py'],
pathex=['misc'],
binaries=None,
datas=get_data_files(),
hiddenimports=['PyQt5.QtOpenGL'],
hiddenimports=['PyQt5.QtOpenGL', 'PyQt5._QOpenGLFunctions_2_0'],
hookspath=[],
runtime_hooks=[],
excludes=['tkinter'],

View File

@@ -1,3 +1,3 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
-e git+https://github.com/xoviat/pyinstaller.git@qtweb#egg=PyInstaller
-e git+https://github.com/pyinstaller/pyinstaller.git@develop#egg=PyInstaller

View File

@@ -1,4 +1,4 @@
-e git+https://github.com/xoviat/pyinstaller.git@qtweb#egg=PyInstaller
-e git+https://github.com/pyinstaller/pyinstaller.git@develop#egg=PyInstaller
# remove @commit-id for scm installs
#@ replace: @.*# @qtweb#
#@ replace: @.*# @develop#

View File

@@ -8,7 +8,7 @@ idna==2.5
isort==4.2.15
lazy-object-proxy==1.3.1
mccabe==0.6.1
pylint==1.7.1
pylint==1.7.2
./scripts/dev/pylint_checkers
requests==2.18.1
six==1.10.0

View File

@@ -1,4 +1,4 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
PyQt5==5.8.2
sip==4.19.2
PyQt5==5.9
sip==4.19.3

View File

@@ -1,7 +1,7 @@
# This file is automatically generated by scripts/dev/recompile_requirements.py
beautifulsoup4==4.6.0
cheroot==5.5.2
cheroot==5.7.0
click==6.7
# colorama==0.3.9
coverage==4.4.1
@@ -30,7 +30,7 @@ pytest-instafail==0.3.0
pytest-mock==1.6.0
pytest-qt==2.1.0
pytest-repeat==0.4.1
pytest-rerunfailures==2.1.0
pytest-rerunfailures==2.2
pytest-travis-fold==1.2.0
pytest-xvfb==1.0.0
PyVirtualDisplay==0.2.1

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python
#
# Executes python-readability on current page and opens the summary as new tab.
#

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python
#
# Adds DuckDuckGo bang as searchengine.
#
@@ -8,14 +8,21 @@
# Example:
# :spawn --userscript ripbang amazon maps
#
import os, re, requests, sys, urllib
from __future__ import print_function
import os, re, requests, sys
try:
from urllib.parse import unquote
except ImportError:
from urllib import unquote
for argument in sys.argv[1:]:
bang = '!' + argument
r = requests.get('https://duckduckgo.com/',
params={'q': bang + ' SEARCHTEXT'})
searchengine = urllib.unquote(re.search("url=[^']+", r.text).group(0))
searchengine = unquote(re.search("url=[^']+", r.text).group(0))
searchengine = searchengine.replace('url=', '')
searchengine = searchengine.replace('/l/?kh=-1&uddg=', '')
searchengine = searchengine.replace('SEARCHTEXT', '{}')
@@ -24,4 +31,4 @@ for argument in sys.argv[1:]:
with open(os.environ['QUTE_FIFO'], 'w') as fifo:
fifo.write('set searchengines %s %s' % (bang, searchengine))
else:
print '%s %s' % (bang, searchengine)
print('%s %s' % (bang, searchengine))

View File

@@ -45,6 +45,8 @@ qt_log_ignore =
^QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to .*
^QGeoclueMaster error creating GeoclueMasterClient\.
^Geoclue error: Process org\.freedesktop\.Geoclue\.Master exited with status 127
^QDBusConnection: name 'org.freedesktop.Geoclue.Master' had owner '' but we thought it was ':1.1'
^Failed to create Geoclue client interface. Geoclue error: org\.freedesktop\.DBus\.Error\.Disconnected
^QObject::connect: Cannot connect \(null\)::stateChanged\(QNetworkSession::State\) to QNetworkReplyHttpImpl::_q_networkSessionStateChanged\(QNetworkSession::State\)
^QXcbClipboard: Cannot transfer data, no data available
^load glyph failed

View File

@@ -26,7 +26,7 @@ __copyright__ = "Copyright 2014-2017 Florian Bruhin (The Compiler)"
__license__ = "GPL"
__maintainer__ = __author__
__email__ = "mail@qutebrowser.org"
__version_info__ = (0, 10, 1)
__version_info__ = (0, 11, 1)
__version__ = '.'.join(str(e) for e in __version_info__)
__description__ = "A keyboard-driven, vim-like browser based on PyQt5."

View File

@@ -410,10 +410,8 @@ def _init_modules(args, crash_handler):
log.init.debug("Initializing network...")
networkmanager.init()
if qtutils.version_check('5.8'):
# Otherwise we can only initialize it for QtWebKit because of crashes
log.init.debug("Initializing proxy...")
proxy.init()
log.init.debug("Initializing proxy...")
proxy.init()
log.init.debug("Initializing readline-bridge...")
readline_bridge = readline.ReadlineBridge()
@@ -636,7 +634,7 @@ class Quitter:
# Save the session if one is given.
if session is not None:
session_manager = objreg.get('session-manager')
session_manager.save(session)
session_manager.save(session, with_private=True)
# Open a new process and immediately shutdown the existing one
try:
args, cwd = self._get_restart_args(pages, session)

View File

@@ -20,11 +20,12 @@
"""Command dispatcher for TabbedBrowser."""
import os
import sys
import os.path
import shlex
import functools
from PyQt5.QtWidgets import QApplication, QTabBar
from PyQt5.QtWidgets import QApplication, QTabBar, QDialog
from PyQt5.QtCore import Qt, QUrl, QEvent, QUrlQuery
from PyQt5.QtGui import QKeyEvent
from PyQt5.QtPrintSupport import QPrintDialog, QPrintPreviewDialog
@@ -227,19 +228,6 @@ class CommandDispatcher:
self._tabbed_browser.close_tab(tab)
tabbar.setSelectionBehaviorOnRemove(old_selection_behavior)
def _tab_close_prompt_if_pinned(self, tab, force, yes_action):
"""Helper method for tab_close.
If tab is pinned, prompt. If everything is good, run yes_action.
"""
if tab.data.pinned and not force:
message.confirm_async(
title='Pinned Tab',
text="Are you sure you want to close a pinned tab?",
yes_action=yes_action, default=False)
else:
yes_action()
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
def tab_close(self, prev=False, next_=False, opposite=False,
@@ -260,7 +248,7 @@ class CommandDispatcher:
close = functools.partial(self._tab_close, tab, prev,
next_, opposite)
self._tab_close_prompt_if_pinned(tab, force, close)
self._tabbed_browser.tab_close_prompt_if_pinned(tab, force, close)
@cmdutils.register(instance='command-dispatcher', scope='window',
name='tab-pin')
@@ -280,9 +268,7 @@ class CommandDispatcher:
return
to_pin = not tab.data.pinned
tab_index = self._current_index() if count is None else count - 1
cmdutils.check_overflow(tab_index + 1, 'int')
self._tabbed_browser.set_tab_pinned(tab_index, to_pin)
self._tabbed_browser.set_tab_pinned(tab, to_pin)
@cmdutils.register(instance='command-dispatcher', name='open',
maxsplit=0, scope='window')
@@ -438,9 +424,18 @@ class CommandDispatcher:
message.error("Printing failed!")
diag.deleteLater()
def do_print():
"""Called when the dialog was closed."""
tab.printing.to_printer(diag.printer(), print_callback)
diag = QPrintDialog(tab)
diag.open(lambda: tab.printing.to_printer(diag.printer(),
print_callback))
if sys.platform == 'darwin':
# For some reason we get a segfault when using open() on macOS
ret = diag.exec_()
if ret == QDialog.Accepted:
do_print()
else:
diag.open(do_print)
@cmdutils.register(instance='command-dispatcher', name='print',
scope='window')
@@ -515,7 +510,7 @@ class CommandDispatcher:
newtab.data.keep_icon = True
newtab.history.deserialize(history)
newtab.zoom.set_factor(curtab.zoom.factor())
new_tabbed_browser.set_tab_pinned(idx, curtab.data.pinned)
new_tabbed_browser.set_tab_pinned(newtab, curtab.data.pinned)
return newtab
@cmdutils.register(instance='command-dispatcher', scope='window')
@@ -868,7 +863,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('count', count=True)
def zoom(self, zoom: int = None, count=None):
def zoom(self, zoom=None, count=None):
"""Set the zoom level for the current tab.
The zoom can be given as argument or as [count]. If neither is
@@ -879,6 +874,13 @@ class CommandDispatcher:
zoom: The zoom percentage to set.
count: The zoom percentage to set.
"""
if zoom is not None:
try:
zoom = int(zoom.rstrip('%'))
except ValueError:
raise cmdexc.CommandError("zoom: Invalid int value {}"
.format(zoom))
level = count if count is not None else zoom
if level is None:
level = config.get('ui', 'default-zoom')
@@ -913,8 +915,9 @@ class CommandDispatcher:
if not force:
for i, tab in enumerate(self._tabbed_browser.widgets()):
if _to_close(i) and tab.data.pinned:
self._tab_close_prompt_if_pinned(
tab, force,
self._tabbed_browser.tab_close_prompt_if_pinned(
tab,
force,
lambda: self.tab_only(
prev=prev, next_=next_, force=True))
return
@@ -925,7 +928,7 @@ class CommandDispatcher:
@cmdutils.register(instance='command-dispatcher', scope='window')
def undo(self):
"""Re-open a closed tab (optionally skipping [count] closed tabs)."""
"""Re-open a closed tab."""
try:
self._tabbed_browser.undo()
except IndexError:
@@ -1160,6 +1163,7 @@ class CommandDispatcher:
detach: Whether the command should be detached from qutebrowser.
cmdline: The commandline to execute.
"""
cmdutils.check_exclusive((userscript, detach), 'ud')
try:
cmd, *args = shlex.split(cmdline)
except ValueError as e:

View File

@@ -28,7 +28,9 @@ Module attributes:
"""
import os
import logging
import sys
import ctypes
import ctypes.util
from PyQt5.QtGui import QFont
from PyQt5.QtWebEngineWidgets import (QWebEngineSettings, QWebEngineProfile,
@@ -132,9 +134,6 @@ def _init_stylesheet(profile):
Mostly inspired by QupZilla:
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/app/mainapplication.cpp#L1063-L1101
https://github.com/QupZilla/qupzilla/blob/v2.0/src/lib/tools/scripts.cpp#L119-L132
FIXME:qtwebengine Use QWebEngineStyleSheet once that's available
https://codereview.qt-project.org/#/c/148671/
"""
old_script = profile.scripts().findScript('_qute_stylesheet')
if not old_script.isNull():
@@ -203,12 +202,10 @@ def init(args):
if args.enable_webengine_inspector:
os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = str(utils.random_port())
# Workaround for a black screen with some setups
# https://github.com/spyder-ide/spyder/issues/3226
if not os.environ.get('QUTE_NO_OPENGL_WORKAROUND'):
# Hide "No OpenGL_accelerate module loaded: ..." message
logging.getLogger('OpenGL.acceleratesupport').propagate = False
from OpenGL import GL # pylint: disable=unused-variable
# WORKAROUND for
# https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
if sys.platform == 'linux':
ctypes.CDLL(ctypes.util.find_library("GL"), mode=ctypes.RTLD_GLOBAL)
_init_profiles()

View File

@@ -20,6 +20,7 @@
"""Wrapper over a QWebEngineView."""
import os
import math
import functools
import sip
@@ -50,12 +51,13 @@ def init():
global _qute_scheme_handler
app = QApplication.instance()
software_rendering = os.environ.get('LIBGL_ALWAYS_SOFTWARE') == '1'
software_rendering = (os.environ.get('LIBGL_ALWAYS_SOFTWARE') == '1' or
'QT_XCB_FORCE_SOFTWARE_OPENGL' in os.environ)
if version.opengl_vendor() == 'nouveau' and not software_rendering:
# FIXME:qtwebengine display something more sophisticated here
raise browsertab.WebTabError(
"QtWebEngine is not supported with Nouveau graphics (unless "
"LIBGL_ALWAYS_SOFTWARE is set as environment variable).")
"QT_XCB_FORCE_SOFTWARE_OPENGL is set as environment variable).")
log.init.debug("Initializing qute://* handler...")
_qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(parent=app)
@@ -342,7 +344,7 @@ class WebEngineScroller(browsertab.AbstractScroller):
else:
perc_y = min(100, round(100 / dy * jsret['px']['y']))
self._at_bottom = dy >= jsret['px']['y']
self._at_bottom = math.ceil(jsret['px']['y']) >= dy
self._pos_perc = perc_x, perc_y
self.perc_changed.emit(*self._pos_perc)

View File

@@ -33,7 +33,6 @@ from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtPrintSupport import QPrinter
from qutebrowser.browser import browsertab
from qutebrowser.browser.network import proxy
from qutebrowser.browser.webkit import webview, tabhistory, webkitelem
from qutebrowser.browser.webkit.network import webkitqutescheme
from qutebrowser.utils import qtutils, objreg, usertypes, utils, log, debug
@@ -42,12 +41,6 @@ from qutebrowser.utils import qtutils, objreg, usertypes, utils, log, debug
def init():
"""Initialize QtWebKit-specific modules."""
qapp = QApplication.instance()
if not qtutils.version_check('5.8'):
# Otherwise we initialize it globally in app.py
log.init.debug("Initializing proxy...")
proxy.init()
log.init.debug("Initializing js-bridge...")
js_bridge = webkitqutescheme.JSBridge(qapp)
objreg.register('js-bridge', js_bridge)

View File

@@ -437,14 +437,10 @@ def data(readonly=False):
"User agent to send. Empty to send the default."),
('proxy',
SettingValue(typ.Proxy(), 'system',
backends=(None if qtutils.version_check('5.8')
else [usertypes.Backend.QtWebKit])),
SettingValue(typ.Proxy(), 'system'),
"The proxy to use.\n\n"
"In addition to the listed values, you can use a `socks://...` "
"or `http://...` URL.\n\n"
"This setting only works with Qt 5.8 or newer when using the "
"QtWebEngine backend."),
"or `http://...` URL."),
('proxy-dns-requests',
SettingValue(typ.Bool(), 'true',

View File

@@ -70,6 +70,8 @@ the <span class="mono">qute://settings</span> page or caret browsing).</span>
{{ install_webengine('qt5-qtwebengine') }}
{% elif distribution.parsed == Distribution.opensuse %}
{{ install_webengine('libqt5-qtwebengine') }}
{% elif distribution.parsed == Distribution.gentoo %}
{{ install_webengine('dev-qt/qtwebengine') }}
{% else %}
{{ unknown_system() }}
{% endif %}

View File

@@ -61,7 +61,7 @@ li {
{{ super() }}
function tryagain()
{
location.href = url;
location.href = "{{ url }}";
}
{% endblock %}

View File

@@ -43,3 +43,4 @@ rules:
array-bracket-newline: "off"
array-element-newline: "off"
no-multi-spaces: ["error", {"ignoreEOLComments": true}]
function-paren-newline: "off"

View File

@@ -232,6 +232,19 @@ class TabbedBrowser(tabwidget.TabWidget):
for tab in self.widgets():
self._remove_tab(tab)
def tab_close_prompt_if_pinned(self, tab, force, yes_action):
"""Helper method for tab_close.
If tab is pinned, prompt. If everything is good, run yes_action.
"""
if tab.data.pinned and not force:
message.confirm_async(
title='Pinned Tab',
text="Are you sure you want to close a pinned tab?",
yes_action=yes_action, default=False)
else:
yes_action()
def close_tab(self, tab, *, add_undo=True):
"""Close a tab.
@@ -273,6 +286,8 @@ class TabbedBrowser(tabwidget.TabWidget):
"""
idx = self.indexOf(tab)
if idx == -1:
if crashed:
return
raise TabDeletedError("tab {} is not contained in "
"TabbedWidget!".format(tab))
if tab is self._now_focused:
@@ -340,7 +355,7 @@ class TabbedBrowser(tabwidget.TabWidget):
newtab = self.tabopen(url, background=False, idx=idx)
newtab.history.deserialize(history_data)
self.set_tab_pinned(idx, pinned)
self.set_tab_pinned(newtab, pinned)
@pyqtSlot('QUrl', bool)
def openurl(self, url, newtab):
@@ -364,7 +379,8 @@ class TabbedBrowser(tabwidget.TabWidget):
log.webview.debug("Got invalid tab {} for index {}!".format(
tab, idx))
return
self.close_tab(tab)
self.tab_close_prompt_if_pinned(
tab, False, lambda: self.close_tab(tab))
@pyqtSlot(browsertab.AbstractTab)
def on_window_close_requested(self, widget):

View File

@@ -26,7 +26,7 @@ from PyQt5.QtCore import (pyqtSignal, pyqtSlot, Qt, QSize, QRect, QPoint,
QTimer, QUrl)
from PyQt5.QtWidgets import (QTabWidget, QTabBar, QSizePolicy, QCommonStyle,
QStyle, QStylePainter, QStyleOptionTab,
QStyleFactory)
QStyleFactory, QWidget)
from PyQt5.QtGui import QIcon, QPalette, QColor
from qutebrowser.utils import qtutils, objreg, utils, usertypes, log
@@ -94,17 +94,18 @@ class TabWidget(QTabWidget):
bar.set_tab_data(idx, 'indicator-color', color)
bar.update(bar.tabRect(idx))
def set_tab_pinned(self, idx, pinned, *, loading=False):
def set_tab_pinned(self, tab: QWidget,
pinned: bool, *, loading: bool = False) -> None:
"""Set the tab status as pinned.
Args:
idx: The tab index.
tab: The tab to pin
pinned: Pinned tab state to set.
loading: Whether to ignore current data state when
counting pinned_count.
"""
bar = self.tabBar()
tab = self.widget(idx)
idx = self.indexOf(tab)
# Only modify pinned_count if we had a change
# always modify pinned_count if we are loading
@@ -502,10 +503,6 @@ class TabBar(QTabBar):
# We return it directly rather than setting `size' because we don't
# want to ensure it's valid in this special case.
return QSize()
elif self.count() * minimum_size.width() > self.width():
# If we don't have enough space, we return the minimum size so we
# get scroll buttons as soon as needed.
size = minimum_size
else:
tab_width_pinned_conf = config.get('tabs', 'pinned-width')
@@ -516,19 +513,21 @@ class TabBar(QTabBar):
no_pinned_count = self.count() - self.pinned_count
pinned_width = tab_width_pinned_conf * self.pinned_count
no_pinned_width = self.width() - pinned_width
# Prevent any tabs from being smaller than the min size
no_pinned_width = max(self.width() - pinned_width,
minimum_size.width() * no_pinned_count)
if pinned:
width = tab_width_pinned_conf
else:
# If we *do* have enough space, tabs should occupy the whole
# window width. If there are pinned tabs their size will be
# subtracted from the total window width.
# During shutdown the self.count goes down,
# but the self.pinned_count not - this generates some odd
# Tabs should attempt to occupy the whole window width. If
# there are pinned tabs their size will be subtracted from the
# total window width. During shutdown the self.count goes
# down, but the self.pinned_count not - this generates some odd
# behavior. To avoid this we compare self.count against
# self.pinned_count.
# self.pinned_count. If we end up having too little space, we
# set the minimum size below.
if self.pinned_count > 0 and no_pinned_count > 0:
width = no_pinned_width / no_pinned_count
else:
@@ -540,6 +539,10 @@ class TabBar(QTabBar):
index < no_pinned_width % no_pinned_count):
width += 1
# If we don't have enough space, we return the minimum size so we
# get scroll buttons as soon as needed.
width = max(width, minimum_size.width())
size = QSize(width, height)
qtutils.ensure_valid(size)
return size

View File

@@ -336,12 +336,12 @@ def check_libraries(backend):
"http://pyyaml.org/download/pyyaml/ (py3.4) "
"or Install via pip.",
pip="PyYAML"),
'PyQt5.QtQml': _missing_str("PyQt5.QtQml"),
}
if backend == 'webengine':
modules['PyQt5.QtWebEngineWidgets'] = _missing_str("QtWebEngine",
webengine=True)
modules['PyQt5.QtOpenGL'] = _missing_str("PyQt5.QtOpenGL")
modules['OpenGL'] = _missing_str("PyOpenGL")
else:
assert backend == 'webkit'
modules['PyQt5.QtWebKit'] = _missing_str("PyQt5.QtWebKit")

View File

@@ -154,8 +154,8 @@ class GUIProcess(QObject):
log.procs.debug("Process started.")
self._started = True
else:
message.error("Error while spawning {}: {}.".format(
self._what, self._proc.error()))
message.error("Error while spawning {}: {}".format(
self._what, ERROR_STRINGS[self._proc.error()]))
def exit_status(self):
return self._proc.exitStatus()

View File

@@ -406,7 +406,7 @@ class SessionManager(QObject):
tab_to_focus = i
if new_tab.data.pinned:
tabbed_browser.set_tab_pinned(
i, new_tab.data.pinned, loading=True)
new_tab, new_tab.data.pinned, loading=True)
if tab_to_focus is not None:
tabbed_browser.setCurrentIndex(tab_to_focus)
if win.get('active', False):
@@ -420,7 +420,10 @@ class SessionManager(QObject):
def delete(self, name):
"""Delete a session."""
path = self._get_session_path(name, check_exists=True)
os.remove(path)
try:
os.remove(path)
except OSError as e:
raise SessionError(e)
self.update_completion.emit()
def list_sessions(self):
@@ -489,7 +492,7 @@ class SessionManager(QObject):
try:
if only_active_window:
name = self.save(name, only_window=win_id,
with_private=with_private)
with_private=True)
else:
name = self.save(name, with_private=with_private)
except SessionError as e:
@@ -516,7 +519,7 @@ class SessionManager(QObject):
self.delete(name)
except SessionNotFoundError:
raise cmdexc.CommandError("Session {} not found!".format(name))
except (OSError, SessionError) as e:
except SessionError as e:
log.sessions.exception("Error while deleting session!")
raise cmdexc.CommandError("Error while deleting session: {}"
.format(e))

View File

@@ -64,8 +64,7 @@ def get_argparser():
help="How URLs should be opened if there is already a "
"qutebrowser instance running.")
parser.add_argument('--backend', choices=['webkit', 'webengine'],
help="Which backend to use (webengine backend is "
"EXPERIMENTAL!).")
help="Which backend to use.")
parser.add_argument('--enable-webengine-inspector', action='store_true',
help="Enable the web inspector for QtWebEngine. Note "
"that this is a SECURITY RISK and you should not "

View File

@@ -81,6 +81,8 @@ def distribution():
return None
pretty = info.get('PRETTY_NAME', 'Unknown')
if pretty == 'Linux': # Thanks, Funtoo
pretty = info.get('NAME', pretty)
if 'VERSION_ID' in info:
dist_version = pkg_resources.parse_version(info['VERSION_ID'])
@@ -88,8 +90,11 @@ def distribution():
dist_version = None
dist_id = info.get('ID', None)
id_mappings = {
'funtoo': 'gentoo', # does not have ID_LIKE=gentoo
}
try:
parsed = Distribution[dist_id]
parsed = Distribution[id_mappings.get(dist_id, dist_id)]
except KeyError:
parsed = Distribution.unknown
@@ -186,7 +191,6 @@ def _module_versions():
('yaml', ['__version__']),
('cssutils', ['__version__']),
('typing', []),
('OpenGL', ['__version__']),
('PyQt5.QtWebEngineWidgets', []),
('PyQt5.QtWebKitWidgets', []),
])

View File

@@ -7,4 +7,3 @@ MarkupSafe==1.0
Pygments==2.2.0
pyPEG2==2.15.2
PyYAML==3.12
PyOpenGL==3.1.0

View File

@@ -64,7 +64,7 @@ def call_tox(toxenv, *args, python=sys.executable):
env['PYTHON'] = python
env['PATH'] = os.environ['PATH'] + os.pathsep + os.path.dirname(python)
subprocess.check_call(
[sys.executable, '-m', 'tox', '-v', '-e', toxenv] + list(args),
[sys.executable, '-m', 'tox', '-vv', '-e', toxenv] + list(args),
env=env)
@@ -109,8 +109,11 @@ def patch_osx_app():
for f in glob.glob(os.path.join(qtwe_core_dir, 'Resources', '*')):
dest = os.path.join(app_path, 'Contents', 'Resources')
if os.path.isdir(f):
shutil.copytree(f, os.path.join(dest, f))
dir_dest = os.path.join(dest, os.path.basename(f))
print("Copying directory {} to {}".format(f, dir_dest))
shutil.copytree(f, dir_dest)
else:
print("Copying {} to {}".format(f, dest))
shutil.copy(f, dest)
# Link dependencies
for lib in ['QtCore', 'QtWebEngineCore', 'QtQuick', 'QtQml', 'QtNetwork',
@@ -124,7 +127,16 @@ def patch_osx_app():
def build_osx():
"""Build OS X .dmg/.app."""
utils.print_title("Cleaning up...")
for f in ['wc.dmg', 'template.dmg']:
try:
os.remove(f)
except FileNotFoundError:
pass
for d in ['dist', 'build']:
shutil.rmtree(d, ignore_errors=True)
utils.print_title("Updating 3rdparty content")
# Currently disabled because QtWebEngine has no pdfjs support
# update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)
utils.print_title("Building .app via pyinstaller")
call_tox('pyinstaller', '-r')
@@ -132,25 +144,24 @@ def build_osx():
patch_osx_app()
utils.print_title("Building .dmg")
subprocess.check_call(['make', '-f', 'scripts/dev/Makefile-dmg'])
utils.print_title("Cleaning up...")
for f in ['wc.dmg', 'template.dmg']:
os.remove(f)
for d in ['dist', 'build']:
shutil.rmtree(d)
dmg_name = 'qutebrowser-{}.dmg'.format(qutebrowser.__version__)
os.rename('qutebrowser.dmg', dmg_name)
utils.print_title("Running smoke test")
with tempfile.TemporaryDirectory() as tmpdir:
subprocess.check_call(['hdiutil', 'attach', dmg_name,
'-mountpoint', tmpdir])
try:
binary = os.path.join(tmpdir, 'qutebrowser.app', 'Contents',
'MacOS', 'qutebrowser')
smoke_test(binary)
finally:
subprocess.check_call(['hdiutil', 'detach', tmpdir])
try:
with tempfile.TemporaryDirectory() as tmpdir:
subprocess.check_call(['hdiutil', 'attach', dmg_name,
'-mountpoint', tmpdir])
try:
binary = os.path.join(tmpdir, 'qutebrowser.app', 'Contents',
'MacOS', 'qutebrowser')
smoke_test(binary)
finally:
subprocess.call(['hdiutil', 'detach', tmpdir])
except PermissionError as e:
print("Failed to remove tempdir: {}".format(e))
return [(dmg_name, 'application/x-apple-diskimage', 'OS X .dmg')]
@@ -167,6 +178,7 @@ def patch_windows(out_dir):
def build_windows():
"""Build windows executables/setups."""
utils.print_title("Updating 3rdparty content")
# Currently disabled because QtWebEngine has no pdfjs support
# update_3rdparty.run(ace=False, pdfjs=True, fancy_dmg=False)
utils.print_title("Building Windows binaries")
@@ -203,8 +215,8 @@ def build_windows():
'/DVERSION={}'.format(qutebrowser.__version__),
'misc/qutebrowser.nsi'])
name_32 = 'qutebrowser-{}-win32.msi'.format(qutebrowser.__version__)
name_64 = 'qutebrowser-{}-amd64.msi'.format(qutebrowser.__version__)
name_32 = 'qutebrowser-{}-win32.exe'.format(qutebrowser.__version__)
name_64 = 'qutebrowser-{}-amd64.exe'.format(qutebrowser.__version__)
artifacts += [
(os.path.join('dist', name_32),
@@ -280,6 +292,14 @@ def build_sdist():
return artifacts
def read_github_token():
"""Read the GitHub API token from disk."""
token_file = os.path.join(os.path.expanduser('~'), '.gh_token')
with open(token_file, encoding='ascii') as f:
token = f.read().strip()
return token
def github_upload(artifacts, tag):
"""Upload the given artifacts to GitHub.
@@ -290,9 +310,7 @@ def github_upload(artifacts, tag):
import github3
utils.print_title("Uploading to github...")
token_file = os.path.join(os.path.expanduser('~'), '.gh_token')
with open(token_file, encoding='ascii') as f:
token = f.read().strip()
token = read_github_token()
gh = github3.login(token=token)
repo = gh.repository('qutebrowser', 'qutebrowser')
@@ -329,6 +347,12 @@ def main():
upload_to_pypi = False
if args.upload is not None:
# Fail early when trying to upload without github3 installed
# or without API token
import github3 # pylint: disable=unused-variable
read_github_token()
if os.name == 'nt':
if sys.maxsize > 2**32:
# WORKAROUND

View File

@@ -43,6 +43,12 @@ travis_retry() {
}
apt_install() {
sudo tee /etc/apt/sources.list <<EOF
deb http://us.archive.ubuntu.com/ubuntu/ trusty main
deb http://us.archive.ubuntu.com/ubuntu/ trusty-security main
deb http://us.archive.ubuntu.com/ubuntu/ trusty-updates main
EOF
sudo rm -rf /etc/apt/sources.list.d
travis_retry sudo apt-get -y -q update
travis_retry sudo apt-get -y -q install --no-install-recommends "$@"
}
@@ -64,8 +70,9 @@ npm_install() {
}
install_node() {
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
apt_install nodejs
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
travis_retry sudo apt-get -y -q update
travis_retry sudo apt-get -y -q install --no-install-recommends nodejs
}
check_pyqt() {

View File

@@ -365,8 +365,7 @@ def generate_commands(filename):
def _generate_setting_section(f, sectname, sect):
"""Generate documentation for a single section."""
version_dependent_options = [('network', 'proxy'),
('general', 'print-element-backgrounds')]
version_dependent_options = [('general', 'print-element-backgrounds')]
for optname, option in sect.items():
f.write("\n")
f.write('[[{}-{}]]'.format(sectname, optname) + "\n")

View File

@@ -579,9 +579,9 @@ Feature: Downloading things from a website.
And I wait until the download is finished
Then the downloaded file content-size should exist
@posix
Scenario: Downloading to unwritable destination
When I set storage -> prompt-download-directory to false
When the unwritable dir is unwritable
And I set storage -> prompt-download-directory to false
And I run :download http://localhost:(port)/data/downloads/download.bin --dest (tmpdir)/downloads/unwritable
Then the error "Download error: Permission denied" should be shown

View File

@@ -153,3 +153,26 @@ Feature: Using private browsing
- history:
- url: http://localhost:*/data/numbers/1.txt
- url: http://localhost:*/data/numbers/2.txt
Scenario: Saving a private session with only-active-window
When I open data/numbers/1.txt
And I open data/numbers/2.txt in a new tab
And I open data/numbers/3.txt in a private window
And I open data/numbers/4.txt in a new tab
And I open data/numbers/5.txt in a new tab
And I run :session-save --only-active-window window_session_name
And I run :window-only
And I run :tab-only
And I run :session-load -c window_session_name
And I wait until data/numbers/5.txt is loaded
Then the session should look like:
windows:
- tabs:
- history:
- url: http://localhost:*/data/numbers/3.txt
- history:
- url: http://localhost:*/data/numbers/4.txt
- history:
- active: true
url: http://localhost:*/data/numbers/5.txt

View File

@@ -292,6 +292,13 @@ Feature: Scrolling
And I run :scroll-page --bottom-navigate next 0 1
Then data/hello2.txt should be loaded
Scenario: :scroll-page with --bottom-navigate when not at the bottom
When I run :scroll-px 0 10
And I wait until the scroll position changed
And I run :scroll-page --bottom-navigate next 0 1
Then the following tabs should be open:
- data/scroll/simple.html
Scenario: :scroll-page with --top-navigate
When I run :scroll-page --top-navigate prev 0 -1
Then data/hello3.txt should be loaded

View File

@@ -60,8 +60,3 @@ Feature: :spawn
Scenario: Running :spawn with userscript that expects the stdin getting closed
When I run :spawn -u (testdata)/userscripts/stdinclose.py
Then the message "stdin closed" should be shown
@posix
Scenario: Running :spawn -d with userscript that expects the stdin getting closed
When I run :spawn -d -u (testdata)/userscripts/stdinclose.py
Then the message "stdin closed" should be shown

View File

@@ -1073,6 +1073,16 @@ Feature: Tab management
- data/numbers/2.txt (pinned)
- data/numbers/3.txt (active)
Scenario: :tab-pin with an invalid count
When I open data/numbers/1.txt
And I open data/numbers/2.txt in a new tab
And I open data/numbers/3.txt in a new tab
And I run :tab-pin with count 23
Then the following tabs should be open:
- data/numbers/1.txt
- data/numbers/2.txt
- data/numbers/3.txt (active)
Scenario: Pinned :tab-close prompt yes
When I open data/numbers/1.txt
And I run :tab-pin

View File

@@ -21,6 +21,7 @@ import os
import sys
import shlex
import pytest
import pytest_bdd as bdd
bdd.scenarios('downloads.feature')
@@ -53,6 +54,14 @@ def clean_old_downloads(quteproc):
quteproc.send_cmd(':download-clear')
@bdd.when("the unwritable dir is unwritable")
def check_unwritable(tmpdir):
unwritable = tmpdir / 'downloads' / 'unwritable'
if os.access(str(unwritable), os.W_OK):
# Docker container or similar
pytest.skip("Unwritable dir was writable")
@bdd.when("I wait until the download is finished")
def wait_for_download_finished(quteproc):
quteproc.wait_for(category='downloads', message='Download * finished')

View File

@@ -51,6 +51,11 @@ Feature: Zooming in and out
Then the message "Zoom level: 50%" should be shown
And the zoom should be 50%
Scenario: Setting zoom with trailing %
When I run :zoom 50%
Then the message "Zoom level: 50%" should be shown
And the zoom should be 50%
Scenario: Setting zoom with count
When I run :zoom with count 40
Then the message "Zoom level: 40%" should be shown

View File

@@ -0,0 +1,251 @@
[general]
ignore-case = smart
startpage = https://start.duckduckgo.com
yank-ignored-url-parameters = ref,utm_source,utm_medium,utm_campaign,utm_term,utm_content
default-open-dispatcher =
default-page = ${startpage}
auto-search = naive
auto-save-config = true
auto-save-interval = 15000
editor = gvim -f "{}"
editor-encoding = utf-8
private-browsing = false
developer-extras = false
print-element-backgrounds = true
xss-auditing = false
default-encoding = iso-8859-1
new-instance-open-target = tab
new-instance-open-target.window = last-focused
log-javascript-console = debug
save-session = false
session-default-name =
url-incdec-segments = path,query
[ui]
history-session-interval = 30
zoom-levels = 25%,33%,50%,67%,75%,90%,100%,110%,125%,150%,175%,200%,250%,300%,400%,500%
default-zoom = 100%
downloads-position = top
status-position = bottom
message-timeout = 2000
message-unfocused = false
confirm-quit = never
zoom-text-only = false
frame-flattening = false
user-stylesheet =
hide-scrollbar = true
smooth-scrolling = false
remove-finished-downloads = -1
hide-statusbar = false
statusbar-padding = 1,1,0,0
window-title-format = {perc}{title}{title_sep}qutebrowser
modal-js-dialog = false
hide-wayland-decoration = false
keyhint-blacklist =
keyhint-delay = 500
prompt-radius = 8
prompt-filebrowser = true
[network]
do-not-track = true
accept-language = en-US,en
referer-header = same-domain
user-agent =
proxy = system
proxy-dns-requests = true
ssl-strict = ask
dns-prefetch = true
custom-headers =
netrc-file =
[completion]
show = always
download-path-suggestion = path
timestamp-format = %Y-%m-%d
height = 50%
cmd-history-max-items = 100
web-history-max-items = 1000
quick-complete = true
shrink = false
scrollbar-width = 12
scrollbar-padding = 2
[input]
timeout = 500
partial-timeout = 5000
insert-mode-on-plugins = false
auto-leave-insert-mode = true
auto-insert-mode = false
forward-unbound-keys = auto
spatial-navigation = false
links-included-in-focus-chain = true
rocker-gestures = false
mouse-zoom-divider = 512
[tabs]
background-tabs = false
select-on-remove = next
new-tab-position = next
new-tab-position-explicit = last
last-close = ignore
show = always
show-switching-delay = 800
wrap = true
movable = true
close-mouse-button = middle
position = top
show-favicons = true
favicon-scale = 1.0
width = 20%
pinned-width = 43
indicator-width = 3
tabs-are-windows = false
title-format = {index}: {title}
title-format-pinned = {index}
title-alignment = left
mousewheel-tab-switching = true
padding = 0,0,5,5
indicator-padding = 2,2,0,4
[storage]
download-directory =
prompt-download-directory = true
remember-download-directory = true
maximum-pages-in-cache = 0
offline-web-application-cache = true
local-storage = true
cache-size =
[content]
allow-images = true
allow-javascript = true
allow-plugins = false
webgl = true
hyperlink-auditing = false
geolocation = ask
notifications = ask
media-capture = ask
javascript-can-open-windows-automatically = false
javascript-can-close-windows = false
javascript-can-access-clipboard = false
ignore-javascript-prompt = false
ignore-javascript-alert = false
local-content-can-access-remote-urls = false
local-content-can-access-file-urls = true
cookies-accept = no-3rdparty
cookies-store = true
host-block-lists = https://www.malwaredomainlist.com/hostslist/hosts.txt,http://someonewhocares.org/hosts/hosts,http://winhelp2002.mvps.org/hosts.zip,http://malwaredomains.lehigh.edu/files/justdomains.zip,https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&mimetype=plaintext
host-blocking-enabled = true
host-blocking-whitelist = piwik.org
enable-pdfjs = false
[hints]
border = 1px solid #E3BE23
mode = letter
chars = asdfghjkl
min-chars = 1
scatter = true
uppercase = false
dictionary = /usr/share/dict/words
auto-follow = unique-match
auto-follow-timeout = 0
next-regexes = \bnext\b,\bmore\b,\bnewer\b,\b[>→≫]\b,\b(>>|»)\b,\bcontinue\b
prev-regexes = \bprev(ious)?\b,\bback\b,\bolder\b,\b[<←≪]\b,\b(<<|«)\b
find-implementation = python
hide-unmatched-rapid-hints = true
[searchengines]
DEFAULT = https://duckduckgo.com/?q={}
[aliases]
[colors]
completion.fg = white
completion.bg = #333333
completion.alternate-bg = #444444
completion.category.fg = white
completion.category.bg = qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #888888, stop:1 #505050)
completion.category.border.top = black
completion.category.border.bottom = ${completion.category.border.top}
completion.item.selected.fg = black
completion.item.selected.bg = #e8c000
completion.item.selected.border.top = #bbbb00
completion.item.selected.border.bottom = ${completion.item.selected.border.top}
completion.match.fg = #ff4444
completion.scrollbar.fg = ${completion.fg}
completion.scrollbar.bg = ${completion.bg}
statusbar.fg = white
statusbar.bg = black
statusbar.fg.private = ${statusbar.fg}
statusbar.bg.private = #666666
statusbar.fg.insert = ${statusbar.fg}
statusbar.bg.insert = darkgreen
statusbar.fg.command = ${statusbar.fg}
statusbar.bg.command = ${statusbar.bg}
statusbar.fg.command.private = ${statusbar.fg.private}
statusbar.bg.command.private = ${statusbar.bg.private}
statusbar.fg.caret = ${statusbar.fg}
statusbar.bg.caret = purple
statusbar.fg.caret-selection = ${statusbar.fg}
statusbar.bg.caret-selection = #a12dff
statusbar.progress.bg = white
statusbar.url.fg = ${statusbar.fg}
statusbar.url.fg.success = white
statusbar.url.fg.success.https = lime
statusbar.url.fg.error = orange
statusbar.url.fg.warn = yellow
statusbar.url.fg.hover = aqua
tabs.fg.odd = white
tabs.bg.odd = grey
tabs.fg.even = white
tabs.bg.even = darkgrey
tabs.fg.selected.odd = white
tabs.bg.selected.odd = black
tabs.fg.selected.even = ${tabs.fg.selected.odd}
tabs.bg.selected.even = ${tabs.bg.selected.odd}
tabs.bg.bar = #555555
tabs.indicator.start = #0000aa
tabs.indicator.stop = #00aa00
tabs.indicator.error = #ff0000
tabs.indicator.system = rgb
hints.fg = black
hints.bg = qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 247, 133, 0.8), stop:1 rgba(255, 197, 66, 0.8))
hints.fg.match = green
downloads.bg.bar = black
downloads.fg.start = white
downloads.bg.start = #0000aa
downloads.fg.stop = ${downloads.fg.start}
downloads.bg.stop = #00aa00
downloads.fg.system = rgb
downloads.bg.system = rgb
downloads.fg.error = white
downloads.bg.error = red
webpage.bg = white
keyhint.fg = #FFFFFF
keyhint.fg.suffix = #FFFF00
keyhint.bg = rgba(0, 0, 0, 80%)
messages.fg.error = white
messages.bg.error = red
messages.border.error = #bb0000
messages.fg.warning = white
messages.bg.warning = darkorange
messages.border.warning = #d47300
messages.fg.info = white
messages.bg.info = black
messages.border.info = #333333
prompts.fg = white
prompts.bg = darkblue
prompts.selected.bg = #308cc6
[fonts]
_monospace = xos4 Terminus, Terminus, Monospace, "DejaVu Sans Mono", Monaco, "Bitstream Vera Sans Mono", "Andale Mono", "Courier New", Courier, "Liberation Mono", monospace, Fixed, Consolas, Terminal
completion = 8pt ${_monospace}
completion.category = bold ${completion}
tabbar = 8pt ${_monospace}
statusbar = 8pt ${_monospace}
downloads = 8pt ${_monospace}
hints = bold 13px ${_monospace}
debug-console = 8pt ${_monospace}
web-family-standard =
web-family-fixed =
web-family-serif =
web-family-sans-serif =
web-family-cursive =
web-family-fantasy =
web-size-minimum = 0
web-size-minimum-logical = 6
web-size-default = 16
web-size-default-fixed = 13
keyhint = 8pt ${_monospace}
messages.error = 8pt ${_monospace}
messages.warning = 8pt ${_monospace}
messages.info = 8pt ${_monospace}
prompts = 8pt sans-serif

View File

@@ -27,7 +27,6 @@ import shutil
from PyQt5.QtGui import QColor
import pytest
import qutebrowser
from qutebrowser.config import config, configexc, configdata
from qutebrowser.config.parsers import keyconf
from qutebrowser.commands import runners
@@ -397,19 +396,6 @@ class TestDefaultConfig:
for cmd in conf.get_bindings_for(sectname).values():
runner.parse(cmd)
def test_upgrade_version(self):
"""Fail when the qutebrowser version changed.
The aim of this is to remind us to add a new file to old_configs.
If the config file of the current release didn't change compared to the
last one in old_configs, just increment the version here.
If it did change, place a new qutebrowser-vx.y.z.conf in old_configs
and then increment the version.
"""
assert qutebrowser.__version__ == '0.10.1'
@pytest.mark.parametrize('filename',
os.listdir(os.path.join(os.path.dirname(__file__), 'old_configs')),
ids=os.path.basename)

View File

@@ -123,24 +123,30 @@ class TestFileHandling:
os.remove(filename)
@pytest.mark.posix
def test_unreadable(self, message_mock, editor, caplog):
"""Test file handling when closing with an unreadable file."""
editor.edit("")
filename = editor._file.name
assert os.path.exists(filename)
os.chmod(filename, 0o077)
if os.access(filename, os.R_OK):
# Docker container or similar
pytest.skip("File was still readable")
with caplog.at_level(logging.ERROR):
editor._proc.finished.emit(0, QProcess.NormalExit)
assert not os.path.exists(filename)
msg = message_mock.getmsg(usertypes.MessageLevel.error)
assert msg.text.startswith("Failed to read back edited file: ")
@pytest.mark.posix
def test_unwritable(self, monkeypatch, message_mock, editor, tmpdir,
caplog):
"""Test file handling when the initial file is not writable."""
tmpdir.chmod(0)
if os.access(str(tmpdir), os.W_OK):
# Docker container or similar
pytest.skip("File was still writable")
monkeypatch.setattr(editormod.tempfile, 'tempdir', str(tmpdir))
with caplog.at_level(logging.ERROR):

View File

@@ -128,11 +128,13 @@ def test_start_detached_error(fake_proc, message_mock, caplog):
"""Test starting a detached process with ok=False."""
argv = ['foo', 'bar']
fake_proc._proc.startDetached.return_value = (False, 0)
fake_proc._proc.error.return_value = "Error message"
fake_proc._proc.error.return_value = QProcess.FailedToStart
with caplog.at_level(logging.ERROR):
fake_proc.start_detached(*argv)
msg = message_mock.getmsg(usertypes.MessageLevel.error)
assert msg.text == "Error while spawning testprocess: Error message."
expected = ("Error while spawning testprocess: The process failed to "
"start.")
assert msg.text == expected
def test_double_start(qtbot, proc, py_proc):

View File

@@ -163,6 +163,15 @@ from qutebrowser.browser import pdfjs
version.DistributionInfo(
id='manjaro', parsed=version.Distribution.manjaro,
version=None, pretty='Manjaro Linux')),
# Funtoo
("""
ID="funtoo"
NAME="Funtoo GNU/Linux"
PRETTY_NAME="Linux"
""",
version.DistributionInfo(
id='funtoo', parsed=version.Distribution.gentoo,
version=None, pretty='Funtoo GNU/Linux')),
])
def test_distribution(tmpdir, monkeypatch, os_release, expected):
os_release_file = tmpdir / 'os-release'
@@ -496,7 +505,6 @@ class ImportFake:
'typing': True,
'PyQt5.QtWebEngineWidgets': True,
'PyQt5.QtWebKitWidgets': True,
'OpenGL': True,
}
self.version_attribute = '__version__'
self.version = '1.2.3'
@@ -556,7 +564,7 @@ class TestModuleVersions:
"""Test with all modules present in version 1.2.3."""
expected = ['sip: yes', 'colorama: 1.2.3', 'pypeg2: 1.2.3',
'jinja2: 1.2.3', 'pygments: 1.2.3', 'yaml: 1.2.3',
'cssutils: 1.2.3', 'typing: yes', 'OpenGL: 1.2.3',
'cssutils: 1.2.3', 'typing: yes',
'PyQt5.QtWebEngineWidgets: yes',
'PyQt5.QtWebKitWidgets: yes']
assert version._module_versions() == expected
@@ -580,17 +588,17 @@ class TestModuleVersions:
@pytest.mark.parametrize('value, expected', [
('VERSION', ['sip: yes', 'colorama: 1.2.3', 'pypeg2: yes',
'jinja2: yes', 'pygments: yes', 'yaml: yes',
'cssutils: yes', 'typing: yes', 'OpenGL: yes',
'cssutils: yes', 'typing: yes',
'PyQt5.QtWebEngineWidgets: yes',
'PyQt5.QtWebKitWidgets: yes']),
('SIP_VERSION_STR', ['sip: 1.2.3', 'colorama: yes', 'pypeg2: yes',
'jinja2: yes', 'pygments: yes', 'yaml: yes',
'cssutils: yes', 'typing: yes', 'OpenGL: yes',
'cssutils: yes', 'typing: yes',
'PyQt5.QtWebEngineWidgets: yes',
'PyQt5.QtWebKitWidgets: yes']),
(None, ['sip: yes', 'colorama: yes', 'pypeg2: yes', 'jinja2: yes',
'pygments: yes', 'yaml: yes', 'cssutils: yes', 'typing: yes',
'OpenGL: yes', 'PyQt5.QtWebEngineWidgets: yes',
'PyQt5.QtWebEngineWidgets: yes',
'PyQt5.QtWebKitWidgets: yes']),
])
def test_version_attribute(self, value, expected, import_fake):

24
tox.ini
View File

@@ -4,7 +4,7 @@
# and then run "tox" from this directory.
[tox]
envlist = py34,py35,py36-cov,misc,vulture,flake8,pylint,pyroma,check-manifest
envlist = py36-cov,misc,vulture,flake8,pylint,pyroma,check-manifest,eslint
distshare = {toxworkdir}
skipsdist = true
@@ -111,6 +111,28 @@ deps =
PyQt5==5.8.2
commands = {envpython} -bb -m pytest {posargs:tests}
[testenv:py35-pyqt59]
basepython = python3.5
setenv =
{[testenv]setenv}
QUTE_BDD_WEBENGINE=true
passenv = {[testenv]passenv}
deps =
{[testenv]deps}
PyQt5==5.9
commands = {envpython} -bb -m pytest {posargs:tests}
[testenv:py36-pyqt59]
basepython = {env:PYTHON:python3.6}
setenv =
{[testenv]setenv}
QUTE_BDD_WEBENGINE=true
passenv = {[testenv]passenv}
deps =
{[testenv]deps}
PyQt5==5.9
commands = {envpython} -bb -m pytest {posargs:tests}
# other envs
[testenv:mkvenv]