Packaging

Packaging is bundling up your python library so that it can be easily pip install by others.

Typically this involves:

  1. Bundling the code into a Built Distribution (wheel) and/or Source Distribution (sdist).

  2. Uploading (publishing) the distribution(s) to python package repository, like PyPI.

This section is a brief bootcamp on package configuration for a CLI application. This is not intended to be a complete tutorial on python packaging and publishing. In this tutorial, replace all instances of mypackage with your own project name.

__main__.py

In python, if you have a module mypackage/__main__.py, it will be executed with the bash command python -m mypackage.

A pretty bare-bones Cyclopts mypackage/__main__.py will look like:

# mypackage/__main__.py

import cyclopts

app = cyclopts.App()

@app.command
def foo(name: str):
    print(f"Hello {name}!")

if __name__ == "__main__":
    app()
$ python -m mypackage World
Hello World!

Entrypoints

If you want your application to be callable like a standard bash executable (i.e. my-package instead of python -m mypackage), we'll need to add an entrypoint.

Modern Python projects typically use pyproject.toml for configuration. The standard way to define console scripts is:

# pyproject.toml
[project.scripts]
my-package = "mypackage.__main__:app"

This creates an executable named my-package that executes the callable app object (from the right of the colon) from the python module mypackage.__main__. Note that this configuration is independent of any special naming, like __main__ or app.

Legacy Configurations

For older projects, you may encounter these alternative formats:

setup.py:

# setup.py
from setuptools import setup

setup(
    # There should be a lot more fields populated here.
    entry_points={
        "console_scripts": [
            "my-package = mypackage.__main__:app",
        ]
    },
)

setup.cfg:

# setup.cfg
[options.entry_points]
console_scripts =
    my-package = mypackage.__main__:app

Poetry:

# pyproject.toml
[tool.poetry.scripts]
my-package = "mypackage.__main__:app"

The setuptools entrypoint documentation goes into further detail.

Result Action

When using Cyclopts as a CLI application, command return values are automatically handled appropriately. By default, App uses "print_non_int_sys_exit" mode, which calls sys.exit() with the appropriate exit code:

  • String returns are printed to stdout, then sys.exit(0) is called

  • Integer returns are passed to sys.exit(int) as the exit code

  • Boolean returns are converted: Truesys.exit(0), Falsesys.exit(1)

  • None returns call sys.exit(0)

This default behavior makes Cyclopts applications work consistently whether run directly as scripts or installed via console_scripts entry points. The result_action can be customized if different behavior is needed: