-Python code follows PEP8 [1] with regard to coding style and PEP257 [2] with
-regard to docstring style. Multi-line docstrings should have one short summary
-line, followed by a blank line and a series of paragraphs. The last paragraph
-should be followed by a line that closes the docstring (no blank line in
-between). Here's an example from lib/bup/helpers.py:
+.. -*-rst-*-
-def unlink(f):
- """Delete a file at path 'f' if it currently exists.
+C
+=
- Unlike os.unlink(), does not throw an exception if the file didn't already
- exist.
- """
- #code...
+The C implementations should follow the `kernel/git coding style
+<http://www.kernel.org/doc/Documentation/CodingStyle>`_.
+
+
+Python
+======
+
+Python code follows `PEP8 <http://www.python.org/dev/peps/pep-0008/>`_
+with regard to coding style and `PEP257
+<http://www.python.org/dev/peps/pep-0257/>`_ with regard to docstring
+style. Multi-line docstrings should have one short summary line,
+followed by a blank line and a series of paragraphs. The last
+paragraph should be followed by a line that closes the docstring (no
+blank line in between). Here's an example from
+``lib/bup/helpers.py``::
+
+ def unlink(f):
+ """Delete a file at path 'f' if it currently exists.
+
+ Unlike os.unlink(), does not throw an exception if the file didn't already
+ exist.
+ """
+ ...
Module-level docstrings follow exactly the same guidelines but without the
blank line between the summary and the details.
-The C implementations should follow the kernel/git coding style [3].
+Exception Handling
+------------------
+
+Avoid finally: blocks in favor of explict catches because a throw
+from a finally block will lose any pending exception. An explicit
+catch can chain it (see below).
+
+To behave similarly under Python 2 and 3, use add_ex_tb() to
+explicitly add stack traces to any exceptions that are going to be
+re-raised by anything other than a no-argument raise (otherwise the
+stack trace will be lost)::
+
+ try:
+ ...
+ except ... as ex:
+ add_ex_tb(ex)
+ pending_ex = ex
+ ...
+ raise pending_ex
+
+When an exception is thrown from an exception handler, the pending
+exception should be the `"context"
+<https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement>`_
+of the new exception, which can be accomplished (portably) via
+``pending_raise()``::
+
+ try:
+ ...
+ except ... as ex:
+ with pending_raise(ex):
+ clean_up()
+
+This should do roughly the same thing in Python 2 and Python 3,
+throwing any exception from ``clean_up()`` after adding ex as the
+``__context__`` if clean_up() throws, and throwing ``ex`` otherwise.
+
+If for some reason, you need more control, you can use
+``add_ex_ctx()`` directly::
+ try:
+ ...
+ except ... as ex:
+ add_ex_tb(ex)
+ try:
+ ...
+ except ... as ex2:
+ add_ex_tb(ex2)
+ raise add_ex_ctx(ex2, ex)
+ raise
-[1]:http://www.python.org/dev/peps/pep-0008/
-[2]:http://www.python.org/dev/peps/pep-0257/
-[3]:http://www.kernel.org/doc/Documentation/CodingStyle
+See the end of ``lib/bup/compat.py`` for a functional example, and all
+of this can be removed once we drop support for Python 2.