From: Oscar H. <osc...@us...> - 2005-02-20 21:49:44
|
Update of /cvsroot/mnet/darcs-mnet/doc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16779 Modified Files: coding_standards.html Log Message: Got the version from mnetproject.org and added that to sf.net since sf.net was older. Index: coding_standards.html =================================================================== RCS file: /cvsroot/mnet/darcs-mnet/doc/coding_standards.html,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -d -r1.1.1.1 -r1.2 --- coding_standards.html 23 Jul 2004 19:14:52 -0000 1.1.1.1 +++ coding_standards.html 20 Feb 2005 21:49:35 -0000 1.2 @@ -6,9 +6,7 @@ <body> <h1>Mnet coding standards</h1> - <p>This document is current as of Mnet Mnet v0.7.</p> - <p>CVS revision: $Id$</p> - + <p>This document is current as of Mnet Mnet v0.7.</p> <p>Here are some Python code style guidelines. We also use some other official Python guidelines by reference (see <a href="#official_Python_standards">official Python standards</a> below). Our Mnet-specific standards override the official standards whenever there is a conflict.</p> @@ -19,20 +17,20 @@ <h2>basic standards</h2> <a name="compatibility" id="compatibility"></a> <h3>compatibility</h3> - <p>Mnet requires Python v2.3 or greater. No effort should be made to offer compatibility with versions of Python older than 2.3. Effort should be made to work with the most recent release of Python, and with every release between v2.3 and the most recent release.</p> + <p>Mnet requires Python v2.3 or greater. No effort should be made to offer compatibility with versions of Python older than 2.3. Effort should be made to work with the most recent release of Python, and with every release between v2.3 and the most recent release.</p> <a name="naming_and_layout" id="naming_and_layout"></a> <h3>naming and layout</h3> <p><ul> - <li>Use <i>readable_names</i> for functions, <i>shortnames</i> for variables and <i>CamelCapNames</i> for classes.</li> - <li>Always put trailing commas in lists, tuples and dicts. For example <code>(spam, eggs, bacon,)</code>, <em>not</em> <code>(spam, eggs, bacon)</code>. This makes it easier to edit (for example, to re-arrange the elements), it makes it more visually distinct from function invocation, and it prevents the error where you meant to write the 1-element tuple <code>(spam,)</code>, but you wrote <code>(spam)</code>, and the parser thinks you mean just <code>spam</code> (with precedence-forcing parenthesis).</li> - <li>Always put parenthesis around tuples. Write <code>(spam, eggs,) = fetch_breakfast()</code> instead of <code>spam, eggs, = fetch_breakfast()</code>.</li> + <li>Use <i>readable_names</i> for functions, <i>shortnames</i> for variables and <i>CamelCapNames</i> for classes.</li> + <li>Always put trailing commas in lists, tuples and dicts. For example <code>(spam, eggs, bacon,)</code>, <em>not</em> <code>(spam, eggs, bacon)</code>. This makes it easier to edit (for example, to re-arrange the elements), it makes it more visually distinct from function invocation, and it prevents the error where you meant to write the 1-element tuple <code>(spam,)</code>, but you wrote <code>(spam)</code>, and the parser thinks you mean just <code>spam</code> (with precedence-forcing parenthesis).</li> + <li>Always put parenthesis around tuples. Write <code>(spam, eggs,) = fetch_breakfast()</code> instead of <code>spam, eggs, = fetch_breakfast()</code>.</li> </ul> - <a name="misc" id="misc"></a> - <h3>comments, idioms, miscellany, license</h3> - <p>Here is a useful header for starting new Python files: -<pre> + <a name="misc" id="misc"></a> + <h3>comments, idioms, miscellany, license</h3> + <p>Here is a useful header for starting new Python files: + <pre> # Copyright (c) 2004 Bryce "Zooko" Wilcox-O'Hearn # mailto:zo...@zo... # http://mnetproject.org/ @@ -47,9 +45,6 @@ XXX doc string describing the module here """ -__version__ = "$Revision$" -# $Source$ - # XXX import Python Standard Library modules here from pyutil.assertutil import _assert, precondition, postcondition @@ -60,53 +55,47 @@ # XXX import from other libraries, with a blank line between each library # XXX your code here -</pre> -</p> + </pre> + </p> - <ul> - <li>Files should begin with a copyright notice, a docstring about that module, then a __version__ var and CVS source comment. It must be in that order for epydoc to find the docstring.</li> - <li>You can use any suitable free software license you want. We recommend something like this one. (Actually, it would be nice if there were a shorter version of this license.)</li> - </ul> + <ul> + <li>Files should begin with a copyright notice then a docstring about that module. It must be in that order for epydoc to find the docstring.</li> + <li>You can use any Free Software license that you want. We recommend this one. If you don't want a permissive license (like this one) then we recommend either the GNU LGPL or the GNU GPL. If you don't want to use a permissive license, nor the GNU LGPL, nor the GNU GPL, then we want to know why not.</li> + </ul> - <a name="truths_and_falsehoods" id="truths_and_falsehoods"></a> - <h3>truths and falsehoods</h3> - <ul> - <li>Always use <code>True</code> or <code>False</code> if that is what you mean -- never write a literal <code>0</code>, <code>1</code>, or <code>None</code> to indicate a boolean value.</li> - <li>Never use the literals <code>True</code> or <code>False</code> in conditional expressions -- instead just write the expression which will evaluate to true or false. For example, write <code>if expr:</code> instead of <code>if expr == True:</code> and <code>if not expr:</code> instead of <code>if expr == False:</code>."</li> - <li>Use the fact that empty sequences, empty strings, empty dicts, and None all evaluate to false. Write <code>if not items:</code> instead of <code>if len(items) == 0:</code>.</li> - </ul> + <a name="truths_and_falsehoods" id="truths_and_falsehoods"></a> + <h3>truths and falsehoods</h3> + <ul> + <li>Always use <code>True</code> or <code>False</code> if that is what you mean -- never write a literal <code>0</code>, <code>1</code>, or <code>None</code> to indicate a boolean value.</li> + <li>Never use the literals <code>True</code> or <code>False</code> in conditional expressions -- instead just write the expression which will evaluate to true or false. For example, write <code>if expr:</code> instead of <code>if expr == True:</code> and <code>if not expr:</code> instead of <code>if expr == False:</code>."</li> + <li>Use the fact that empty sequences, empty strings, empty dicts, and None all evaluate to false. Write <code>if not items:</code> instead of <code>if len(items) == 0:</code>.</li> + </ul> - <a name="modules" id="modules"></a> - <h3>modules</h3> - <ul> - <li>Put imports from the same library on a single line e.g.: <code>from pyutil import dictutil, strutil, randutil</code>. This over-rides PEP 8.</li> - <li>Import modules rather than classes, functions, or other contents of a module (especially not variables). For example, import BlockWrangler with "import BlockWrangler" (the module) and then reference the BlockWrangler class with "BlockWrangler.BlockWrangler". - <ul> - <li>exception 1: ubiquitous functions which are really "part of the language" more than part of the application such as humanreadable.hr and debugprint.debugprint can be imported directly for terseness.</li> - <li>exception 2: if it looks a <em>lot</em> better to you, for readability, to import the contents of a module, then go ahead and make an exception to this rule, but still do not do "from Thingie import *".</li> - </ul> - </li> - <li>To import other modules from the same package do a simple <code>import module</code> instead of a <code>from package import module</code>, e.g. inside pyutil.humanreadable we write <code>import dictutil</code> instead of <code>from pyutil import dictutil</code>.</li> - </ul> - - <a name="advanced_idioms" id="advanced_idioms"></a> - <h2>advanced idioms</h2> + <a name="modules" id="modules"></a> + <h3>modules</h3> + <ul> + <li>Put imports from the same library on a single line e.g.: <code>from pyutil import dictutil, strutil, randutil</code>. This over-rides PEP 8.</li> + <li>To import other modules from the same package do a simple <code>import module</code> instead of a <code>from package import module</code>, e.g. inside pyutil.humanreadable we write <code>import dictutil</code> instead of <code>from pyutil import dictutil</code>.</li> + </ul> + + <a name="advanced_idioms" id="advanced_idioms"></a> + <h2>advanced idioms</h2> - <a name="preconditions_and_assertions" id="preconditions_and_assertions"></a> - <h3>preconditions and assertions</h3> + <a name="preconditions_and_assertions" id="preconditions_and_assertions"></a> + <h3>preconditions and assertions</h3> - <a name="basic_preconditions_and_assertions" id="basic_preconditions_and_assertions"></a> - <h4>basic preconditions and assertions</h4> - <p>Make sure you have <code>from pyutil.assertutil import _assert, precondition, postcondition</code> in your imports (as shown in the template above). Now design preconditions for your methods and functions, and assert them like this: -<pre> + <a name="basic_preconditions_and_assertions" id="basic_preconditions_and_assertions"></a> + <h4>basic preconditions and assertions</h4> + <p>Make sure you have <code>from pyutil.assertutil import _assert, precondition, postcondition</code> in your imports (as shown in the template above). Now design preconditions for your methods and functions, and assert them like this: + <pre> def oaep(m, emLen, p=""): precondition(emLen >= (2 * SIZE_OF_UNIQS) + 1, "emLen is required to be big enough.", emLen=emLen, SIZE_OF_UNIQS=SIZE_OF_UNIQS) ... -</pre> - </p> - <p>Notice how you pass in any values that ought to be printed out in the error message if the assertion fails -- in the example, we pass the values <code>emLen</code> and <code>SIZE_OF_UNIQS</code>. You can pass these as normal args or keyword args. If you use keyword args then the name of the argument will also appear in the error message, which can be helpful. For example, if the assertion above fails, then a debug message will appear at the end of the stack trace, like this: -<i> -<pre> + </pre> + </p> + <p>Notice how you pass in any values that ought to be printed out in the error message if the assertion fails -- in the example, we pass the values <code>emLen</code> and <code>SIZE_OF_UNIQS</code>. You can pass these as normal args or keyword args. If you use keyword args then the name of the argument will also appear in the error message, which can be helpful. For example, if the assertion above fails, then a debug message will appear at the end of the stack trace, like this: + <i> + <pre> >>> oaep("some secret thingie", 20) Traceback (most recent call last): File "<stdin>", line 1, in ? @@ -114,15 +103,15 @@ File "/home/zooko/playground/pyutil_new/pyutil/assertutil.py", line 47, in precondition raise preconditionfailureexception AssertionError: precondition: emLen is required to be big enough. -- emLen: 20 :: <type 'int'>, 'SIZE_OF_UNIQS': 20 :: <type 'int'> -</pre> -</i> -</p> - <p>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! A good practice is to always use the words "required to" in your message, for example "Spam is required to be firm.".</p> + </pre> + </i> + </p> + <p>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! A good practice is to always use the words "required to" in your message, for example "Spam is required to be firm.".</p> - <a name="class_invariants" id="class_invariants"></a> - <h4>class invariants</h4> - <p>If your class has internal state which is complicated enough that a bug in the class's implementation could lead to garbled internal state which could in turn lead to misbehavior, then you should have a class invariant. A class invariant is a method like this (an actual example from BlockWrangler, but truncated for space):</p> -<pre> + <a name="class_invariants" id="class_invariants"></a> + <h4>class invariants</h4> + <p>If your class has internal state which is complicated enough that a bug in the class's implementation could lead to garbled internal state which could in turn lead to misbehavior, then you should have a class invariant. A class invariant is a method like this (an actual example from BlockWrangler, but truncated for space):</p> + <pre> def _assert_consistency(self): # All of the keys in all of these dicts must be ids. for d in (self.bId2chunkobj, self.bId2peers, self.Idsofwantedblocks, self.Idsoflocatedblocks,): @@ -134,29 +123,29 @@ # must *not* appear in bId2peers[blockId]. for ((peer, blockId,), claim,) in self.peerclaimedblock.items(): _assert((claim == 1) == (peer in self.bId2peers.get(blockId, ())), "The blockId must appear in bId2peers if and only if the peer has claimed the block.", claim=claim, peer=peer, bId2peersentry=self.bId2peers.get(blockId, ())) -</pre> - <p>Now you can put <cite>assert self._assert_consistency()</cite> everywhere in your class where the class <em>ought</em> 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 while isolating them into specific code paths and it disambiguates the internal structure of the class so that other developers can hack on it without subtle misunderstandings.</p> + </pre> + <p>Now you can put <cite>assert self._assert_consistency()</cite> everywhere in your class where the class <em>ought</em> 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 while isolating them into specific code paths and it disambiguates the internal structure of the class so that other developers can hack on it without subtle misunderstandings.</p> - <a name="list_comprehensions" id="list_comprehensions"></a> - <h4>list comprehensions</h4> - <p>If you are writing code to generate a list, consider using Python's <cite>list comprehension</cite> syntax. Consider writing <code>resultlist = [x for x in inputlist if x > 3]</code> instead of <pre> + <a name="list_comprehensions" id="list_comprehensions"></a> + <h4>list comprehensions</h4> + <p>If you are writing code to generate a list, consider using Python's <cite>list comprehension</cite> syntax. Consider writing <code>resultlist = [x for x in inputlist if x > 3]</code> instead of <pre> resultlist = [] for x in inputlist: if x > 3: resultlist.append(x) -</pre>.</p> + </pre>.</p> - <a name="configuration" id="configuration"></a> - <h2>configuration</h2> - <h3>minimizing configuration</h3> - <ul> - <li>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.</li> - <li>If there are constant values which end-users do not need to modify, then do not make them configurable, but put them in all-caps variables at the beginning of the Python file in which they are used.</li> - <li>Design your algorithms so that they have as few "voodoo constants" and "tweakable parameters" as possible. If you added a few of those parameters then you would have a combinatorial explosion of possibilities. If that happened, then (a) the code would never get tested in all its possible configurations, and (b) nobody would be able to understand how the algorithm behaves in <em>general</em>. The end result would be that users run algorithms that have never been tested and that nobody understands. In addition, this is an indicator that the basic algorithm ought to be replaced. If you find yourself needing to add more and more special cases to handle failures of the basic algorithm, this might indicate that the basic algorithm ought to be replaced with one that doesn't have so many edge cases.</li> - </ul> + <a name="configuration" id="configuration"></a> + <h2>configuration</h2> + <h3>minimizing configuration</h3> + <ul> + <li>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.</li> + <li>If there are constant values which end-users do not need to modify, then do not make them configurable, but put them in all-caps variables at the beginning of the Python file in which they are used.</li> + <li>Design your algorithms so that they have as few "voodoo constants" and "tweakable parameters" as possible. If you added a few of those parameters then you would have a combinatorial explosion of possibilities. If that happened, then (a) the code would never get tested in all its possible configurations, and (b) nobody would be able to understand how the algorithm behaves in <em>general</em>. The end result would be that users run algorithms that have never been tested and that nobody understands. In addition, this is an indicator that the basic algorithm ought to be replaced. If you find yourself needing to add more and more special cases to handle failures of the basic algorithm, this might indicate that the basic algorithm ought to be replaced with one that doesn't have so many edge cases.</li> + </ul> - <h3>how to implement configuration</h3> - <p>Whether in application code or in library code, never pass configuration values via a "conf dict". Instead use Python parameters. For example, do not write <pre> + <h3>how to implement configuration</h3> + <p>Whether in application code or in library code, never pass configuration values via a "conf dict". Instead use Python parameters. For example, do not write <pre> class BlockStore: def __init__(self, confdict={}, recoverdb=True, name='*unnamed*'): if confdict.has_key('MAX_MEGABYTES'): @@ -168,7 +157,7 @@ self.backendtype = confdict.get("BACKEND", "flat").lower() blockstore = BlockStore(confdict) -</pre>, but instead <pre> + </pre>, but instead <pre> class BlockStore: def __init__(self, maxspace=None, path="", maintainertype="rnd", backendtype="flat", recoverdb=True, name='*unnamed*'): self.basepath = os.path.abspath(path) @@ -179,29 +168,29 @@ if maxspace is not None: maxspace = int(maxspace) * 2**20 blockstore = BlockStore(maxspace, confdict.get('PATH', ""), confdict.get('MAINTAINER', 'rnd').lower(), confdict.get('BACKEND', 'flat').lower()) -</pre>.</p> + </pre>.</p> - <a name="official_Python_standards" id="official_Python_standards"></a> - <h2>official Python standards</h2> - <p>These 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 Mnet-specific guidelines above override all else, of course.</p> + <a name="official_Python_standards" id="official_Python_standards"></a> + <h2>official Python standards</h2> + <p>These 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 Mnet-specific guidelines above override all else, of course.</p> - <a name="PEP_290" id="PEP_290"></a> - <h3>PEP 290</h3> - <p><a href="http://www.python.org/peps/pep-0290.html">PEP 290: Code Migration and Modernization</a></p> + <a name="PEP_290" id="PEP_290"></a> + <h3>PEP 290</h3> + <p><a href="http://www.python.org/peps/pep-0290.html">PEP 290: Code Migration and Modernization</a></p> - <a name="PEP_8" id="PEP_8"></a> - <h3>PEP 8</h3> - <p><a href="http://www.python.org/peps/pep-0008.html">PEP 8: Style Guide for Python Code</a></p> - - <a name="PEP_257" id="PEP_257"></a> - <h3>PEP 257</h3> - <p><a href="http://www.python.org/peps/pep-0257.html">PEP 257: Docstring Conventions</a></p> - - <hr> - <address><a href="mailto:zo...@zo...">Zooko</a></address> -<!-- Created: Sun Feb 2 17:18:44 EST 2003 --> -<!-- hhmts start --> -Last modified: Thu May 6 12:40:24 EDT 2004 + <a name="PEP_8" id="PEP_8"></a> + <h3>PEP 8</h3> + <p><a href="http://www.python.org/peps/pep-0008.html">PEP 8: Style Guide for Python Code</a></p> + + <a name="PEP_257" id="PEP_257"></a> + <h3>PEP 257</h3> + <p><a href="http://www.python.org/peps/pep-0257.html">PEP 257: Docstring Conventions</a></p> + + <hr> + <address><a href="mailto:zo...@zo...">Zooko</a></address> + <!-- Created: Sun Feb 2 17:18:44 EST 2003 --> + <!-- hhmts start --> +Last modified: Sat Aug 7 12:29:16 ADT 2004 <!-- hhmts end --> </body> </html> |