Skip to content
Snippets Groups Projects
Commit 912dd90c authored by Françoise Conil's avatar Françoise Conil
Browse files

Nombreux ajouts sur les backend et les outils

De nombreux pointeurs sur des articles, des comparaisons, des outils
complémentaires (cookiecutter, towncrier, ...)
parent 83290f62
No related branches found
No related tags found
No related merge requests found
images/do-while_run.jpg

73.5 KiB

images/jetbrains-python-developers-survey-2022-create-package-tool.png

105 KiB

images/pypi-2fa-activation.png

50.4 KiB

images/pypi-add-trusted-publisher.png

213 KiB

images/quand-tu-prends-un-appart-paris.jpg

38.3 KiB

images/tag-and-create-release.png

44.9 KiB

......@@ -18,8 +18,8 @@ versionner son code Python ?
- Structure d'un identifiant de version Python
- Logiciel de gestion de version : git
- Forges (GitHub, GitLab)
- Librairies de gestion de l'identifiant de version (Versioneer,
setuptools_scm, Miniver, ...)
- Librairies de gestion de l'identifiant de version (setuptools_scm,
Versioneer, Miniver, ...)
::: aside
Cette présentation ne décrit pas toutes les étapes nécessaires au packaging
......@@ -371,7 +371,7 @@ GitHub, on peut consulter la liste des versions et récupérer un `zip` ou un
- [tags du project Flit](https://github.com/pypa/flit/tags)
## Créer une release sur GitHub
## Créer une release sur GitHub 1/2
1. Dans [GitHub.com](https://github.com/), accédez à la page principale du dépôt
2. À droite de la liste des fichiers, cliquez sur **Releases**
......@@ -391,7 +391,7 @@ Liste des étapes reprise de la documentation officielle :
[Managing releases in a repository](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository?tool=webui#creating-a-release)
:::
---
## Créer une release sur GitHub 2/2
8. Vous pouvez lister les contributeurs en les déclarant dans la description de
la release via @mention (vous permet de sélectionner une personne dans la liste
......@@ -413,6 +413,16 @@ Liste des étapes reprise de la documentation officielle :
[Managing releases in a repository](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository?tool=webui#creating-a-release)
:::
## GitHub crée des lightweight tags
::: {.callout-warning title="ATTENTION"}
Il semble que les [tags créés par GitHub soient des lightweight tags](https://github.com/orgs/community/discussions/4924)
et non des annotated tags.
Cela peut perturber certains outils utilisés pour le packaging comme
dans l'[issue 521 de setuptools_scm](https://github.com/pypa/setuptools_scm/issues/521).
:::
## Avec les tags sur GitLab
Si des **tag** ont été positionnés dans l'historique du code et envoyés sur
......@@ -447,6 +457,8 @@ Liste des étapes reprise de la documentation officielle : [Create a release](ht
Quelques informations, très simplifiées, pour aborder le fichier `pyproject.toml`
![](images/quand-tu-prends-un-appart-paris.jpg){height="350"}
## Python Packaging Authority
> The [Python Packaging Authority](https://www.pypa.io/) (PyPA) is a working
......@@ -460,42 +472,196 @@ Parmis ces documentations, [The Packaging Flow](https://packaging.python.org/en/
^[Voir aussi le tutoriel [Packaging Python Projects](https://packaging.python.org/en/latest/tutorials/packaging-projects/)]
spécifie les principales étapes du packaging.
## Principales étapes du packaging
- Avoir le **code source** du package, typiquement le checkout d'un **tag** du
code issu d'un gestionnaire de version
- Créer un **fichier de configuration** pour décrire les **métadonnées** du package
(nom, version, etc) et pour spécifier la manière de **générer le package**. Il
s'agit généralemement du fichier `pyproject.toml` ^[Voir [PEP 518](https://peps.python.org/pep-0518/)
et [Declaring project metadata](https://packaging.python.org/en/latest/specifications/declaring-project-metadata/#declaring-project-metadata)
qui remplace la [PEP 621](https://peps.python.org/pep-0621/)]
- Exécuter l'**outil de build** pour produire une [source distribution (sdist)](https://packaging.python.org/en/latest/glossary/#term-Source-Distribution-or-sdist)
et une ou plusieurs [built distribution (wheel)](https://packaging.python.org/en/latest/glossary/#term-Built-Distribution)
à partir du fichier de configuration. Souvent, il n'y a qu'un [wheel](https://packaging.python.org/en/latest/glossary/#term-Wheel)
pour un package **pur Python**
- Mettre en ligne les éléments produits sur un service de distribution de
package (généralement [PyPI](https://pypi.org/)).
## Historiquement
Pendant longtemps le packaging a reposé sur le fichier `setup.py`. Cela posait
plusieurs problèmes ^[[L'enfer des paquets Python : la folie des
formats](https://www.stella.coop/blog/00007-l-enfer-des-paquets-python-la-folie-des-formats)]
dont la nécessité d'exécuter un fichier Python pour déterminer comment
installer un package, connaître ses dépendances, etc
Le packaging a longtemps a reposé sur [setuptools](https://setuptools.pypa.io/en/latest/)
et un script `setup.py`. Cela posait plusieurs problèmes dont la nécessité
d'exécuter ce script Python pour déterminer comment installer un package,
connaître ses dépendances, etc ^[Lire la série d'articles : [L'enfer des paquets Python](https://www.stella.coop/blog/00003-l-enfer-des-paquets-python-le-sac-de-noeuds)]
L’idée d'utiliser un **format déclaratif** pour la création des métadonnées de
package a été d'abord expérimentée via une solution intégrée à `setuptools` :
`setup.cfg` ^[[Aventuriers du packaging perdu (Présentation du
`setup.cfg`)](https://twidi.github.io/python-packaging-talk/fr)].
Cependant, il était également nécessaire de décorréler l'**outil d'installation**
[pip](https://pip.pypa.io/en/stable/) de l'exécution de `setuptools` avec
`setup.py`.
Les [PEP 517](https://peps.python.org/pep-0517/) et [PEP 518](https://peps.python.org/pep-0518/)
ont défini les notions de **build frontend** (`pip`, `build`) et de **build
backend** (`setuptools`, `Flit`, `Hatch`, ...) qui doivent être spécifiées
dans le fichier `pyproject.toml`.
Ce découplage frontend / backend a permis de faire évoluer `pip` et
`setuptools` et de faire apparaître de nouveaux **outils de build**.
## Build frontend
L’idée n’est pas de proposer un nouveau format de métadonnées mais de définir,
dans ce fichier texte `pyproject.toml`, les informations nécessaires pour que
le **build frontend** puisse créer un environnement de génération du package et
invoquer le **build backend** spécifié.
```{.toml}
[build-system]
requires = [
"cffi; implementation_name == 'pypy'",
"cython>=3.0.0; implementation_name == 'cpython'",
"packaging",
"setuptools>=61",
"setuptools_scm[toml]",
]
build-backend = "setuptools.build_meta"
[project]
name = "pyzmq"
```
Via la section `[build-system]`, le **build frontend** (`pip`, `build`) sait
qu'il a besoin d'un "environnement" Python avec `cffi`, `packaging`, ... et
une version minimale du **build backend** `setuptool` supérieure à 61.
Il sait aussi qu'il doit appeler `setuptool` comme **build backend** pour
générer le package `pyzmq`.
L’idée d'utiliser un **format déclaratif** pour la création de package a été
d'abord expérimentée via une solution intégrée à setuptools: `setup.cfg`
^[[Aventuriers du packaging perdu (Présentation du `setup.cfg`)](https://twidi.github.io/python-packaging-talk/fr)]
## Build backends
En 2016, la [PEP 518](https://peps.python.org/pep-0518/) introduit le fichier
`pyproject.toml`. L’idée n’est pas de proposer un nouveau format de métadonnées
mais d’inclure, dans un fichier texte simple, les dépendances nécessaires pour
**construire un package**. Il devient alors possible d'utiliser d'autres outils que
`setuptools` et `distutils`, au moins pour construire des packages. ^[[L’enfer
des paquets Python : des fichiers partout](https://www.stella.coop/blog/00009-l-enfer-des-paquets-python-des-fichiers-partout)]
Il devient alors possible d'utiliser d'autres **build backend** que
`setuptools` pour construire des packages. ^[[L’enfer des paquets Python : des
fichiers partout](https://www.stella.coop/blog/00009-l-enfer-des-paquets-python-des-fichiers-partout)]
L'historique réel est bien plus complexe ^[Lire la série d'articles : [L'enfer
des paquets Python](https://www.stella.coop/blog/00003-l-enfer-des-paquets-python-le-sac-de-noeuds)]
et le fichier `setup.py` reste encore nécessaire pour un grand nombre de
projets (compilation de code en C++).
L'extrait du `pyproject.toml` du projet [structlog](https://github.com/hynek/structlog)
ci-dessous indique que le **build backend** est [hatchling](https://hatch.pypa.io/latest/)
pour générer le package.
## setuptools reste un backend de build possible
Il indique également que les packages [hatch-vcs](https://pypi.org/project/hatch-vcs/)
et [hatch-fancy-pypi-readme](https://pypi.org/project/hatch-fancy-pypi-readme/) (en
version supérieure à 22.8.0) sont nécessaires pour le build du package `structlog`.
```{.toml}
[build-system]
requires = ["hatchling", "hatch-vcs", "hatch-fancy-pypi-readme>=22.8.0"]
build-backend = "hatchling.build"
[project]
dynamic = ["readme", "version"]
name = "structlog"
```
::: {.notes}
- `requires` : contient la liste des packages nécessaires pour générer le package
- `build-backend` : indique le `backend` que le `fontend` Python `build` doit
utiliser pour générer le package : ici `hatchling`
Voir
- `requires`, `build-backend`, `backend`, `fontend` : [The Packaging Flow](https://packaging.python.org/en/latest/flow/),
[Packaging Python Projects](https://packaging.python.org/en/latest/tutorials/packaging-projects/)
:::
## Génération du package par le frontend `build`
Le **frontend** `build` crée un environnement "isolé" où il installe les
`requires` spécifiés dans `build-system` pour générer les packages source
`sdist` et binaire `wheel` du projet `structlog`.
```{.bash code-line-numbers="6-9,12-14,21,22"}
$ git clone https://github.com/hynek/structlog.git
$ cd structlog
$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip install --upgrade pip build
$ python -m build
* Creating venv isolated environment...
* Installing packages in isolated environment... (hatch-fancy-pypi-readme>=22.8.0, hatch-vcs, hatchling)
* Getting build dependencies for sdist...
* Building sdist...
* Building wheel from sdist
* Creating venv isolated environment...
* Installing packages in isolated environment... (hatch-fancy-pypi-readme>=22.8.0, hatch-vcs, hatchling)
* Getting build dependencies for wheel...
* Building wheel...
/tmp/build-env-br9rr4sl/lib/python3.10/site-packages/setuptools_scm/git.py:308: UserWarning: git archive did not support describe output
warnings.warn("git archive did not support describe output")
/tmp/build-env-br9rr4sl/lib/python3.10/site-packages/setuptools_scm/git.py:327: UserWarning: unprocessed git archival found (no export subst applied)
warnings.warn("unprocessed git archival found (no export subst applied)")
Successfully built structlog-23.2.1.dev34.tar.gz and structlog-23.2.1.dev34-py3-none-any.whl
$ ls dist/
structlog-23.2.1.dev34-py3-none-any.whl structlog-23.2.1.dev34.tar.gz
```
::: aside
`pip` et `build` ne sont pas installés avec `python` sur `Ubuntu`.
:::
## Génération du package par le frontend `pip`
```{.bash code-line-numbers="6,8-11,16,17"}
$ git clone https://github.com/hynek/structlog.git
$ cd structlog
$ git describe
23.2.0-34-g8d3eeb1
$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip install --upgrade pip
$ python -m pip wheel --wheel-dir=dist .
Processing /home/fconil/LogicielsSrc/structlog
Installing build dependencies ... done
Getting requirements to build wheel ... done
Preparing metadata (pyproject.toml) ... done
Building wheels for collected packages: structlog
Building wheel for structlog (pyproject.toml) ... done
Created wheel for structlog: filename=structlog-23.2.1.dev34-py3-none-any.whl size=63292 sha256=f0afd834471686ece125bc56332b47b77eeda85377ca79cc378dd36f19159d4f
Stored in directory: /tmp/pip-ephem-wheel-cache-iru73n78/wheels/d4/a0/d1/88d4397a5f4751562af152ee044e264ac0fb9f7d6be1c3002d
Successfully built structlog
$ ls dist
structlog-23.2.1.dev34-py3-none-any.whl
```
Installation
```{.bash code-line-numbers="1,5,10"}
$ python -m pip install dist/structlog-23.2.1.dev34-py3-none-any.whl
Processing ./dist/structlog-23.2.1.dev34-py3-none-any.whl
Installing collected packages: structlog
Successfully installed structlog-23.2.1.dev34
$ pip list
Package Version
---------- ------------
pip 23.3.1
setuptools 59.6.0
structlog 23.2.1.dev34
```
## setuptools / setup.py
::: {.callout-note title="setuptools fait toujours partie des backends de build"}
L'article [Why you shouldn't invoke setup.py directly](https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html)
précise que [setuptools](https://setuptools.pypa.io/en/latest/)
est toujours maintenu et fait partie des backend utilisable (*19 oct 2021*).
est toujours maintenu et fait partie des backend utilisables (*19 oct 2021*).
C'est l'usage de `python setup.py <commande>` qui ne doit plus être utilisé et
fait l'objet de `DeprecationWarning` ^[Ne peut pas respecter pas les
spécifications [PEP 517](https://peps.python.org/pep-0517/) et
[PEP 518](https://peps.python.org/pep-0518/) des frontends de `build`] ^[À
C'est l'utilisation de `python setup.py <commande>` qui fait l'objet de
`DeprecationWarning` ^[Ne peut pas respecter pas les spécifications [PEP 517](https://peps.python.org/pep-0517/)
et [PEP 518](https://peps.python.org/pep-0518/) des frontends de `build`] ^[À
déterminer : quand, pourquoi et comment serait-on encore amené à utiliser un
fichier `setup.py`].
fichier `setup.py`]
```{.bash}
$ python setup.py install
......@@ -511,86 +677,89 @@ running install
See https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html for details.
********************************************************************************
```
:::
## Principales étapes du packaging
- Avoir le **code source** du package, typiquement le checkout d'un **tag** du
code issu d'un gestionnaire de version
- Créer un **fichier de configuration** pour décrire les **métadonnées** du package
(nom, version, etc) et pour spécifier la manière de **générer le package**. Il
s'agit généralemement du fichier `pyproject.toml` ^[Voir [PEP 518](https://peps.python.org/pep-0518/)
et [Declaring project metadata](https://packaging.python.org/en/latest/specifications/declaring-project-metadata/#declaring-project-metadata)
qui remplace la [PEP 621](https://peps.python.org/pep-0621/)]
- Exécuter l'**outil de build** pour produire une [source distribution (sdist)](https://packaging.python.org/en/latest/glossary/#term-Source-Distribution-or-sdist)
et une ou plusieurs [built distribution (wheel)](https://packaging.python.org/en/latest/glossary/#term-Built-Distribution)
à partir du fichier de configuration. Souvent, il n'y a qu'un [wheel](https://packaging.python.org/en/latest/glossary/#term-Wheel)
pour un package **pur Python**
- Mettre en ligne les éléments produits sur un service de distribution de
package (généralement [PyPI](https://pypi.org/)).
## pyproject.toml (1/2)
## pyproject.toml - exemple minimal 1/3
Voici un exemple de `pyproject.toml` qui utilise [Flit](https://flit.pypa.io/en/latest/)
pour générer le package et l'uploader sur `PyPI`.
Le fichier `pyproject.toml` est un fichier texte, au format [TOML](https://toml.io/en/),
dont voici une version minimale :
```{.toml}
[build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "foobar"
name = "example"
version = "0.1.0"
authors = [{name = "Sir Robin", email = "robin@camelot.uk"}]
description = "Exploring packaging tools"
```
[project.urls]
Home = "https://github.com/sirrobin/foobar"
pour configurer le packaging du projet basique :
```{.bash}
├── pyproject.toml
└── src
└── example
├── __init__.py
└── hello.py
```
::: aside
- `requires` : contient la liste des packages nécessaires pour générer le package
- `build-backend` : indique le `backend` que le `fontend` Python `build` doit
utiliser pour générer le package : ici `Flit`
Python Packaging User Guide :
Voir
- Guide : [Writing your pyproject.toml](https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#writing-pyproject-toml),
*page créée le 5 nov 2023*
- Tutoriel : [Packaging Python Projects](https://packaging.python.org/en/latest/tutorials/packaging-projects/#configuring-metadata)
- `requires`, `build-backend`, `backend`, `fontend` : [The Packaging Flow](https://packaging.python.org/en/latest/flow/),
[Packaging Python Projects](https://packaging.python.org/en/latest/tutorials/packaging-projects/)
Scientific Python Library Development Guide : [Tutoriel Packaging](https://learn.scientific-python.org/development/tutorials/packaging/)
:::
## pyproject.toml - les URL du projet (2/2)
::: {.notes}
Si la table `[build-system]` est omise, ce qui est déconseillé, le système de build va utiliser
La section `[project.urls]` liste les liens à afficher pour le projet et les
étiquettes à utiliser pour ces liens. Ces étiquettes, qui ne sont pas définies
^[[Core metadata specifications](https://packaging.python.org/en/latest/specifications/core-metadata/)],
diffèrent selon les documentations, ce qui est troublant :
```{.toml}
[build-system]
# Minimum requirements for the build system to execute.
requires = ["setuptools", "wheel"] # PEP 508 specifications.
```
- URL du dépôt du code : `Repository` ^[[Declaring project metadata](https://packaging.python.org/en/latest/specifications/declaring-project-metadata/#declaring-project-metadata)] ou `Source` ^[[Flit : The pyproject.toml config file](https://flit.pypa.io/en/latest/pyproject_toml.html#urls-table)] ?
On trouve aussi `URL`, `GitHub`, `GitLab`, ...
cf [PEP 518](https://peps.python.org/pep-0518/#build-system-table)
:::
L'article [PyPI Project URLs Cheatsheet](https://daniel.feldroy.com/posts/2023-08-pypi-project-urls-cheatsheet)
évoque des étiquettes trouvées via l'analyse du [code](https://github.com/pypi/warehouse/blob/70eac9796fa1eae24741525688a112586eab9010/warehouse/templates/packaging/detail.html#L20-L62)
de [PyPI](https://pypi.org/).
## pyproject.toml - Spécifications 2/3
Pourtant le projet [YAPF](https://pypi.org/project/yapf/0.40.2/#description) a
bien des étiquettes `Docs` et `Issues` mais PyPI n'affiche pas de lien vers les
URL. Problème de simple quote ^[[TOML String type](https://toml.io/en/v1.0.0#string)] ?
`Changelog` est pourtant affiché
::: {.callout-note title="Consulter"}
- [PEP 518](https://peps.python.org/pep-0518/) Specifying Minimum Build System Requirements for Python Projects
::: {.notes}
L'auteur de [PyPI Project URLs Cheatsheet](https://daniel.feldroy.com/posts/2023-08-pypi-project-urls-cheatsheet)
a obtenu les étiquettes suivantes à partir du [code](https://github.com/pypi/warehouse/blob/70eac9796fa1eae24741525688a112586eab9010/warehouse/templates/packaging/detail.html#L20-L62)
de [PyPI](https://pypi.org/)
- [Declaring project metadata](https://packaging.python.org/en/latest/specifications/declaring-project-metadata/#declaring-project-metadata) (PyPA)
qui regroupe et remplace :
- `homepage`
- `repository`
- `changelog`
- `docs`, `documentation`
- `bugs`, `issues`, `tracker`
- `dowload`
- `sponsor`, `funding`, `donate`
- `mastodon`, `twitter`, `slack`, `reddit`, `discord`, `gitter`
- [PEP 621](https://peps.python.org/pep-0621/) Storing project metadata in pyproject.toml
- [PEP 631](https://peps.python.org/pep-0631/) Dependency specification in
pyproject.toml based on `PEP 508` qui a été intégrée à la `PEP 621`
- [PEP 508](https://peps.python.org/pep-0508/) Dependency specification for Python Software Packages
:::
## pyproject.toml - métadonnées dynamiques 3/3
Les métadonnées dynamiques sont les métadonnées qu'un backend de build va
renseigner à l'exécution.
La liste des métadonnées qui peuvent être dynamiques dépend du backend ainsi
que la façon de récupérer dynamiquement ces métadonnées.
L'identifiant de `version` du projet est souvent récupéré dynamiquement depuis
le gestionnaire de version, généralement avec un plugin du backend.
[setuptools](https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html#dynamic-metadata)
permet de récupérer la **liste des dépendances** depuis un fichier conforme à un sous-ensemble du `requirement format` ^[Voir `pip`
[Requirements File Format](https://pip.pypa.io/en/latest/reference/requirements-file-format/),
fonctionne aussi avec le [`requirements.in` de pip-tools](https://pip-tools.readthedocs.io/en/latest/#requirements-from-pyproject-toml)]
::: {.callout-warning title="ATTENTION"}
Le nom du projet ne peut pas être une métadonnée dynamique. ^[[Declaring
project metadata](https://packaging.python.org/en/latest/specifications/declaring-project-metadata/#dynamic)]
:::
# PyPI
......@@ -622,6 +791,10 @@ fichiers](https://pypi.org/help/#file-size-limit) ou de la [taille totale du
projet](https://test.pypi.org/help/#project-size-limit)].
:::
::: {.notes}
Information affichée dans la gestion du projet sur `PyPI` / `TestPyPI`.
:::
## PyPI : Documentation et tests
Voici quelques sources d'information sur [PyPI](https://pypi.org/)
......@@ -740,7 +913,7 @@ droits) ou `maintainer`.
`maintainers` du package et les comptes gestionnaires du projet sur `PyPI`.
:::
## PyPI Organizations
## PyPI : Organizations
Les organisations `PyPI` sont une notion récente ^[[Introducing PyPI
Organizations](https://blog.pypi.org/posts/2023-04-23-introducing-pypi-organizations/)],
......@@ -1097,12 +1270,13 @@ exclude_lines = [
`setuptools` ne gère pas les dépendances.
`setuptools` n'upload pas les distributions générées sur `PyPI`.
`setuptools` n'upload pas les distributions générées sur `PyPI`, il est
conseillé d'utiliser twine.
`setuptools` ne gère pas les environnements virtuels.
::: {.callout-tip}
Les outils que j'ai expérimentés (`Versioneer`, `setuptools_scm`, `Miniver`)
Les outils que j'ai expérimentés (`setuptools_scm`, `Versioneer`, `Miniver`)
pour intégrer la version git au package semblent nécessiter `setuptools`
comme **backend de build**.
:::
......@@ -1130,6 +1304,88 @@ ces nouveaux standards. Et maintenant ?
`Poetry` dépendrait d'un seul développeur ?
## backend : PDM
[PDM](https://pdm-project.org/) est mis en avant ^[[pyOpenSci Packaging
guide](https://www.pyopensci.org/python-package-guide/package-structure-code/intro.html)]
par [pyOpenSci](https://www.pyopensci.org/) une organisation ^[pyOpenSci is a
fiscally sponsored project of [Community Initiatives](https://communityinitiatives.org/)
and is funded by the [Sloan Foundation](https://sloan.org/)] pour le peer review de package scientifique en
Open Science.
En fait, `PDM` est à la fois un **frontend** et un **backend** ce qui était le
cas de `setuptools` et peut prêter à confusion ^[[My User Experience Porting Off
setup.py](https://discuss.python.org/t/user-experience-with-porting-off-setup-py/37502/66)
sur [discuss.python.org](https://discuss.python.org/)].
Le projet semble très actif 2500 commits avec beaucoup de contributeurs.
Cependant 1789 commits / 2500 sont faits par [un unique contributeur](https://github.com/frostming).
::: {.callout-note title="PEP 582"}
`PDM` est le seul outil qui implémente la [PEP
582](https://peps.python.org/pep-0582/). Cette PEP proposait une alternative
aux environnements virtuels avec l'utilisation d'un dossier `__pypackages__`,
permettant un fonctionnement proche de [npm](https://docs.npmjs.com/about-npm).
^[[PEP 582: the future of Python packaging?](https://chriswarrick.com/blog/2023/01/15/how-to-improve-python-packaging/#pep-582-the-future-of-python-packaging)]
Est-il raisonnable d'adopter un usage sur une spécification rejetée ?
:::
## Comparaison des backends
Le [Scientific Python Library Development Guide](https://learn.scientific-python.org/development/),
donne un descriptif rapide de nombreux backend sur sa [page de template de projets](https://github.com/scientific-python/cookie)
D'autres tableaux comparatifs ont été réalisés ^[Cf PR [Add tools comparison
tables](https://github.com/pypa/packaging.python.org/pull/1196#issuecomment-1806879578) du Python Packaging User Guide] :
- [How to improve Python packaging, or why fourteen tools are at least twelve
too many](https://chriswarrick.com/blog/2023/01/15/how-to-improve-python-packaging/#tooling-proliferation-and-the-python-package-authority)
par Chris Warrick qui avait publié un article critique de
[Pipenv](https://chriswarrick.com/blog/2018/07/17/pipenv-promises-a-lot-delivers-very-little/) en 2018
- pyOpenSci [Python packaging tools summary](https://www.pyopensci.org/python-package-guide/package-structure-code/python-package-build-tools.html#package-tool-features-table)
- [An unbiased evaluation of environment management and packaging tools](https://alpopkes.com/posts/python/packaging_tools/)
d'Anna-Lena Popkes interviewée dans [TalkPython n°436](https://talkpython.fm/episodes/show/436/an-unbiased-evaluation-of-environment-and-packaging-tools)
## Python Developers Survey 2022 Results
Le [Python Developers Survey 2022 Results](https://lp.jetbrains.com/python-developers-survey-2022/#PythonPackaging)
de JetBrains donne aussi des informations intéressantes sur les pratiques de la
communauté
![](images/jetbrains-python-developers-survey-2022-create-package-tool.png)
## Statistiques sur le code
Statistiques de commits
```{.txt}
| backend | Premier commit | dernier commit | nb commits | nb commit | nb authors |
| | | | | per active day | |
| ---------- | -------------- | -------------- | ---------- | -------------- | ---------- |
| Flit | 2015-03-13 | 2023-11-10 | 1178 | 3.0 | 74 |
| Hatch | 2021-12-29 | 2023-11-13 | 669 | 2.8 | 42 |
| setuptools | 1998-12-18 | 2023-11-15 | 14175 | 4.5 | 603 |
| PDM | 2019-12-27 | 2023-10-16 | 2501 | 3.4 | 154 |
```
Principaux contributeurs
```{.txt}
| Flit | Hatch | setuptools | PDM |
| ----------------------- | ----------------------------- | ------------------------ | ------------------------ |
| auteur 1 : 879 (74.62%) | auteur 1 : 590 (88.19%) | auteur 1 : 6094 (42.99%) | auteur 1 : 1916 (76.61%) |
| auteur 2 : 46 (3.90%) | auteur 2 (bot) : 12 (1.79%) | auteur 2 : 1423 (10.04%) | idem : 175 (7.00%) |
| auteur 3 : 26 (2.21%) | auteur 3 : 12 (1.79%) | auteur 3 : 632 (4.46%) | auteur 3 : 53 (2.12%) |
632 (4.46%)
```
::: aside
- Données gitstats sur les dépôts le 2023-11-15
- TODO : Ajouter Poetry
:::
# Librairies de gestion de l'identifiant de version
Il existe des librairies qui récupèrent le **tag** pour le définir
......@@ -1191,19 +1447,12 @@ Ces deux métadonnées sont récupérées du fichier `src/ntt/__init__.py`.
__version__ = "0.1.1"
```
## Librairies possibles
## À vérifier
::: {.callout-warning}
Veillez à respecter la [PEP 440](https://peps.python.org/pep-0440/) pour
l'identifiant de version
:::
::: {.callout-tip title="À vérifier"}
Que se passe-t-il si le numéro de version déclaré dans le `pyproject.toml`
est différent du tag positionné dans le gestionnaire de version ?
:::
- [setuptools_scm](https://github.com/pypa/setuptools_scm)
- [hatch-vcs](https://github.com/ofek/hatch-vcs)
- [flit_scm](https://pypi.org/project/flit-scm/) basé sur `setuptools_scm`
- [Versioneer](https://pypi.org/project/versioneer/)
## setuptools_scm
......@@ -1228,3 +1477,233 @@ Le projet qui m'a fait découvrir `Versioneer` est passé à `setuptools_scm`.
serves the same purpose as Versioneer, except that it only works with Git and
multiplatform support is still experimental.
## À vérifier
::: {.callout-warning}
Veillez à respecter la [PEP 440](https://peps.python.org/pep-0440/) pour
l'identifiant de version
:::
::: {.callout-tip title="À vérifier"}
Que se passe-t-il si le numéro de version déclaré dans le `pyproject.toml`
est différent du tag positionné dans le gestionnaire de version ?
:::
# Guides - documentations
## Scientific Python Library Development Guide
Le [Scientific Python Library Development Guide](https://learn.scientific-python.org/development/)
publié en juillet 2023, semble être une excellente ressource à ce jour
# Accessoirement
## pyproject.toml - la déclaration des URL
La section `[project.urls]` liste les liens à afficher pour le projet et les
étiquettes à utiliser pour ces liens. Ces étiquettes, qui ne sont pas définies
^[[Core metadata specifications](https://packaging.python.org/en/latest/specifications/core-metadata/)],
diffèrent selon les documentations, ce qui est troublant :
- URL du dépôt du code : `Repository` ^[[Declaring project metadata](https://packaging.python.org/en/latest/specifications/declaring-project-metadata/#declaring-project-metadata)] ou `Source` ^[[Flit : The pyproject.toml config file](https://flit.pypa.io/en/latest/pyproject_toml.html#urls-table)] ?
On trouve aussi `URL`, `GitHub`, `GitLab`, ...
L'article [PyPI Project URLs Cheatsheet](https://daniel.feldroy.com/posts/2023-08-pypi-project-urls-cheatsheet)
évoque des étiquettes trouvées via l'analyse du [code](https://github.com/pypi/warehouse/blob/70eac9796fa1eae24741525688a112586eab9010/warehouse/templates/packaging/detail.html#L20-L62)
de [PyPI](https://pypi.org/).
Pourtant le projet [YAPF](https://pypi.org/project/yapf/0.40.2/#description) a
bien des étiquettes `Docs` et `Issues` mais PyPI n'affiche pas de lien vers les
URL. Problème de simple quote ^[[TOML String type](https://toml.io/en/v1.0.0#string)] ?
`Changelog` est pourtant affiché
::: {.notes}
L'auteur de [PyPI Project URLs Cheatsheet](https://daniel.feldroy.com/posts/2023-08-pypi-project-urls-cheatsheet)
a obtenu les étiquettes suivantes à partir du [code](https://github.com/pypi/warehouse/blob/70eac9796fa1eae24741525688a112586eab9010/warehouse/templates/packaging/detail.html#L20-L62)
de [PyPI](https://pypi.org/)
- `homepage`
- `repository`
- `changelog`
- `docs`, `documentation`
- `bugs`, `issues`, `tracker`
- `dowload`
- `sponsor`, `funding`, `donate`
- `mastodon`, `twitter`, `slack`, `reddit`, `discord`, `gitter`
:::
## Gestion des dépendances avec pip-tools 1/2
[pip-tools](https://pypi.org/project/pip-tools/) est un outil qui calcule
récursivement les dépendances spécifiées dans un `pyproject.toml`, un
`setup.py`/`setup.cfg` ou fichier texte avec une liste de packages (par
convention souvent nommée `requirements.in`).
`pip-compile` crée un environnement isolé pour le calcul des dépendances
lorsqu'on lui fournit un `pyproject.toml` :
```{.bash code-line-numbers="1,3-6"}
$ pip-compile -v pyproject.toml
Using pip-tools configuration defaults found in 'pyproject.toml'.
Creating venv isolated environment...
Installing packages in isolated environment... (flit_core >=3.2,<4)
Getting build dependencies for wheel...
Getting metadata for wheel...
Using indexes:
https://pypi.org/simple
```
::: aside
- `pip-tools` utilise le [résolveur de dépendances de `pip`](https://pip.pypa.io/en/stable/topics/dependency-resolution/).
Le "legacy resolver" était le résolveur interne de `pip`, le "backtracking
resolver" serait la librairie [resolvelib](https://github.com/sarugaku/resolvelib)
qui semble "vendorée" (intégrée) dans `pip`, voir `pip._vendor`.
- "`pip-tools` parses `pyproject.toml` metadata using `build`, not by `pip`",
voir [issue pip-tools 1781](https://github.com/jazzband/pip-tools/issues/1781#issuecomment-1366863514)
:::
## Gestion des dépendances avec pip-tools 2/2
Cette étape ne semble pas présente lorsqu'on lui fournit un `requirements.in`
```bash
$ pip-compile -v requirements.in
Using indexes:
https://pypi.org/simple
```
`pip-compile` génère un fichier `requirements.txt` avec les dépendances
calculées que l'on installe par `pip-sync`.
```bash
$ pip-sync requirements.txt
```
::: {.callout-warning title="ATTENTION"}
`pip-sync` installe les packages spécifiés dans le fichier `requirements.txt`.
Si des packages ont été manuellement installés dans l'environnement et qu'ils
ne sont pas présents dans le fichier `requirements.txt`, ils seront désinstallés.
:::
## Doit-on committer son requirements.txt ?
La question est posée dans une [issue pip-tools 1838](https://github.com/jazzband/pip-tools/issues/1838)
Il est certains que si les utilisateurs d'un projet ont des environnements
différents, un seul requirements.txt (ou xxx.lock) ne peut pas être appliqué
pour tous.
## Workflow de tag 1/2
![](images/do-while_run.jpg){height="350"}
::: aside
Avec ces plugin de récupération de tag dans `git`, quel est le bon workflow à adopter ?
:::
## Workflow de tag 2/2
![](images/tag-and-create-release.png){height="550"}
::: aside
À quel moment faut-il taguer dans le processus de publication de package ?
:::
## Template de projet 1/3
Le [Scientific Python Library Development Guide](https://learn.scientific-python.org/development/),
propose des templates de projet très riches à utiliser au choix avec [copier](https://copier.readthedocs.io/en/stable/),
[cookiecutter](https://cookiecutter.readthedocs.io/) ou [cruft](https://cruft.github.io/cruft/).
J'ai fait un test avec `cookiecutter`, avec un template qui utilise
[setuptools_scm](https://setuptools-scm.readthedocs.io/). Le `pyproject.toml`
référence un fichier `_version.py`
```{.toml}
[tool.setuptools_scm]
write_to = "src/example/_version.py"
```
ignoré par le `.gitignore` du template
```{.git}
# setuptools_scm
src/*/_version.py
```
Le projet contient un fichier `src/example/_version.pyi`
```{.python}
from __future__ import annotations
version: str
version_tuple: tuple[int, int, int] | tuple[int, int, int, str, str]
```
::: aside
Qu'est-ce que ce fichier `.pyi`, c'est lié au typage ? Il semblerait que oui,
ce seraient des `stub files` pour les controleurs de types statiques : [stub files dans la PEP 484](https://peps.python.org/pep-0484/#stub-files),
[stub files dans la mypy](https://mypy.readthedocs.io/en/stable/stubs.html)
:::
## Template de projet 2/3
Le fichier généré `src/example/_version.py`
```{.python}
# file generated by setuptools_scm
# don't change, don't track in version control
TYPE_CHECKING = False
if TYPE_CHECKING:
from typing import Tuple, Union
VERSION_TUPLE = Tuple[Union[int, str], ...]
else:
VERSION_TUPLE = object
version: str
__version__: str
__version_tuple__: VERSION_TUPLE
version_tuple: VERSION_TUPLE
__version__ = version = '0.0.1'
__version_tuple__ = version_tuple = (0, 0, 1)
```
Il n'est pas géré par `git`, et les packages ont bien le tag
```{.bash}
$ git tag -l -n
0.0.1 Initial release
$ git status
Sur la branche main
Fichiers non suivis:
(utilisez "git add <fichier>..." pour inclure dans ce qui sera validé)
.pre-commit-config.yaml
$ ls dist/
example-0.0.1-py3-none-any.whl example-0.0.1.tar.gz
```
::: {.notes}
Projet généré et testé dans `/tmp`, donc à recommencer si on veut garder une trace.
:::
## Template de projet 3/3
C'est trop cool et cela amène plein de connaissances et des idées de bonnes
pratiques !
Mettre la génération avec `cookiecutter`.
## towncrier pour créer des changelogs
[towncrier](https://towncrier.readthedocs.io/en/stable/index.html) semble
servir à créer des `changelogs`.
::: {.callout-note title="À ÉTUDIER"}
Used by Twisted, pytest, pip, BuildBot, and attrs, among others.
:::
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment