1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
|
=========
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:
.. code-block:: python
# mypackage/__main__.py
import cyclopts
app = cyclopts.App()
@app.command
def foo(name: str):
print(f"Hello {name}!")
def main():
app()
if __name__ == "__main__":
main()
.. code-block:: console
$ python -m mypackage World
Hello World!
In the current state, the :func:`main` function is an unnecessary extra level of indirection (could just directly call :obj:`app`), but it can sometimes offer you additional flexibility in the future if you need it.
-----------
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_.
We'll investigate the setuptools solution, and the poetry solution.
^^^^^^^^^^
Setuptools
^^^^^^^^^^
``setup.py`` is a script at the root of your project that gets executed upon installation.
``setup.cfg`` and ``pyproject.toml`` are two other alternatives that are supported.
The following are all equivalent, **but should not be used at the same time**.
It is important that the function specified **takes no arguments**.
.. code-block:: python
# setup.py
from setuptools import setup
setup(
# There should be a lot more fields populated here.
entry_points={
"console_scripts": [
"my-package = mypackage.__main__:main",
]
},
)
.. code-block:: toml
# pyproject.toml
[project.scripts]
my-package = "mypackage.__main__:main"
.. code-block:: cfg
# setup.cfg
[options.entry_points]
console_scripts =
my-package = mypackage.__main__:main
All of these represent the same thing: create an executable named ``my-package`` that executes function ``main`` (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 ``main``.
The setuptools entrypoint_ documentation goes into further detail.
^^^^^^
Poetry
^^^^^^
Poetry_ is a tool for dependency management and packaging in Python (and what Cyclopts uses).
The syntax is very similar to setuptools:
.. code-block:: toml
# pyproject.toml
[tool.poetry.scripts]
my-package = "mypackage.__main__:main"
.. _Poetry: https://python-poetry.org
.. _entrypoint: https://setuptools.pypa.io/en/latest/userguide/entry_point.html#entry-points
|