Changes between Version 26 and Version 27 of CodingStandards


Ignore:
Timestamp:
2013-12-19T01:32:50Z (11 years ago)
Author:
daira
Comment:

capitalize headings, minor cleanups

Legend:

Unmodified
Added
Removed
Modified
  • CodingStandards

    v26 v27  
    1 = coding standards =
     1= Coding standards =
    22
    33Here are some Python code style guidelines. We also include official Python guidelines by reference (see the section on "official Python standards" below). This document overrides the official standards whenever there is a conflict.
    44
    5 == basic standards ==
    6 === compatibility ===
     5== Basic standards ==
     6=== Compatibility ===
    77
    88Tahoe requires Python v2.6.6 or greater (although the current code only refuses to run on Python < 2.6). No effort should be made to offer compatibility with versions of Python older than 2.6.6. Effort should be made to work with every Python release from v2.6.6 to the most recent 2.x, inclusive.
    99
    10 === naming and layout ===
     10=== Naming and Layout ===
    1111
    1212 * Use {{{underscore_separated_names}}} for functions, {{{CamelCapNames}}} for classes, {{{alllowercasenames}}} for modules, and {{{ALL_CAPS_NAMES}}} for constants. Use all lower-case variable names (e.g. {{{variable_name}}} or {{{variablename}}}). Prepend a leading underscore to private names.
    1313 * Put parentheses around tuples if it helps make the code more readable, leave them off if not.
    1414
    15 === comments, idioms, miscellany, license, imports, docstrings, line widths ===
     15=== Comments, Idioms, Miscellany, License, Imports, Docstrings, Line widths ===
    1616
    1717Here is a useful header for starting new Python files:
     
    1919{{{
    2020"""
    21 optional doc string describing the module here
     21Optional doc string describing the module here.
    2222"""
    2323
     
    3939 * PEP 8 says: "If operators with different priorities are used, consider adding whitespace around the operators with the lowest priority(ies)." This is a good rule; note that it also applies to some non-obvious low-priority operators, like '{{{:}}}' for list slicing. (Example: {{{a[b-c : d]}}} good, {{{a[b - c:d]}}} bad. If a slice is from the start or to the end of the array, put the '{{{:}}}' immediately next to the bracket on that side.)
    4040
    41 === truths and falsehoods ===
     41=== Truths and Falsehoods ===
    4242
    4343 * Don't use the literals {{{True}}} or {{{False}}} in conditional expressions -- instead just write the expression which will evaluate to true or false. For example, write {{{if expr:}}} instead of {{{if expr == True:}}} and {{{if not expr:}}} instead of {{{if expr == False:}}}.
    4444 * Avoid relying on the fact that empty sequences, empty strings, empty dicts, {{{0}}}, and {{{None}}} are treated as false. Write {{{if len(items) == 0:}}}, {{{if thing is None:}}}, etc.
    4545
    46 == advanced idioms ==
     46== Idioms ==
    4747
     48=== Preconditions and Assertions ===
    4849
    49 
    50 === preconditions and assertions ===
    51 
    52 ==== basic preconditions and assertions ====
     50==== Basic preconditions and assertions ====
    5351
    5452Make sure you have {{{from allmydata.util.assertutil import _assert, precondition, postcondition}}} in your imports (as shown in the template above). Now design preconditions for your methods and functions, and assert them like this:
     
    7270}}} 
    7371
    74 The "error message" that will accompany a failed expression should be a statement of what is required for correct operation. Don't write something like "Spam isn't firm.", because that is ambiguous: the error could be that the spam is supposed to be firm and it isn't, or the error could be that spam isn't supposed to be firm and it is! The same ambiguity can apply to the sentence "Spam must be firm.".  It helps to use the words "required to" in your message, for example "Spam is required to be firm.".
     72The "error message" that will accompany a failed expression should be a statement of what is required for correct operation. Don't write something like "Spam isn't firm.", because that is ambiguous: the error could be that the spam is supposed to be firm and it isn't, or the error could be that spam isn't supposed to be firm and it is! It helps to use the words "required to" in your message, for example "Spam is required to be firm.".
    7573
    7674Assertions are not a substitute for proper error handling! An assertion, precondition or postcondition should only be used for cases that "cannot happen" unless the code is incorrect. They should not be used to check for invalid inputs; in that case, raise an exception instead.
    7775
    78 ==== avoid "bare assert" ====
     76==== Avoid "bare assert" ====
    7977
    8078Python's built-in {{{assert}}} statement, unlike {{{allmydata.util.assertutil._assert}}}, can be switched off by the {{{-O}}} option to {{{python}}} or the {{{PYTHONOPTIMIZE}}} environment variable. Although this might sound useful to reduce the overhead of assertions, in practice that overhead is negligable, and conditional assertions are more trouble than they're worth (partly because they create a configuration that is mostly untested). We are in the process of removing all bare asserts from the codebase (#1968).
    8179
    82 ==== class invariants ====
     80==== Class invariants ====
    8381
    8482If your class has internal state which is complicated enough that a bug in the class's implementation could lead to garbled internal state, then you should have a class invariant. A class invariant is a method like this (an actual example from !BlockWrangler, but truncated for space):
     
    10098Now you can put {{{assert self._assert_invariants()}}} everywhere in your class where the class ought to be in an internally consistent state. For example, at the beginning of every externally-callable method. This technique can be very valuable in developing a complex class -- it catches bugs early, it isolates bugs into specific code paths, and it clarifies the internal structure of the class so that other developers can hack on it without subtle misunderstandings.
    10199
    102 * we actually appear to only have one instance of this pattern in Tahoe at time of writing, in {{{allmydata.util.dictutil}}}. It has the disadvantage of cluttering up the logic with calls to {{{_assert_invariants}}}, and should probably be used sparingly. -- Daira
     100* We actually appear to only have one instance of this pattern in Tahoe at time of writing, in {{{allmydata.util.dictutil}}}. It has the disadvantage of cluttering up the logic with calls to {{{_assert_invariants}}}, and should probably be used sparingly. -- Daira
    103101
    104 ==== assertion policy ====
     102==== Assertion policy ====
    105103
    106104One axis of interest is how time-consuming the checks are. Many precondition
     
    134132
    135133
    136 === configuration ===
     134=== Configuration ===
    137135
    138 ==== minimizing configuration ====
     136==== Minimizing configuration ====
    139137
    140138 * Do not implement configuration files for modules or libraries -- code that is going to be used by other code. Only applications -- code that is going to be used by humans -- have configuration files. Modules and libraries get "configured" by the code that calls them, for example by passing arguments to their constructors.
     
    142140 * Design algorithms so that they have as few "voodoo constants" and "tweakable parameters" as possible.
    143141
    144 ==== how to implement configuration ====
     142==== How to implement configuration ====
    145143
    146144Whether in application code or in library code, never pass configuration values via a configuration object. Instead use Python parameters. For example -- here's another real-life example -- do not write
     
    170168
    171169
    172 == official Python standards ==
     170== Official Python Standards ==
    173171
    174172These are listed in decreasing order of priority, so if a point in one of the latter guidelines contradicts a point in one of the earlier ones, then go with the earlier. The Tahoe-LAFS-specific guidelines above override all else, of course.