|
Currently, bigger changes are going on in qutebrowser, as part of a student research project about adding a plugin API to qutebrowser and moving a lot of code from the code into plugins. Due to that, bandwidth for pull request review is currently very limited, and contributions might lead to merge conflicts due to ongoing refactorings. |
I <3
[Of course, that says <3
in HTML.]
contributors!
This document contains guidelines for contributing to qutebrowser, as well as useful hints when doing so.
If anything mentioned here would prevent you from contributing, please let me know, and contribute anyways! The guidelines are meant to make life easier for me, but if you don’t follow everything in here, I won’t be mad at you. In fact, I will probably change it for you.
If you have any problems, I’m more than happy to help! You can get help in several ways:
-
Send a mail to the mailing list at qutebrowser@lists.qutebrowser.org (optionally subscribe first).
-
Join the IRC channel
#qutebrowser
on Freenode (webchat).
Finding something to work on
Chances are you already know something to improve or add when you’re reading this. It might be a good idea to ask on the mailing list or IRC channel to make sure nobody else started working on the same thing already.
If you want to find something useful to do, check the issue tracker. Some pointers:
If you prefer C++ or Javascript to Python, see the relevant issues which involve work in those languages:
-
C++ (mostly work on Qt, the library behind qutebrowser)
There are also some things to do if you don’t want to write code:
-
Help the community, e.g., on the mailinglist and the IRC channel.
-
Improve the documentation.
-
Help on the website and graphics (logo, etc.).
Using git
qutebrowser uses git for its development. You can clone the repo like this:
git clone https://github.com/qutebrowser/qutebrowser.git
If you don’t know git, a git cheatsheet might come in
handy. Of course, if using git is the issue which prevents you from
contributing, feel free to send normal patches instead, e.g., generated via
diff -Nur
.
Getting patches
The preferred way of submitting changes is to fork the repository and to submit a pull request.
If you prefer to send a patch to the mailinglist, you can generate a patch based on your changes like this:
git format-patch origin/master 
Replace master by the branch your work was based on, e.g.,
origin/develop .
|
Running qutebrowser
After installing qutebrowser via tox, you can run
.venv/bin/qutebrowser --debug --temp-basedir
to test your changes with debug
logging enabled and without affecting existing running instances.
Alternatively, you can install qutebrowser’s dependencies system-wide and run
python3 -m qutebrowser --debug --temp-basedir
.
Useful utilities
Checkers
qutebrowser uses tox to run its unittests and several linters/checkers.
Currently, the following tox environments are available:
-
Tests using pytest:
-
py35
,py36
: Run pytest for python 3.5/3.6 with the system-wide PyQt. -
py36-pyqt57
, …,py36-pyqt59
: Run pytest with the given PyQt version (py35-*
also works). -
py36-pyqt59-cov
: Run with coverage support (other Python/PyQt versions work too).
-
-
flake8
: Run various linting checks via flake8. -
vulture
: Run vulture to find unused code portions. -
pylint
: Run pylint static code analysis. -
pyroma
: Check packaging practices with pyroma. -
eslint
: Run ESLint javascript checker. -
check-manifest
: Check MANIFEST.in completeness with check-manifest. -
mkvenv
: Bootstrap a virtualenv for testing. -
misc
: Runscripts/misc_checks.py
to check for:-
untracked git files
-
VCS conflict markers
-
common spelling mistakes
-
The default test suite is run with tox
; the list of default
environments is obtained with tox -l
.
Please make sure the checks run without any warnings on your new contributions.
There’s always the possibility of false positives; the following techniques are useful to handle these:
-
Use
_foo
for unused parameters, withfoo
being a descriptive name. Using_
is discouraged. -
If you think you have a good reason to suppress a message, then add the following comment:
# pylint: disable=message-name
Note you can add this per line, per function/class, or per file. Please use the smallest scope which makes sense. Most of the time, this will be line scope.
-
If you really think a check shouldn’t be done globally as it yields a lot of false-positives, let me know! I’m still tweaking the parameters.
Running Specific Tests
While you are developing you often don’t want to run the full test suite each time.
Specific test environments can be run with tox -e <envlist>
.
Additional parameters can be passed to the test scripts by separating
them from tox
arguments with --
.
Examples:
# run only pytest tests which failed in last run:
tox -e py35 -- --lf
# run only the end2end feature tests:
tox -e py35 -- tests/end2end/features
# run everything with undo in the generated name, based on the scenario text
tox -e py35 -- tests/end2end/features/test_tabs_bdd.py -k undo
# run coverage test for specific file (updates htmlcov/index.html)
tox -e py35-cov -- tests/unit/browser/test_webelem.py
Profiling
In the scripts/ subfolder there’s a run_profile.py
which profiles the code
and shows a graphical representation of what takes how much time.
It uses the built-in Python cProfile module and can show the output in four different ways:
-
Raw profile file (
--profile-tool=none
) -
pyprof2calltree and KCacheGrind (
--profile-tool=kcachegrind
) -
SnakeViz (
--profile-tool=snakeviz
)
Debugging
There are some useful functions for debugging in the qutebrowser.utils.debug
module.
When starting qutebrowser with the --debug
flag, you also get useful debug
logs. You can add --logfilter [!]category[,category,…]
to restrict
logging to the given categories.
With --debug
there are also some additional debug-*
commands available,
for example :debug-all-objects
and :debug-all-widgets
which print a list of
all Qt objects/widgets to the debug log — this is very useful for finding
memory leaks.
Useful websites
Some resources which might be handy:
Documentation of used Python libraries:
Related RFCs and standards:
HTTP
-
RFC 7230 - Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing (Errata)
-
RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content (Errata)
-
RFC 7232 - Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests (Errata)
-
RFC 7233 - Hypertext Transfer Protocol (HTTP/1.1): Range Requests (Errata)
-
RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching (Errata)
-
RFC 7235 - Hypertext Transfer Protocol (HTTP/1.1): Authentication (Errata)
-
RFC 5987 - Character Set and Language Encoding for Hypertext Transfer Protocol (HTTP) Header Field Parameters (Errata)
-
RFC 6266 - Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP) (Errata)
-
RFC 6265 - HTTP State Management Mechanism (Cookies) (Errata)
Hints
Python and Qt objects
For many tasks, there are solutions available in both Qt and the Python standard library.
In qutebrowser, the policy is usually to use the Python libraries, as they provide exceptions and other benefits.
There are some exceptions to that:
-
QThread
is used instead of Python threads because it provides signals and slots. -
QProcess
is used instead of Python’ssubprocess
. -
QUrl
is used instead of storing URLs as string, see the handling URLs section for details.
When using Qt objects, two issues must be taken care of:
-
Methods of Qt objects report their status with their return values, instead of using exceptions.
If a function gets or returns a Qt object which has an
.isValid()
method such asQUrl
orQModelIndex
, there’s a helper functionensure_valid
inqutebrowser.utils.qtutils
which should get called on all such objects. It will raisequtebrowser.utils.qtutils.QtValueError
if the value is not valid.If a function returns something else on error, the return value should carefully be checked.
-
Methods of Qt objects have certain maximum values based on their underlying C++ types.
To avoid passing too large of a numeric parameter to a