diff options
author | 2009-12-09 16:26:43 +0000 | |
---|---|---|
committer | 2009-12-09 16:26:43 +0000 | |
commit | 396e6ca7ef4a61a9b93b990be11fcddf3559abb9 (patch) | |
tree | 3f3b60a7dc86d5b14db480029708f69da636718c /DEVELOPING | |
parent | Fix bug with epkginfo not displaying keywords correctly for highest visible v... (diff) | |
download | gentoolkit-396e6ca7ef4a61a9b93b990be11fcddf3559abb9.tar.gz gentoolkit-396e6ca7ef4a61a9b93b990be11fcddf3559abb9.tar.bz2 gentoolkit-396e6ca7ef4a61a9b93b990be11fcddf3559abb9.zip |
Add DEVELOPING file, based upon the file from portage
svn path=/trunk/gentoolkit/; revision=705
Diffstat (limited to 'DEVELOPING')
-rw-r--r-- | DEVELOPING | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/DEVELOPING b/DEVELOPING new file mode 100644 index 0000000..ea5f457 --- /dev/null +++ b/DEVELOPING @@ -0,0 +1,166 @@ +Code Guidelines +--------------- +These are a few guidelines to stick to when modifying or adding code to +Gentoolkit. + +First, read Python's PEP 8: http://www.python.org/dev/peps/pep-0008/ +Next, read Portage's DEVELOPING file. +Next, read Portage's Docstring specs: + http://www.gentoo.org/proj/en/portage/doc/policies/docstring-spec.xml + +(Portage DEVELOPING overrides PEP 8, so we use tabs instead of spaces.) + +Here are a few clarifications and changes to the above: + +Line-Wrapping +------------- +- Do NOT space out to an opening paren (etc). Different tab settings make this + difficult to read: + + BAD: + foo = get_foo(keyword1=default, + keyword2=default, + ...) + + OK: + foo = get_foo(keyword1=default, keyword2=default, keyword3=default, + keyword4=default, ...) + + OK: + foo = get_foo( + keyword1=default, + keyword2=default, + ... + ) + +- Max. line length is strictly 80 characters with a tab length of 4 characters. +- "The preferred way of wrapping long lines is by using Python's implied line + continuation inside parentheses, brackets and braces" rather than using '\' + (PEP 8). + Even better than that is pre-defining a snippet of the long line in a + variable. So: + + BAD: (too long) + self._descriptions = [e.text for e in self._xml_tree.findall("longdescription")] + + OK: + self._descriptions = \ + [e.text for e in self._xml_tree.findall("longdescription")] + + BETTER: + self._descriptions = [ + e.text for e in self._xml_tree.findall("longdescription") + ] + + BEST: (easiest to read and test) + long_descriptions = self._xml_tree.findall("longdescription") + self._descriptions = [e.text for e in long_descriptions] + +Imports: +-------- +Same as PEP 8 and Portage's DEVELOPING spec, but make sure to split python +default libraries, Gentoo system libraries (like portage) and lastly local +modules (gentoolkit), so: + + GOOD: + import os + import re + + import portage + from portage.versions import catpkgsplit, pkgcmp + + from gentoolkit import CONFIG + from gentoolkit import pprinter as pp + ... + +Exceptions: +----------- +Always raise exceptions and catch them at the last possible moment. This allows +API consumers to catch them and decide what to do with them. Do not print an +error to stderr from inside a consumable. Never "print" an error string, always +write it to stderr. + +Lastly, if an error is fatal (should be raised all the way up), try to make +sure it is an errors.Gentoolkit* error. That allows API consumers to catch all +fatal errors with: except 'gentoolkit.errors.GentoolkitException'. See +bin/equery to see how we catch those exceptions before they hit the user. + + BAD: + try: + result = tree.aux_get(str(self.cpv), [var]) + except KeyError: + sys.stderr.write("aux_get returned unexpected results") + + BETTER: + # This line raises KeyError if self.cpv not found: + result = tree.aux_get(str(self.cpv), [var]) + + BEST: + try: + result = tree.aux_get(str(self.cpv), [var]) + except KeyError: + err = "aux_get returned unexpected results" + raise errors.GentoolkitFatalError(err) + +Docstrings: +----------- +Follow this example for any complicated function or method. Don't worry about +docstring for private methods (like _foo) or methods like __this__. It's +definitely OK to write docstrings for these methods as well if there's +something tricky about them, though. + + def graph_reverse_depends(...): + # A ONE-LINE sentence describing the function in simplest terms: + """Graph direct reverse dependencies for self. + + # An optional second paragraph to give more detailed information. + # Sometimes an 'Example usage' here can be worth more than a lengthy + # description. Examples should be an ACTUAL interpreter session: + Example usage: + >>> from gentoolkit.dependencies import Dependencies + >>> ffmpeg = Dependencies('media-video/ffmpeg-0.5_p20373') + >>> # I only care about installed packages that depend on me: + ... from gentoolkit.helpers import get_installed_cpvs + >>> # I want to pass in a sorted list. We can pass strings or + ... # Package or Atom types, so I'll use Package to sort: + ... from gentoolkit.package import Package + >>> installed = sorted(Package(x) for x in get_installed_cpvs()) + >>> deptree = ffmpeg.graph_reverse_depends( + ... only_direct=False, # Include indirect revdeps + ... pkgset=installed) # from installed pkgset + >>> len(deptree) + 44 + + # Lastly use epydoc's special fields to document further. + # See: http://epydoc.sourceforge.net/fields.html + @type pkgset: iterable + @keyword pkgset: sorted pkg cpv strings or anything sublassing + L{gentoolkit.cpv.CPV} to use for calculate our revdep graph. + @type max_depth: int + @keyword max_depth: Maximum depth to recurse if only_direct=False. + -1 means no maximum depth; + 0 is the same as only_direct=True; + >0 means recurse only this many times; + @type only_direct: bool + @keyword only_direct: to recurse or not to recurse + @type printer_fn: callable + @keyword printer_fn: If None, no effect. If set, it will be applied to + each L{gentoolkit.atom.Atom} object as it is added to the results. + @rtype: list + @return: L{gentoolkit.dependencies.Dependencies} objects + """ + +Other concerns: +--------------- +- Choose names which are full, clear words (not necessary in small loops). +- It is NEVER necessary to prefix names with "my". Consider: + class FooThinger(object): + def __init__(self, foo): + self.myfoo = foo + + Just use FooThinger.foo or FooThinger.orig_foo; "my"foo tells us nothing. +- Comment and document in simple, unambiguous and non-repetitive English. +- When adding a TODO, FIXME or XXX comment, please date it and add your name so + that other devs know who to ask about the proposed change. +- Be careful of spelling. DO spell check your source code and be professional + when writing comments. |