Python coding template including ENV environment variable configuration
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Example Python project in a package using modules, tests, logging and configurations

This is a template for a Python 3.4+ project including:

  • module structure with a and a tests/ folder
  • unit test with test environment (via environment variable) allowing configuration via a function call
  • main file with argparse template for command line arguments
  • config module with inherited configurations so you can easily add your own
  • logging configured with ISO-8601 date (parseable by dateutil.parser), process number, file and line number


$ python develop  # install locally, it symlinks back to this folder
$ (python install)  # probably you *don't want to do this* as this project is useless by itself (once you've customised it, maybe this is what you want to do...)


Python coding template including ENV environment variable configuration::

$ python --env=dev
$ CONFIG=dev python 

Using --help will show the default arguments and all your options:

$ python --help
usage: [-h] [--env ENV]

Project description for this prototype...

optional arguments:
-h, --help  show this help message and exit
--env ENV   optional configuration argument (default: dev)


  • You probably want to edit logger = logging.getLogger(LOGGER_NAME) in to use your own name (see how it is used in
  • In edit at least ConfDev (the default configuration) so it has a useful basic configuration for your problem
  • Add some tests in tests/

Overriding the configuration

I've built and used a variety of configuration systems over the years, this is my 'best guess' as to one that works for web microservices (I tend to use Flask), console scripts (e.g. for local usage and Docker) and hacky idea testing.

As it stands if you don't provide any arguments, the Conf will use whatever's coded in its class (see

$ python 
2015-05-20 16:31:11.625 p16016 {} INFO - These are our args: Namespace(a_parameter=None, env='dev')
2015-05-20 16:31:11.625 p16016 {} INFO - This is our configuration: dev
2015-05-20 16:31:11.625 p16016 {} INFO - This is an example log message, logging is configured once config.get() has been called
2015-05-20 16:31:11.626 p16016 {} INFO - The value of a_parameter=42

If you pass in an override parameter, that'll be used in preference:

$ python --a_parameter=1
2015-05-20 16:32:46.517 p16038 {} INFO - These are our args: Namespace(a_parameter=1, env='dev')
2015-05-20 16:32:46.517 p16038 {} INFO - This is our configuration: dev
2015-05-20 16:32:46.517 p16038 {} INFO - This is an example log message, logging is configured once config.get() has been called
2015-05-20 16:32:46.517 p16038 {} INFO - The value of a_parameter=1

Bare in mind that this assumes that None (i.e. not provided) signifies that the parameter isn't being overridden, this might not be the case in your application.

NOTE this override mechanism might be overkill for your needs! Feel free to strip out the overrides parameter to simplify everything! Alternatively you might want to pick-up an environment variable for overrides instead of passing them in at the command line.

Further reading


Use py.test (or nosetests if you're old-skool) to run tests, remember that you can see stdout if you do py.test -s which'll include any logging messages.

Some notes:

  • for unit testing it is useful to add coverage with:
  • pip is useful for installing, use pip freeze > requirements.txt to free versions of the libraries you're using
  • when logging prefer to use %r or %s in the message rather than more specific types (e.g. %d) as e.g. a %d will raise another exception if None is received but %r can handle the None and a decimal number
  • you might want to add a utilities folder for command-line utilities, alongside the tests
  • is a package-generator, that might give you more ideas (and, frnakly, maybe it is a whole pile better - I'm open to input!) thx @zemanel


  • in we could auto-discover the available configurations by looking at who inherits from ConfBasic rather than building the list manually
  • it would be nice to check that all configurations have a unique name and none are in conflict