Code Guidelines --------------- A few code guidelines to try to stick to, please comment if none of these make sense, they are pretty basic and mostly apply to old code. However for people who are looking at current code, they make take up bad habits that exist in the current codebase. Python Version -------------- Python 2.7 is the minimum supported version as it eases 3.x compatibility. All exception handling should use Python 3 'except' syntax, and the print function should be used instead of Python 2's print statement (use "from __future__ import print_function" everywhere). Dependencies ------------ Python and Bash should be the only hard dependencies. Any other dependencies, including external Python modules that are not included with Python itself, must be optionally enabled by run-time detection. Tabs ---- For legacy reasons, all leading whitespace should be tabs. All internal whitespace should be regular spaces. Set tab stop to 4 to calculate line width. Line-Wrapping ------------- Lines should typically not be longer than 80 characters; if they are an attempt should be made to wrap them. Move code to the line below and indent once (\t). errors.append(MalformedMetadata( errors.DESCRIPTION_TOO_LONG_ERROR % \ (length, max_desc_len), attr='DESCRIPTION.toolong') Do not do this: errors.append(MalformedMetadata( errors.DESCRIPTION_TOO_LONG_ERROR % \ (length, max_desc_len), attr='DESCRIPTION.toolong') The mixing of tabs and spaces means other developers can't read what you did. This is why the python peps state spaces over tabs; because with spaces the line wrapping is always clear (but you cannot convert spaces as easily as tabwidth). Comparisons ----------- if foo != None should be replaced with: if foo is not None: Is not does a reference comparison (address1 = address2 basically) and the == forces a by value compare (with __eq__()) Dict Lookups ------------ Try not to use has_key, you can use if foo in dict instead of if dict.has_key(foo) Also don't do stuff like: if foo in dict and dict[foo]: Generally you can do two things here, if you are messing with defaults.. dict.get(foo, some_default) will try to retrieve foo from dict, if there is a KeyError, will insert foo into dict with the value of some_default. This method is preferred in cases where you are messing with defaults: try: dict[foo] except KeyError: dict[foo] = default_value The get call is nicer (compact) and faster (try,except are slow). Exceptions ---------- Don't use the format raise Exception, "string" It will be removed in py3k. YES: raise KeyError("No key") NO: raise KeyError, "No key" Imports ------- Import things one per line YES: import os import time import sys NO: import os,sys,time When importing from a module, you may import more than 1 thing at a time. YES: from portage.module import foo, bar, baz Multiline imports are ok (for now :)) Try to group system and package imports separately. YES: import os import sys import time from portage.locks import lockfile from portage.versions import vercmp NO: import os import portage import portage.util import time import sys Try not to import large numbers of things into the namespace of a module. I realize this is done all over the place in current code but it really makes it a pain to do code reflection when the namespace is cluttered with identifiers from other modules. YES: from portage import output NO: from portage.output import bold, create_color_func, darkgreen, \ green, nocolor, red, turquoise, yellow The YES example imports the 'output' module into the current namespace. The negative here is having to use output.COLOR all over the place instead of just COLOR. However it means during introspection of the current namespace 'green','red', 'yellow', etc. will not show up. The NO example just imports a set of functions from the output module. It is somewhat annoying because the import line needs to be modified when functions are needed and often unused functions are left in the import line until someone comes along with a linter to clean up (does not happen often). Commits ------- Prefer small commits that change specific things to big commits that change a lot of unrelated things. This makes it easier to see what parts of the system have actually changed. It also makes it easier to cherry-pick and revert commits. Use your common sense! When you make a significant change, make sure to update RELEASE-NOTES for the to-be-released version. Very significant changes should be mentioned in NEWS as well. See the current entries to these files for examples of what constitutes significant. Commit messages --------------- Commit messages should be in the imperative mood with a capitalised header, optionally followed by a newline and a more detailed explanatory text. The headline should be capped at 70 characters, the detailed text at 72. Prefix the message with the component you touched if this makes sense. Postfix the message with the bug it fixes, if it does. Feel free to use the following notes (if applicable): Signed-off-by: Wrote (a substantial portion of) the patch Reviewed-by: Reviewed the patch thoroughly Tested-by: Tested the patch thoroughly Acked-by: Approved the concept but did not read the patch in detail (typically used by the maintainer of a specific portion, or a lead) Suggested-by: Designed the implementation Requested-by: Reported the bug/made the feature request Example: " emerge: Fix --tree output (bug 555555) Make sure newlines appear where they are supposed to. Fix a bug with colourisation of --tree output when used in tandem with --verbose --pretend --ask. Signed-off-by: Foo Bar Reviewed-by: Fu Baz Reported-by: Qux Quux " For a more detailed explanation (and rationalisation) of these rules: Releases -------- First update the NEWS and RELEASE-NOTES files and commit. Second create a git tag for this release: git tag v2.2.8 Then create the tarball and run the tests: ./mkrelease.sh --changelog-rev v2.2.7 --tag --runtests 2.2.8 Make sure you have all supported python versions installed first (see PYTHON_SUPPORTED_VERSIONS in runtests). Version bump the ebuild and verify it can re-install itself: emerge portage emerge portage Publish the results (no going back now): - Push the new git tag - Upload the tarball - Commit the new ebuild version Close the bugs blocking the tracker bug for this release.