Releasing to PyPI#
The distribution on PyPI is called xnns; the import package, the command
line and the GitHub repository are xnn (the PyPI name xnn belongs to
someone else). Releases are built and uploaded by the GitHub Actions workflow
.github/workflows/release.yml using PyPI Trusted Publishing, so no API token is stored
anywhere.
What the workflow does#
On every pushed tag
vX.Y.Z: build the sdist and wheel withpython -m build, runtwine check --strict, verify that the tag equalsv+xnn.__version__, verify that the.frcforce-field files and the D3 tables are inside the wheel, install the wheel into a clean virtual environment and import it, upload to PyPI, then create the GitHub Release for the tag (auto-generated notes) with the files attached. Plaingitis all that is needed on your side.On a manual Run workflow:
target = testpypiuploads the same build to TestPyPI as a rehearsal, from any branch or tag;target = pypipublishes a tag that was pushed earlier (select the tag under Use workflow from; it must equalv+__version__);target = noneonly builds and checks.
The version is defined once, in src/xnn/__init__.py (__version__);
pyproject.toml reads it (dynamic = ["version"]).
One-time setup#
GitHub environments. In the repository go to Settings > Environments and create
pypiandtestpypi. Optionally add yourself as a required reviewer ofpypiso every upload needs an explicit approval.PyPI. Log in at https://pypi.org, open Your account > Publishing and add a pending trusted publisher (the project does not exist yet, it is created by the first upload):
PyPI project name:
xnnsOwner:
molssi-aiRepository name:
xnn(the name the repository has when the workflow runs)Workflow name:
release.ymlEnvironment name:
pypi
TestPyPI. The same at https://test.pypi.org with environment
testpypi.
Cutting a release#
Bump
__version__insrc/xnn/__init__.py, make surepytest testsand the strict docs build pass, commit and push tomain.Rehearse: Actions > Release > Run workflow with
target = testpypi. Check https://test.pypi.org/p/xnns and, in a scratch environment,pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ xnns.Tag and push (the tag must equal
v+__version__or the workflow fails before uploading):git tag -a v0.1.0 -m "xnn 0.1.0" git push origin v0.1.0
Watch Actions > Release. When it is green the package is at https://pypi.org/p/xnns,
pip install xnnsworks, and the GitHub Release for the tag exists with the sdist and wheel attached.
A version can be uploaded to PyPI only once. If a release has to be redone,
bump the version (for example 0.1.1) and publish a new release.
Metadata rules that PyPI enforces#
No direct URL requirements in the metadata: the Allegro reference implementation (
mir-group/allegro, a git dependency) is therefore not part of any extra and is installed by hand for its fidelity notebook.twine check --strictmust pass, so the README has to be valid Markdown with absolute links only.The
licensefield is an SPDX expression (MIT), which needssetuptools >= 77at build time. The BSD-3 notice of the vendored SEAMM force-field files travels inside the package itself (xnn/ffnn/data/LICENSE-SEAMM), so it is in every wheel and sdist.