'Hypermodernize' your Python Package
Tags: python, packaging, cleancode
Published: 2023-12-07 11:28:00

---
title: 'Hypermodernize' your Python Package
published: true
description: Convert your legacy 'setup.py' into a modern 'pyproject.toml' 
tags: python, packaging, cleancode
cover_image: https://github.com/cleder/talks/blob/main/images/python-packaging.jpg?raw=true
# Use a ratio of 100:42 for best results.
published_at: 2023-12-07 11:28 +0000
---
In the original [Hypermodern Python Blogpost](https://cjolowicz.github.io/posts/hypermodern-python-01-setup/#setting-up-a-python-project-using-poetry), Poetry was recommended as the preferred tool.
There are quite a lot of packaging tools out there which I do not want to go into in depth, instead I recommend Anna-Lena Popkes [An unbiased evaluation of environment management and packaging tools](https://alpopkes.com/posts/python/packaging_tools/).
What _has_ emerged as the preferred way to store packaging information is the [`pyproject.toml`](https://packaging.python.org/en/latest/specifications/pyproject-toml/#pyproject-toml-spec) file.

Using `pyproject.toml` over `setup.py` has become a preferred choice for several reasons:

1. **Consistent Configuration:** `pyproject.toml` is part of the [PEP 518](https://peps.python.org/pep-0518/) and [PEP 517](https://peps.python.org/pep-0517/) specifications, offering a standardized and consistent way to declare build configurations and dependencies.
2. **PEP 518 Support:** `pyproject.toml` supports PEP 518, allowing the declaration of build system requirements, enabling better compatibility with modern build tools and providing more flexibility in the build process.
3. **Modern Tooling:** Some modern Python tools rely on `pyproject.toml` for project configuration. Adopting `pyproject.toml` aligns with these tools and facilitates a smoother integration with them.
4. **Readability and Maintainability:** The `pyproject.toml` format is often considered more readable and straightforward than the Python code used in `setup.py`. This can contribute to better maintainability, especially for more complex projects.
5. **Standardization:** As Python packaging evolves, `pyproject.toml` is becoming the de facto standard for configuration, supported by tools like `pip` and build systems like `flit` and `poetry`.

The adoption of `pyproject.toml` aligns with modern best practices in the Python packaging ecosystem.

Converting a `setup.py` base package to a `pyproject.toml` based one turns out to be straightforward for most use cases.
While it is [easy to write](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#writing-pyproject-toml) a `pyproject.toml` there are a number of tools to convert legacy package information into this format.

 - [setuptools-py2cfg](https://github.com/gvalkov/setuptools-py2cfg#setuptools-py2cfg) A script for converting `setup.py` to `setup.cfg`
 - [ini2toml](https://github.com/abravalheri/ini2toml#ini2toml) which automatically translates [.ini/.cfg](https://docs.python.org/3/library/configparser.html#supported-ini-file-structure) files into [TOML](https://toml.io/)
 - [validate-pyproject](https://github.com/abravalheri/validate-pyproject#validate-pyproject) for automated checks on `pyproject.toml` powered by JSON Schema definitions
 - [pyprojectsort](https://github.com/kieran-ryan/pyprojectsort#pyprojectsort) enforces consistent formatting of pyproject.toml files, reducing merge request conflicts and saving time otherwise spent on manual formatting.   
 - [pyroma](https://github.com/regebro/pyroma) Rate your Python packages package friendliness.

## Example

Install the required packages

```console
pip install setuptools-py2cfg ini2toml[full]
```

or if you get an error `no matches found: ini2toml[full]`


```console
pip install setuptools-py2cfg ini2toml configupdater tomlkit
```

Create a temporary `cfg` file

```console
setuptools-py2cfg > tmp.cfg
```

and convert it into a `toml` file:

```console
ini2toml --output-file=tmp.toml --profile=setup.cfg tmp.cfg
```

Apart from the profile `setup.cfg` `ini2toml` also has profiles to convert settings to their `pyproject.toml` equivalent for

 - `.coveragerc`
 - `.isort.cfg`
 - `mypy.ini`
 - `pytest.ini` ('ini_options' table)

After you converted the files, cut and paste them into a new (or existing) `pyproject.toml` file and validate and format them.

```console
pip install validate-pyproject pyprojectsort pyroma
```

```console
pyprojectsort
validate-pyproject pyproject.toml
```

Now you can delete your old setup.py file and verify that your package still builds as expected with 

```console
rm setup.py
python -m build
pyroma .
```

Check the `dist/[my-package-name].tar.gz` file to ensure it builds like before.

Adjust and tweak the settings as outlined in the [user guide](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#writing-pyproject-toml)

## Additional information

- [Authoring a Modern Python Package](https://medium.com/@noexec/creating-and-publishing-a-modern-python-package-e0b5bce9461d)
- [Moshe Zadka: pyproject.toml, packaging, and you](https://youtu.be/UOdMnlQRRCk)