Paket veröffentlichen
=====================
Schließlich könnt ihr das Paket auf dem :term:`Python Package Index`
(:term:`PyPI`) oder einem anderen Index, :abbr:`z.B. (zum Beispiel)`
:doc:`gitlab` oder :term:`devpi`, bereitstellen.
Für den :term:`Python Package Index` müsst ihr euch bei *Test PyPI*
registrieren. *Test-PyPI* ist eine separate Instanz, die zum Testen und
Experimentieren vorgesehen ist. Um dort ein Konto einzurichten, geht ihr auf
https://test.pypi.org/account/register/. Weitere Informationen findet ihr unter
`Using TestPyPI
`_.
Nun könnt ihr eine :file:`~/.pypirc`-Datei erstellen:
.. code-block:: ini
[distutils]
index-servers=
test
[test]
repository = https://test.pypi.org/legacy/
username = veit
.. seealso::
Wenn ihr die PyPI-Anmeldung automatisieren wollt, lest zunächst `Careful
With That PyPI
`_.
Nachdem ihr registriert seid, könnt ihr euer :term:`Distribution Package` mit
``uv publish`` hochladen.
Anschließend könnt ihr ``uv publish`` entweder mit der Option ``--username
__token__`` verwenden oder die Umgebungsvariable
``UV_PUBLISH_USERNAME=__token__`` setzen, um alle Archive unter :file:`/dist`
auf den :term:`Python Package Index` hochladen.
.. code-block:: console
$ uv publish --publish-url https://test.pypi.org/legacy/ --username __token__ dist/*
``--publish-url``
Die URL des Upload-Endpunkts (nicht die Index-URL).
``--username``
Den Benutzernamen für den Upload.
.. note::
Wenn ihr eine ähnliche Fehlermeldung erhaltet wie
.. code-block:: console
The user 'veit' isn't allowed to upload to project 'example'
müsst ihr einen eindeutigen Namen für euer Paket auswählen:
#. ändert das ``name``-Argument in der :file:`pyproject.toml.`-Datei
#. entfernt das ``dist``-Verzeichnis
#. generiert die Archive neu
Überprüfen
----------
Installation
~~~~~~~~~~~~
Ihr könnt ``uv`` verwenden um euer Paket von *Test PyPI* zu installieren und zu
überprüfen, ob es funktioniert:
.. code-block:: console
uv add -i https://test.pypi.org/simple/ mypack
.. note::
Wenn ihr einen anderen Paketnamen verwendet habt als ``mypack``, ersetzt ihn
im obigen Befehl durch euren Paketnamen.
``uv add`` sollte das Paket von *Test PyPI* installieren und die Ausgabe sollte
in etwa so aussehen:
.. code-block:: console
Resolved 8 packages in 5ms
Installed 7 packages in 36ms
+ mypack==0.1.0
Ihr könnt testen, ob euer Paket korrekt installiert wurde indem ihr :func:`main`
aufruft:
.. code-block:: console
$ uv run mypack
Hello from mypack!
.. note::
Die Pakete auf *Test-PyPI* werden nur temporär gespeichert. Wenn ihr ein
Paket in den echten :term:`Python Package Index` (:term:`PyPI`) hochladen
wollt, könnt ihr dies tun, indem ihr ein Konto auf :term:`pypi.org` anlegt.
README
~~~~~~
Überprüft auch, ob die :file:`README.rst`-Datei auf der Test-PyPI-Seite korrekt
angezeigt wird.
PyPI
----
Registriert euch nun beim :term:`Python Package Index` (:term:`PyPI`) und stellt
sicher, dass die `Zwei-Faktor-Authentifizierung
`_.
.. seealso::
* `PyPI now supports uploading via API token
`_
* `What is two factor authentication and how does it work on PyPI?
`_
Schließlich könnt ihr nun euer Paket auf :term:`PyPI` veröffentlichen:
.. code-block:: console
$ uv upload dist/*
.. note::
Ihr könnt Releases nicht einfach ersetzen da ihr Pakete mit derselben
Versionsnummer nicht erneut hochladen könnt.
.. note::
Entfernt nicht alte Versionen aus dem Python Package Index. Dies verursacht
nur Arbeit für jene, die diese Version weiter verwenden wollen und dann auf
alte Versionen auf GitHub ausweichen müssen. PyPI hat eine `yank
`_-Funktion, die ihr stattdessen nutzen
könnt. Dies ignoriert eine bestimmte Version, wenn sie nicht explizit mit
``==`` oder ``===`` angegeben wurde.
.. seealso::
* `PyPI Release Checklist
`_
.. _pypi_github_action:
GitHub Action
-------------
Ihr könnt auch eine GitHub-Aktion erstellen, die ein Paket erstellt und auf PyPI
hochlädt. Eine solche :file:`.github/workflows/pypi.yml`-Datei könnte
folgendermaßen aussehen:
.. code-block:: yaml
:caption: .github/workflows/pypi.yml
:linenos:
:emphasize-lines: 3-5, 12, 31, 36, 38-
name: Publish Python Package
on:
release:
types: [created]
jobs:
test:
…
package-and-deploy:
runs-on: ubuntu-latest
needs: [test]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version-file: .python-version
cache-dependency-path: '**/pyproject.toml'
- name: Setup cached uv
uses: hynek/setup-cached-uv@v2
- name: Create venv
run: |
uv venv
echo "$PWD/.venv/bin" >> $GITHUB_PATH
- name: Build
run: |
uv build
- name: Retrieve and publish
steps:
- name: Retrieve release distributions
uses: actions/download-artifact@v4
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
username: __token__
password: ${{ secrets.PYPI_TOKEN }}
Zeilen 3–5
Dies stellt sicher, dass der Arbeitsablauf jedes Mal ausgeführt wird, wenn
ein neues GitHub-Release für das Repository erstellt wird.
Zeile 12
Der Job wartet auf das Bestehen des ``test``-Jobs bevor er ausgeführt wird.
Zeile 31
Hier sollte :samp:`{mypack}` durch euren Paketnamen ersetzt werden.
Zeile 36
Die GitHub-Aktion ``actions/download-artifact`` stellt die gebauten
Verteilungspakete bereit.
Zeile 38–41
Die GitHub-Aktion ``pypa/gh-action-pypi-publish`` veröffentlicht die Pakete
mit dem Upload-Token auf :term:`PyPI`.
.. seealso::
* `GitHub Actions `_
* :doc:`cibuildwheel`
.. _trusted_publishers:
Trusted Publishers
------------------
`Trusted Publishers `_ ist ein
Verfahren zum Veröffentlichen von Paketen auf dem :term:`PyPI`. Es basiert auf
OpenID Connect und erfordert weder Passwort noch Token. Dazu sind lediglich die
folgenden Schritte erforderlich:
#. Fügt einen *Trusted Publishers* auf PyPI hinzu
Je nachdem, ob ihr ein neues Paket veröffentlichen oder ein bestehendes
aktualisieren wollt, unterscheidet sich der Prozess geringfügig:
* zum Aktualisieren eines bestehenden Pakets siehe `Adding a trusted
publisher to an existing PyPI project
`_
* zum veröffentlichen eines neuen Pakets gibt es ein spezielles Verfahren,
*Pending Publisher* genannt; :abbr:`s.a. (siehe auch)` `Creating a PyPI
project with a trusted publisher
`_
Ihr könnt damit auch einen Paketnamen reservieren, bevor ihr die erste
Version veröffentlicht. Damit könnt ihr sicherstellen, dass ihr das Paket
auch unter dem gewünschten Namen veröffentlichen könnt.
Hierfür müsst ihr in `pypi.org/manage/account/publishing/
`_ einen neuen *Pending
Publisher* erstellen mit
* Namen des PyPI-Projekts
* GitHub-Repository Owner
* Namen des Workflows, :abbr:`z.B. (zum Beispiel)` :file:`publish.yml`
* Name der Umgebung (optional), :abbr:`z.B. (zum Beispiel)` ``release``
#. Erstellt eine Umgebung für die GitHub-Actions
Wenn wir eine Umgebung auf :term:`PyPI` angegeben haben, müssen wir diese nun
auch erstellen. Das kann in :menuselection:`Settings --> Environments` für
das Repository geschehen. Der Name unserer Umgebung ist ``release``.
#. Konfiguriert den Arbeitsablauf
Hierfür erstellen wir nun die Datei :file:`.github/workflows/publish.yml` in
unserem Repository:
.. code-block:: yaml
:caption: .github/workflows/pypi.yml
:lineno-start: 10
:emphasize-lines: 3, 4-5
package-and-deploy:
runs-on: ubuntu-latest
+ environment: release
+ permissions:
+ id-token: write
needs: [test]
steps:
Zeile 12
Die Angabe einer GitHub-Umgebung ist optional, wird aber dringend
empfohlen.
Zeilen 13–14
Die ``write``-Berechtigung ist für *Trusted Publishing* erforderlich.
Zeilen 42–44
``username`` und ``password`` werden für die GitHub-Aktion
``pypa/gh-action-pypi-publish`` nicht mehr benötigt.
.. code-block:: yaml
:caption: .github/workflows/pypi.yml
:lineno-start: 40
:emphasize-lines: 3-
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
- with:
- username: __token__
- password: ${{ secrets.PYPI_TOKEN }}
.. _digital-attestations:
Digital Attestations
--------------------
Seit 14. November 2024 unterstützt :term:`PyPI` auch :pep:`740` mit `Digital
Attestations `_. PyPI verwendet das
`in-toto Attestation Framework `_ zum
Ausstellen der Digital Attestations `SLSA Provenance
`_ und `PyPI Publish Attestation (v1)
`_.
Die Erstellung und Veröffentlichung erfolgt standardmäßig, sofern über
:ref:`Trusted Publishing ` und die GitHub-Action
`pypa/gh-action-pypi-publish `_
zum Veröffentlichen verwendet werden:
.. code-block:: yaml
:caption: .github/workflows/pypi.yml
jobs:
pypi-publish:
name: Upload release to PyPI
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/{YOUR-PYPI-PROJECT-NAME}
permissions:
id-token: write
steps:
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
.. note::
Die Unterstützung für die automatische Erstellung von Digital Attestations
und die Veröffentlichung aus anderen Trusted Publisher-Umgebungen ist
geplant.
.. seealso::
`PyPI now supports digital attestations
`_