Installation is easy:

pip install atelier

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.

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 that 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.

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

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 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_project_from_path
>>> from pathlib import Path
>>> prj = get_project_from_path(Path('docs/p1'))
>>> prj.load_setup_file()  
Traceback (most recent call last):
Exception: Oops, called sys.exit().
Atelier requires the setup() call to be in a "if __name__ == '__main__':" condition.
>>> prj = get_project_from_path(Path('docs/p3'))
>>> prj.load_setup_file()  
Traceback (most recent call last):
Exception: Oops, doesn't define a name SETUP_INFO.
>>> prj = get_project_from_path(Path('docs/p2'))
>>> print(prj.SETUP_INFO)
>>> prj.load_setup_file()  
>>> prj.SETUP_INFO == {'version': '1.0.0', 'name': 'foo'}
>>> prj.SETUP_INFO == dict(name="foo", version="1.0.0")

Defining shell aliases

Under Linux you can easily define abbreviations for certain commands which you use often. 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 command to your PATH.



$ per_project [options] CMD ...

Run the given shell command CMD in the root directory of each project.

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

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


--showlist, -l

Print a list of all projects to stdout. Does not run any command.

--dirty, -d
  • Print or process only projects that have a dirty git status. i.e. only those which have revision_control_system set to 'git' and which have local modifications.


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.


Start after project PRJNAME (like --start, but without the named project).

--until PRJNAME

Stop after project PRJNAME.


Loop over the projects in reverse order.


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 that 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 shell command. So the following two lines are not equivalent:

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

Usage examples:

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

See the Demo projects included with the Developer Guide page of the Lino project for more usage examples.

>>> from atelier.sheller import Sheller
>>> shell = Sheller()
>>> shell('per_project --help')
usage: per_project [-h] [-v] [--start START] [-a AFTER] [-u UNTIL] [--showlist] [-d] [-r] ...

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

positional arguments:
  cmd                   The command to run on every project.

  -h, --help            show this help message and exit
  -v, --voice           Speak the result through speakers when terminated. (default: False)
  --start START, -s START
                        Start from that project, skip those before. (default: -)
  -a AFTER, --after AFTER
                        Start after that project, skip those before. (default: -)
  -u UNTIL, --until UNTIL
                        Only until that project, skip those after. (default: -)
  --showlist, -l        Show list of projects. (default: False)
  -d, --dirty           Process only projects with a dirty git status. (default: False)
  -r, --reverse         Loop in reverse order. (default: False)


demo project

A functional project that can be run out of the box. Used for learning or testing.

Demo projects are used by the test suite and the Sphinx documentation. They must have been initialized with inv prep before running inv test or inv bd.

The list of demo projects for a given repository is defined by demo_projects in the file.