Package#
Configuration#
pyproject.toml file replaces setup.py.
It is written in TOML.
Python standard library has a module named tomllib for reading (but not writing) TOML files. To write TOML files, other non-standard libraries such as toml and tomli-W can be used. However, these don’t preserve the original style of a TOML file when modifying. TOML Kit is another alternative that also preserves styling, and is used in this package to read, modify and write the pyproject.toml file.
Version#
We use semantic versions.
We use versioningit to automatically handle versions. It will calculate the version of the package and dynamically inject it into pyproject.toml, so that using pip or build to install/build the package will always have a version number. The version number is also injected into the main _init_.py file of the package.
The configurations are stored in pyproject.toml, under [tool.versioningit] tables.
For this, after the initial commit to your repository, create a tag:
git tag -a 0.0.0 -m “Initial template by PyPackIT”
and push:
git push origin –tags
or
git push origin 0.0.0
This will build the package with version 0.0.0.
Afterward, until you create the next tag (0.0.1), any push to the main branch will create a development version in the form of 0.0.1.devN, where N is the number of commits to the main branch since the last tag. This is a PEP440-compliant public version identifier, so that each push to the main branch can be published on TestPyPI.
For developers:
an alternative is pypa/setuptools_scm
Versioneer will automatically infer what version
is installed by looking at the git
tags and how many commits ahead this version is. The format follows
PEP 440 and has the regular expression of:
\d+.\d+.\d+(?\+\d+-[a-z0-9]+)
If the version of this commit is the same as a git
tag, the installed version is the same as the tag,
e.g. v0.1.2
, otherwise it will be appended with +X
where X
is the number of commits
ahead from the last tag, and then -YYYYYY
where the Y
’s are replaced with the git
commit hash.
Build#
Publishing#
References: Python Packaging User Guide on publishing package distribution releases using GitHub Actions workflows.
We use a better alternative; First, we use the PyPI cibuildwheel GitHub action, to build multiple wheels on a matrix of OS and Python versions. This is only done when the package is not pure python (see this issue).
Then, we use the pypi-publish GitHub action, to publish the package on PyPI and TestPyPI, using trusted publishing.
Description#
The project description shown on PyPI is defined in pyproject.toml, under the [project] table.
PyPI uses the readme_renderer Python package to generate HTML outputs from the provided README file. The renderer only allows for certain HTML tags and attributes . For example, the
The Twine Python package, which is PyPI’s recommended tool for uploading packages
to PyPI, has a command to check the README file for PyPI compatibility: twine check
.
This command is run automatically by the pypi-publish GitHub action,
when the verify-metadata
input is set to true
(see pypi-publish code). We have this check implemented in our publishing workflow.
However, twine check, which uses the readme_renderer Python package under the hood,
is not sufficient on its own, as it only checks whether the file could have been rendered by PyPI. However,
for example if there are unsupported HTML tags in the README file, twine check will pass, but those tags
will be rendered as plain text on PyPI (see twine code). Therefore, we also need to visually investigate the rendered README
file. This is done by using the readme_renderer Python package in an extra
step to generate and upload the rendered README file as an artifact.