---
jupytext:
  formats: md:myst
  text_representation:
    extension: .md
    format_name: myst
    format_version: 0.13
kernelspec:
  display_name: Bash
  language: bash
  name: bash
---

# Modern Python packaging

:::{admonition} Education objectives
- understand modern Python packaging
- PyPA, <https://packaging.python.org>
- UV and PDM
- mention pypa-build and twine
:::

Python packaging has been fundamentally changed during the previous years.

The changes have been driven by the Python Packaging Authority ([PyPA]), which is a
working group that maintains a core set of software projects used in Python packaging.

There are very good resources on the web, in particular,

- <https://packaging.python.org>
- <https://www.pyopensci.org/python-package-guide/>

so we won't dive into the details here. However, one important point is that for new
project you should not need a `setup.py` file.

Moreover, there are very good tools to handle all the tasks needed for a Python project.
Depending on your need, we would advice these 3 complementary tools:

- [PDM]: package and project manager supporting the latest PEP standards.
- [UV]: fast package and project manager.
- [Pixi]: generalist package manager based on the conda ecosystem.

```{note}
[PDM can use UV](https://pdm-project.org/en/latest/usage/uv/) to speed-up few operations.
```

## A simple example using PDM

```{code-cell} bash
cd ../common/examples/example-py-project
ls
```

The file `example_py_package/pyproject.toml` contains

```{literalinclude} ../common/examples/example-py-project/pyproject.toml
---
lineno-match:
---
```

Note that this package define three "entry points" (`project.scripts`), two CLI[^cli] and
a TUI[^tui].

The source files are in the directory `src`:

```{code-cell} bash
ls src
```

```{code-cell} bash
ls src/example_py_package
```

One can create a virtual environment for the project and run a command provided by the
project:

```{code-cell} bash
:tags: [hide-cell]

export PDM_IGNORE_ACTIVE_VENV=1
unset PDM_PROJECT
```

```{code-cell} bash
:tags: [hide-output]

pdm sync --clean
```

```{code-cell} bash
pdm run example-py-simple
```

One can also use the python of the virtual environment:

```{code-cell} bash
pdm run python -c "from example_py_package import simple_function as sf; sf()"
```

Let us see what gives `example-py-cli` another command provided by the project:

```{code-cell} bash
# another command defined in this project
pdm run example-py-cli -h
```

```{code-cell} bash
pdm run example-py-cli --version
```

```{code-cell} bash
pdm run example-py-cli -n Mourad
```

One can format the code of the project with:

```{code-cell} bash
pdm run format
```

In real cases (i.e. for a real project and with execution outside of a notebook), one can
activate the environment and directly run commands.

```sh
. .venv/bin/activate
pytest src --color=no --code-highlight=no
example-py-simple
example-py-calculator
```

```{todo}

Better explain different aspects of packaging (with testing, linting, formatting and doc)

We base the presentation on a simple tool to visualize
info from Wikipedia using packages like sys, os, pathlib, argparse and third-party
dependencies like Requests and Textual...

Documentation with Sphinx + mention MkDocs and Readthedocs

```

[^cli]: CLI is for Command Line Interface.

[^tui]: TUI is for Terminal User Interface.

[pdm]: https://pdm-project.org
[pixi]: https://pixi.sh
[pypa]: https://www.pypa.io
[uv]: https://docs.astral.sh/uv/
