| 1 | Style guide |
| 2 | =========== |
| 3 | |
| 4 | This document describes the main coding rules in use in the plat/al codebase. |
| 5 | |
| 6 | Python |
| 7 | ------ |
| 8 | |
| 9 | Plat/al mostly follows the :pep:8 rules and `Django's coding style`_. |
| 10 | |
| 11 | .. _Django's coding style: https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/ |
| 12 | |
| 13 | Mostly: |
| 14 | |
| 15 | - Lines are limited to 120 characters |
| 16 | - Indent with 4 spaces |
| 17 | |
| 18 | Annotations |
| 19 | """"""""""" |
| 20 | |
| 21 | - Use ``TODO`` and ``FIXME`` annotations with the name of the assignee:: |
| 22 | |
| 23 | # TODO(x2006barrois): make the spam more explicit |
| 24 | # FIXME(x2008gelineau): this may fry the eggs |
| 25 | |
| 26 | - Use ``XXX`` for things we can't improve, such as limitations in Python:: |
| 27 | |
| 28 | # XXX: OrderedDict does not exist before Python 2.7 |
| 29 | |
| 30 | |
| 31 | Imports |
| 32 | """"""" |
| 33 | |
| 34 | **Do not use** ``import *``. |
| 35 | |
| 36 | When importing from the same package, use relative imports. |
| 37 | Otherwise, use absolute imports: |
| 38 | |
| 39 | .. code-block:: python |
| 40 | |
| 41 | # xnet/foo/bar.py |
| 42 | |
| 43 | # Absolute import of xnet.blih |
| 44 | from xnet import blih |
| 45 | |
| 46 | # Relative import of xnet.foo.baz |
| 47 | from . import baz |
| 48 | |
| 49 | |
| 50 | Imports should be ordered from most general to most local: |
| 51 | |
| 52 | #. Standard lib imports |
| 53 | #. Django imports |
| 54 | #. Third party lib imports |
| 55 | #. Plat/al imports |
| 56 | #. Current app imports |
| 57 | |
| 58 | |
| 59 | Exceptions |
| 60 | """""""""" |
| 61 | |
| 62 | Exceptions are quite powerful, but should be used properly. |
| 63 | |
| 64 | Each module defining custom exceptions should define a base class for its |
| 65 | exceptions; other exceptions from the module must then inherit from that base |
| 66 | exception. This makes it much easier to catch module-specific exceptions: |
| 67 | |
| 68 | |
| 69 | .. code-block:: python |
| 70 | |
| 71 | # blah/foo.py |
| 72 | |
| 73 | class FooError(Exception): |
| 74 | """Base class for exceptions from blah.foo.""" |
| 75 | |
| 76 | class SpecificException(FooError): |
| 77 | """A specific exception.""" |
| 78 | |
| 79 | def some_fun(): |
| 80 | """Demo function for exception catching.""" |
| 81 | try: |
| 82 | do_something() |
| 83 | except SpecificException as e: |
| 84 | handle_specific_exception(e) |
| 85 | |
| 86 | # module bar.py |
| 87 | |
| 88 | def other_fun(): |
| 89 | try: |
| 90 | do_something() |
| 91 | except foo.FooError as e: |
| 92 | handle_generic_foo_exception(e) |
| 93 | |
| 94 | |
| 95 | Only catch the errors that you expect. Let the other errors propagate. Do not catch an exception then raise another one, as this hides the true cause of the error. |
| 96 | |
| 97 | Avoid generic excepts, or worse, naked excepts: |
| 98 | |
| 99 | - ``except Exception:`` will catch import or syntax exceptions |
| 100 | - ``except:`` and ``except BaseException:`` will catch all exceptions, including ``KeyboardInterrupt``, thus preventing ``^C``. |