If you like to help, pywikibot is not just writing code. You can help easily by categorizing, confirming, prioritizing bugs. Just go to the browse projects in phabricator and get the list. For more info see Bug management/How to triage.
Broken tests always get a High priority to be solved instantly. Priority of the framework library parts should be higher than that of scripts. Bugs should have higher priority than feature requests.
Making a patch
Commit messages should follow the Gerrit Commit message guidelines.
You may prefix the subject with indicator enclosed by square brackets. Here are some examples:
|[bugfix] or [FIX]||Fixes a bug – refer the related phabricator task. This patch should be prioritized.|
|[cleanup]||Code cleanup – does not affect the behavior but improves the code.|
|[compat2core]||Compat to core relationship – scripts merged from compat or some compat functionality merged to core.|
|[i18n]||Internationalisation issues – translating related code, translation dictionaries, interface to translatewiki.net.|
|[FEAT]||Feature – new options, additional behavior. A bit like [IMPR] below.|
|[IMPR]||Improvement – new options, additional behavior or code cleanup.|
|[L10N]||Localisation issues – project related code mostly done in config or family files.|
|[PEP8]||PEP8 related changes – code style changes, looks nicer.|
|[POC]||Proof of concept – indicates a new concept or new library part.|
|[TEST] or [tests]||Tests related code – mostly found in tests folder.|
|[WIP]||Working in Process – you may review it but don't submit it with CR+2. The patch author or committer is grateful for reviewing his code, suggestions and remarks.|
Pywikibot uses semantic versioning, which means that versions consist of three numbers (such as 1.2.4). These are used to convey the kind of backward compatibility you can expect...
- The first value is the major version. This changes infrequently, and indicates that backward incompatible changes have been made (such as the removal of deprecated functions).
- The second value is the minor version. This is the most common kind of release, and denotes that the improvements are backward compatible.
- The third value is the patch version. These tend not to contain substantial improvements or new features.
All code within the pywikibot directory must be deprecated before removal unless it is private. Our tools module provides several mechanisms to do so...
Scripts provide backward compatibility with regard to their behavior as well, but implementations can change at any time. Never import a script aside from testing.
Prior to version 6.4.0 pywikibot did not follow any particular versioning scheme.
Coding style guideline
Follow PEP 8
These are some standards for writing code - PEP 8 is mainly about writing your code in a way that would be easy to read. Most of the rules are enforced by Jenkins. Accepted code by Jenkins is voted with +2 (not +1!). Some of the most important things are:
- Add a space before and after an equal sign ("=") when you want to define a variable except in function/method signatures which don't use any spaces around the equal sign.
- Line breaks should be done before a binary operator, readability counts:
# No, operator is far away from their operands result = (isinstance(precision, int) and precision in self.PRECISION.values()) result = isinstance(precision, int) and ( precision in self.PRECISION.values()) # Yes, easy to read result = (isinstance(precision, int) and precision in self.PRECISION.values())
- All lines are shorter than 80 characters.
- Indentation is really important about readability of code, use it properly, use 4 spaces instead of tab character
- Imports should be sorted by “source” (first standard libraries, then third party and then local (pywikibot)), “type” (first normal
from X import Y) and then alphabetical. Between the sources (and preferably between types) should be a newline. Also, each import has to be in a separated line. For example:
import re import math import pywikibot from pywikibot.site import Namespace
Follow PEP 257
This standard is mainly about docstrings (documentation inside code). There are two kinds of docstring, one-line docstring and multi-line docstring. A one-line docstring has to be like:
def function(a, b): """Do X and return a list."""
and a multi-line docstring has to be like:
def function(argument1='Foo', argument2='Bar'): """ This function does something. Keyword arguments: argument1 -- the first argument (default "Foo") argument2 -- the second argument (default "Bar") """
Multi-line docstrings consist of a summary line just like a one-line docstring, followed by a blank line, followed by a more elaborate description. The summary line may be used by automatic indexing tools; it is important that it fits on one line and is separated from the rest of the docstring by a blank line.
- Names of classes has to be CapWord (use DataPage instead of Datapage, datapage or data_page)
- Names of functions and methods has to be lowercase with underscores for better readability (e.g. set_label instead setLabel, or SetLabel)
- Names of errors has to be CapWord with "Error" suffix (like NoPageError)
Don't forget to update the documentation both in mediawiki.org and in the code.
For adding the documentation you need to add it at the top of the class or file or function you're working on it as an example:
class WikibasePage(BasePage): """The base page for the Wikibase extension.""" def __init__(self, site, title: str = '', **kwargs): """ Initializer. If title is provided, either ns or entity_type must also be provided, and will be checked against the title parsed. :param site: Wikibase data site :type site: DataSite :param title: normalized title of the page :keyword ns: namespace :type ns: Namespace instance, or int :keyword entity_type: Wikibase entity type :type entity_type: str ('item' or 'property') :raises TypeError: incorrect use of parameters :raises ValueError: incorrect namespace """
Type annotations introduced with Python 3 due to PEP 3107 are highly recommended. Every method or function must have a documentation string. Documentation of a class constructor should be placed at the class documentation itself. Documentation should follow Epytext Markup Language.Epydoc fields decorators should be used. The pywikibot API reference is generated using the markup language. There is a help page about decorators also in python.org help wiki.
Major changes to the framework (except scripts and tests) should be noted in the ROADMAP.rst file.
Test via pyflakes
pyflakes is a tool to check correct usage of variables in code - for example if you define a variable and don't use it (or don't define a variable and use it), it returns an error for you.
You can easily install and run the check, there is a manual for it.
- Use "bot" instead of "robot" in naming variables, documentation, etc.
- Never use tab character, use 4 spaces instead.
- For any changes or new lines use single quotes for strings, or double quotes if the string contains a single quote.
- Do not use a
u''prefix on strings, as it is meaningless in Python 3.
- Prefer f-strings over
string.format(). Modulo operator
%for string formatting should be avoided.
- If you want to remove a part of code, don't comment it out. Just remove it. Probably deprecate their usage first.
- Don't use
\r(carriage return character) in code; some code editors add it automatically, check and delete them.
- Code should be written in a way that it is executable for Python 3.6+. (See details)
- Avoid using global variables with defining "global variable" at the beginning of the function.
- Comparisons to singletons must always be done with
- Use built-in string methods
endswith()to check for prefixes or suffixes instead of string slicing.
- Avoid deeply nested blocks:
if not page.exists(): pywikibot.output('Page does not exist.') elif page.isRedirectPage(): pywikibot.output('Redirect page.') else: treat(page)
- To be avoided:
if page.exists(): if page.isRedirectPage(): pywikibot.output('Redirect page.') else: treat(page) else: pywikibot.output('Page does not exist.')
- Avoid unnecessary
elifblocks if the leading
ifblock has a
returnstatement which leaves the control flow:
while True: if not page.exists(): continue if page.isRedirectPage(): break print('oops') print('ok then')
- To be avoided:
while True: if not page.exists(): continue elif page.isRedirectPage(): break else: print('oops') print('ok then')
- As contributor you may add yourself to the CREDITS.rst list.