How to contribute

Submitting changes

Due to confidentiality issues, we are not able for now to publish any source- controlled repository (even if we do have a Mercurial repository for the project). However, this does not prevent motivated users from contributing to the project by sending patches applied to the last published version of the library. To compensate the absence of source repository, we try to update the library as often as we can in order to keep the public source archive version as close as possible to the internal development version.

Coding guidelines

In general, we try to follow the standard Python coding guidelines, which cover all the important coding aspects (docstrings, comments, naming conventions, import statements, ...) as described here:

The easiest way to check that your code is following those guidelines is to run pylint (a note greater than 8/10 seems to be a reasonnable goal).

PyQt v4.4 compatibility issues

The project has to be compatible with PyQt >= v4.4 which means that the following recommendations should be followed:

  • avoid using super: when writing classes deriving from a QObject child class (i.e. almost any single class imported from QtGui or QtCore), the super builtin-function should not be used outside the constructor method (call the parent class method directly instead)
  • before using any function or method from PyQt4, please check that the feature you are about to use was already implemented in PyQt4 v4.4 (more precisely in the Qt version used in PyQt4 v4.4) – if not, a workaround should be implemented to avoid breaking compatibility
  • do not use the PyQt-specific QFileDialog static methods (not present in Qt) which were introduced in PyQt v4.6: getOpenFileNameAndFilter, getOpenFileNamesAndFilter and getSaveFileNameAndFilter (guidata provides wrappers around QFileDialog static methods handling the selected filter which were taken from the spyderlib library (from module spyderlib.qt.compat): they are available in guidata.qt.compat)

PyQt / PySide compatibility

The project should be mostly compatible with both PyQt and PySide (although PySide is not as popular as it used to be, so testing tend to be limited).

PyQt5 compatibility

In its current implementation, the code base has to be compatible with PyQt API #2 (PySide-compatible API, PyQt >= v4.6) and with PyQt5, which means that the following recommendations should be followed:

  • QVariant objects must not be used (API #2 compatibility)
  • Use exclusively new-style signals and slots
  • Read carefully PyQt5 documentation regarding class inheritance behavior: it is quite different than the old PyQt4 implementation. Producing code compatible with both PyQt4 and PyQt5 can be tricky: testing is essential.

Python 3 compatibility

Regarding Python 3 compatibility, we chose to handle it by maintaining a single source branch being compatible with both Python 2.6-2.7 and Python 3.

Here is what we have done.

Fixing trivial things with 2to3

The first step is to run the 2to3 script (see Python documentation) to convert print statements to print function calls – note that your source directory (named directory_name) has to be version controlled (no backup is done thanks to the -n option flag). python 2to3.py -w -n -f print directory_name

Open each modified source file and add the following line at the beginning: from __future__ import print_function

Then run again 2to3 with all other Python 2/3 compatible fixers: python 2to3.py -w -n -f apply -f dict -f except -f exitfunc -f filter -f has_key -f map -f ne -f raise -f ws_comma -f xrange -f xreadlines -f zip directory_name

After these two steps, your code should be compatible with Python 2.6, 2.7 and 3.x, but only with respect to the simplest changes that occured between Python 2 and Python 3. However, this a step forward to Python 3 compatibility without breaking Python 2.6+ compatibility.

Fixing unicode issues

In Python 3, unicode and str strings have been replaced by str and bytes strings:

  • str is the text string type, supporting unicode characters natively
  • bytes is the binary string type.

As a consequence, Python 2 code involving strings may cause compatibility issues with Python 3. For example:

  • file I/O may return bytes instead of str in Python 3 (depending on the open mode): this can be solved by calling the decode method on the bytes object (this will work on both Python 2 str and Python 3 bytes objects)
  • in Python 3.0-3.2, the u’unicode text’ or u”unicode text” syntax is not allowed and will raise a SyntaxError: this can be solved by inserting the from __future__ import unicode_literals at the beginning of the script and by removing all the u string prefixes
  • in Python 3 isinstance(text, basestring) can be replaced by is_text_string(text) (function of the guidata.py3compat module)
  • in Python 3 isinstance(text, unicode) can be replaced by is_unicode(text) (function of the guidata.py3compat module)
  • in Python 3 unicode(text) can be replaced by to_text_string(text) (function of the guidata.py3compat module)