Python Coding Guidelines


Run Black on every commit.

Import Order

Run import sorter on every commit.

Sorter should work in the following way:

  1. group imports in order by

    • standard library

    • 3rd party libraries

    • your own libraries

    • app local libraries

    • package local imports

    Helps you to skim quickly through what is imported.

  2. sort those alphabetically

    This builds upon 1 and usually gives a nice shape to the import lines.

  3. always import a single object

    Makes diffs easier to read (even if you have –word-diff) and eliminates some merge conflicts.

  4. Pragma markup to except an import from the sorting order. This is necessary because while module imports SHOULD not effect global state of the process in any way other than adding the module into the local scope of the import. They MAY have side effects either by defect or by necessity [1].


import functools
from functools import partial
import os
import os.path

from twisted.internet.defer import Deferred
from twisted.internet.defer import inlineCallbacks
from twisted.internet import reactor

from mylib import foo

from myapp import session

from .model import BussinessThing

The last three here may be in single group since there is so few in each block but as the blocks grow it may be preferable to separate like this. Use judgement.

Wild Card Import Considered Harmful

from foo import *

It is only marginally useful in some niche use cases.

It risks identifier shadowing. Consider this:

import foo
import bar
assert foo.A is not bar.A

from foo import A
from bar import A
assert A is bar.A and A is not foo.A

It is generally better to just disallow by linter policy.

Stop Writing Custom Logging Initializers

logging has fairly sane declarative config which you need to just load via dictConfig and you are done.

In the code you will get loggers via logging.getLogger(__name__). There is mostly no need to write wrappers around the getLogger.

It is way too common to see code bases which turn these one-liners into tens to hundreds of lines of code with no added benefit. Even worse, these custom initializers usually bring more dependencies which complicate or even entirely prevent the use of REPL to run simple tests within the runtime of the project.