How it works

To install the atelier package you must say:

$ pip install atelier

Installing atelier also installs the invoke package, which installs the command inv into your PATH. When you run inv (or its alias invoke) from a project directory or a subdirectory, then invoke reads the in the root directory of your project.


The inv command is a kind of make tool that is configured using file.

A configuration file for the invoke package. It must define a variable named ns, which must be an instance of an invoke namespace.

To activate atelier for your project, you create a file in your project’s root directory, and define the variable ns by calling atelier.invlib.setup_from_tasks().

Your should have at least the following two lines:

from atelier.invlib import setup_from_tasks
ns = setup_from_tasks(globals())

You can specify project configuration settings directly in your project’s file. Example content:

from atelier.invlib import setup_from_tasks
ns = setup_from_tasks(globals(), "mypackage",

You can specify user-wide project configuration settings in a file named, which must be in your home directory.

You can also define system-wide default configuration files. See the Invoke documentation for more information.

When you have no file, Atelier will operate in single project mode: the causes on the fly creation of a single project descriptor.

The file


If you have more than one project, then you define the global projects list in a configuration file named ~/.atelier/, which contains something like:

add_project('/home/john/myprojects/second_project', 'p2')

where the first argument to add_project is the name of a directory which is expected to contain a

The optional second argument is a nickname for that project. If no nickname is specified, the nickname will be the leaf name of that directory.

It is allowed but not recommended to have several projects with a same nickname.

Your projects’ files

If a project has a file, then atelier uses it.


The file of a Python project can be as simple as this:

from setuptools import setup
setup(name='foo', version='1.0.0')

But for atelier there are two additional required conventions:

  • The file must define a name SETUP_INFO, which must be a dict containing the keyword arguments to be passed to the setup() function.

  • The file should actually call the setup() function only if invoked from a command line, i.e. only if __name__ == ‘__main__’.

So the above minimal file becomes:

from setuptools import setup
SETUP_INFO = dict(name='foo', version='1.0.0')
if __name__ == '__main__':

Atelier tries to verify these conditions and raises an exception if the doesn’t comply:

>>> from atelier.projects import get_setup_info
>>> from unipath import Path
>>> get_setup_info(Path('docs/p1'))
Traceback (most recent call last):
Exception: Oops, docs/p1/ called sys.exit().
Atelier requires the setup() call to be in a "if __name__ == '__main__':" condition.
>>> get_setup_info(Path('docs/p3'))
Traceback (most recent call last):
Exception: Oops, docs/p3/ doesn't define a name SETUP_INFO.
>>> d = get_setup_info(Path('docs/p2'))
>>> d == {'version': '1.0.0', 'name': 'foo'}
>>> d == dict(name="foo", version="1.0.0")

Project configuration settings

TODO: document them all.


‘root_dir’: root_dir, ‘build_dir_name’: ‘.build’, # e.g. ablog needs ‘_build’ ‘project_name’: str(, ‘locale_dir’: None, ‘help_texts_source’: None, ‘help_texts_module’: None, ‘tolerate_sphinx_warnings’: False, ‘cleanable_files’: [], ‘revision_control_system’: None, ‘apidoc_exclude_pathnames’: [], ‘editor_command’: os.environ.get(‘EDITOR’), ‘prep_command’: “”, ‘test_command’: “python -m unittest discover -s tests”, ‘demo_projects’: [], ‘demo_prep_command’: “ prep –noinput –traceback”, ‘coverage_command’: ‘which invoke prep test clean –batch bd’, ‘languages’: None, ‘blog_root’: root_dir.child(‘docs’), ‘long_date_format’: “%Y%m%d (%A, %d %B %Y)”, ‘sdist_dir’: root_dir.child(‘dist’), ‘pypi_dir’: root_dir.child(‘.pypi_cache’), ‘use_dirhtml’: False, ‘doc_trees’: [‘docs’], ‘intersphinx_urls’: {},

Defining shell aliases

Under Linux you can easily define abbreviations for certain commands which you use oftem. These are called shell aliases. There are several ways for defining them, we recommend to write them into your ~/.bash_aliases.


Conventional name for the file that holds your shell aliases. See Configuring your login sessions with dot files.

After editing your ~/.bash_aliases you must open a new terminal in order to see the changes.

The per_project command

Installing the atelier package will add the per_project script:


Usage : per_project [options] CMD …

Loop over all projects, executing the given shell command CMD in the root directory of each project.

Special case: When CMD starts with the word git, then skip all projects which don’t have their revision_control_system set to 'git'.

The projects are processed in the order defined in your ~/.atelier/ file.


  • --list or -l : print a list of all projects to stdout. Does not run any command.

  • --start PRJNAME : start at project PRJNAME. This is useful e.g. when you have been running the test suite on all your projects and one project failed. After repairing that failure you want to continue the started loop without repeating previous test suites again.

  • --after PRJNAME : start after project PRJNAME (like –start, but without the named project).

  • --until PRJNAME : stop after project PRJNAME.

  • --voice : Speak the result through speakers when terminated.


We recommend to define an alias pp for per_project in your ~/.bash_aliases:

alias pp='per_project'

Note that the first argument which is not an option (i.e. not starting with a -) marks the beginning of the shell command to be executed. Any - after that is considered a part of the command. So the following two lines are not equivalent:

$ pp inv --help
$ pp --help inv

Usage examples:

$ pp -l
$ pp inv test
$ pp git st

See the Project management page of the Lino project for more usage examples.

See also