Développer un projet Python en 2021 : les outils
Alors que Python poursuit en 2020 sa croissance exceptionnelle, la multiplication des outils à disposition du développeur Python peut être déconcertante. Essayons d’y voir plus clair.
Ce premier post détaille les outils de gestion de projets Python qui me semblent les plus intéressants. Dans un deuxième volet, je parlerai de la programmation Python en elle-même.
Note : Tout ce qui est écrit ici a été testé sous Ubuntu/Debian mais reste valable sous Windows, avec un peu plus d’efforts. Les versions récentes de Windows permettent en outre d’utiliser Linux via WSL.
Gérer les versions Python : pyenv
Commençons par le commencement : installer Python. Bien que Python soit installé nativement sur toute distribution Linux qui se respecte, changer de version à partir des sources peut être fastidieux. pyenv est un utilitaire écrit en shell qui simplifie l’installation et l’utilisation de différentes versions de Python.
Pour installer pyenv, le plus simple est de passer par ce script :
curl https://pyenv.run | shell
Ceci télécharge puis exécute https://pyenv.run, qui clone le dépôt github.com:pyenv/pyenv dans ~/.pyenv
et ajoute pyenv dans ~/.shellrc
.
pyenv utilise un hook pour intercepter les commandes Python et choisir la bonne version à utiliser.
Pour voir les versions de Python détectées :
pyenv global
system # exécutable Python apporté par le système d'exploitation
Note : Sous Ubuntu, il n’y a pas de commande python
par défaut, ce qui empêche pyenv de le détecter. Une solution est de créer un lien symbolique vers python3
: ln -s /usr/bin/python3 /usr/bin/python
.
Installons les éventuelles dépendances manquantes de Python :
sudo apt-get update; sudo apt-get install --no-install-recommends make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
Ajoutons la version 3.9.1 de Python :
pyenv install 3.9.1
python3.9.1 est alors installé dans ~/.pyenv/versions/3.9.1
.
Il est possible de spécifier une version de Python au niveau global ou local :
pyenv global 3.9.1 # utiliser python3.9.1 globalement
pyenv local 3.9.1 # utiliser python3.9.1 localement (répertoire en cours)
python
, python3
ou python3.9
permet alors d’utiliser notre version 3.9.1 fraîchement installée.
EDI : PyCharm vs Visual Code
PyCharm et Visual Code sont, de loin, les environnements de développement privilégiés par les développeurs Python.1 Alors que PyCharm est spécifique au langage Python, Visual Code est un EDI “tout en un” qui est très utilisé aussi en développement web, par exemple. À noter que PyCharm est gratuit dans sa version Community mais payante et propriétaire en version Professional. Au contraire, Visual Code est entièrement gratuit et open source. J’ai personnellement adopté Visual Code pour sa légereté et ses nombreux plugins.
Voici quelques commandes Visual Code que j’ai trouvé particulièrement utiles:
- Ctrl + Maj + P / F1 : ouvrir la liste des commandes
Certaines commandes n’ont pas de raccourci mais sont très pratiques : “Transform to Lower Case” ou “Sort Imports”, par exemple - Ctrl + P : naviguer parmi les fichiers/fonctions
- Ctrl + F5 : exécuter un fichier
- F5 : débugger un fichier
- Ctrl + C / Ctrl + V / Ctrl + X (sans sélection) : copier/coller/couper la ligne en cours
- Alt + Up/Down : déplacer une ligne vers le haut/bas
- Alt + Clic : selection multi-curseurs
- Ctrl + Maj + L : selectionner tous les mots identiques
- Ctrl + Space : complétion automatique
Dépendances : Poetry vs Pipenv vs conda
Il est fortement déconseillé d’installer tous ses packages Python globalement : il deviendrait difficile de partager uniquement les dépendances nécessaires pour un projet et certains projets peuvent nécessiter des versions différentes du même package…
Un environnement virtuel permet de regrouper les packages requis pour un projet particulier. Depuis Python 3.3, venv permet de créer nativement des environnements virtuels. De nombreux développeurs utilisent venv pour installer leurs packages et pip freeze
pour partager la liste requirements.txt
des versions à installer. Cette approche se heurte à de nombreux problèmes : la mise à jour des packages est délicate et pip est notoirement connu pour sa déficience dans la résolution des dépendances2.
Poetry, Pipenv et conda sont des surcouches plus évoluées qui offrent plus de possibilités.
Conda est un peu à part : alors que les autres outils sont basés sur PyPI/pip (et leurs packages wheel/source), conda a son propre dépôt (Anaconda Cloud) et système de packages. De ce fait, conda est plutôt utilisé comme outil tout-en-un (il permet aussi de mettre à jour Python, par exemple) et s’interface assez mal.
Dans la suite, je détaille l’utilisation de Poetry : il est similaire à Pipenv mais, contrairement aux deux autres, il se base sur les recommandations officielles PEP 517 et PEP 518.
Installer Poetry :
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
Créer un nouveau projet :
poetry new projet
Ceci génère la structure suivante :
projet/
├── projet
│ └── __init__.py
├── pyproject.toml
├── README.rst
└── tests
├── __init__.py
└── test_projet.py
Il est aussi possible utiliser un projet déjà existant :
poetry init
Le fichier .toml généré ressemble à :
[tool.poetry]
name = "projet"
version = "0.1.0"
description = ""
authors = ["Quentin Fortier <qpfortier@gmail.com>"]
[tool.poetry.dependencies]
python = "^3.9"
[tool.poetry.dev-dependencies]
pytest = "^5.2"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
Ce fichier remplace requirements.txt
en définissant les dépendances utilisées pour le projet. Ainsi, python = “^3.9” signifie que la version de Python doit être supérieure à 3.9, mais ne doit pas être mise à jour à la prochaine major release (4.*).
Ajoutons la dernière version de NumPy à notre projet :
poetry add numpy
Poetry ajoute alors numpy
à pyproject.toml
. Pour installer les packages ajoutés :
poetry install # ou poetry update si un install a déjà été fait
Poetry créé alors un environnement virtuel dans ~/.cache/pypoetry/virtualenvs
qui ressemble à ceci :
projet-v_ZTu9ix-py3.9/
├── bin
│ ├── activate
│ ├── pip
│ ├── pytest
│ ├── python -> /home/qfortier/.pyenv/versions/3.9.1/bin/python # lien symbolique
├── lib # contient les packages installés avec poetry/pip
└── pyvenv.cfg
On peut ensuite utiliser notre environnement virtuel en exécutant poetry run
ou poetry shell
.
Constatons par exemple que Poetry ajoute automatiquement notre projet au PYTHONPATH (plus besoin de manipuler sys.path
à la main ni d’imports relatifs!) :
poetry shell
(projet-v_ZTu9ix-py3.9) python -c "import sys; print(sys.path)"
['', '/home/qfortier/.pyenv/versions/3.9.1/lib/python3.9', '/home/qfortier/.cache/pypoetry/virtualenvs/projet-v_ZTu9ix-py3.9/lib/python3.9/site-packages',
'/home/qfortier/code/projet' # chemin vers notre projet
]
Ainsi, un module projet/projet/a/b.py
sera importé de la façon suivante dans un fichier Python :
import projet.a.b
Pour utiliser l’environnement virtuel de Poetry dans Visual Code, utiliser la commande “Python : Select Interpreter” puis donner le chemin correspondant (~/.cache/pypoetry/virtualenvs/<projet>/bin/python
). Visual Code affiche l’environnement en cours d’utilisation :
Note : Par défaut, Visual Code cherche un environnement virtuel dans le répertoire du projet. Il est possible de chercher parmi les environnements Poetry en ajoutant la ligne suivante au fichier settings.json: "python.venvPath": "~/.cache/pypoetry/virtualenvs/"
Environnement virtuel et Jupyter
Pour utiliser un environnement virtuel dans Jupyter, il faut l’ajouter en tant que kernel :
- Activer l’environnement (
poetry shell
, par exemple) - Installer ipykernel :
pip install ipykernel
- Ajouter l’environnement :
ipython kernel install --user --name=envname
- Sélectionner le kernel correspondant dans Jupyter
Packaging
Après avoir rempli pyproject.toml
, Poetry permet de construire une archive de package pour notre projet :
poetry build
Cette commande crée en fait deux archives du projet : projet-0.1.0.tar.gz
et projet-0.1.0-py3-none-any.whl
. Ce dernier est un format wheel qui peut ensuite être installé, avec ses dépendances :
pip install projet-0.1.0-py3-none-any.whl
Il est tout aussi simple de publier le projet sur un dépôt, par défaut PyPI :
poetry publish
Votre projet devient alors accessible à la communauté via pip install projet
.
Voici un tableau résumant les fonctionnalités de Poetry et ses alternatives :
python | poetry | pipenv | conda | |
---|---|---|---|---|
installer un package | pip install | poetry add | pipenv install | conda install |
liste des dépendances | requirements.txt | pyproject.toml + poetry.lock | Pipfile + Pipfile.lock | environment.yml |
installer toutes les dépendances | pip install -r requirements.txt | poetry install | pipenv install | conda install |
mettre à jour toutes les dépendances | pip-review | poetry update | pipenv update | conda update |
créer un environnement virtuel | python -m venv | (automatique) | (automatique) | conda create |
activer un environnement virtuel | source venv/bin/activate | poetry shell | pipenv shell | conda activate |
lancer une commande dans l’environnement | X | poetry run | pipenv run | X |
construire une archive du package | setuptools | poetry build | X | conda skeleton + conda-build |
publier un package | twine | poetry publish | X | anaconda upload |
Gérer les versions du code source : Git et GitHub
Git est un logiciel permettant de conserver un historique des modifications du code source, dans ce qu’on appelle un dépôt.
Après avoir installé git
(sudo apt install git
), on peut initialiser un dépôt dans le répertoire courant :
git init
Chaque modification du dépôt est appelé un commit. Après avoir modifié un fichier, il faut enregistrer les modifications pour le prochain commit :
git add fichier
Le fichier est alors staged.
Après avoir rajouté les modifications souhaitées, vous pouvez vérifier le contenu du prochain commit avec git status
puis le valider :
git commit
Git vous demande alors un message expliquant les modifications apportées par ce commit.
Voici quelques règles pour écrire un bon commit:
- Un commit doit être atomique (une seule modification) : si votre message contient “et”, il faut probablement utiliser deux commits
- Un commit doit être complet : évitez de faire la moitié d’une tâche et attendez de finir votre modification pour commit
- Un message commence en général par un verbe et doit être concis, en sautant éventuellement une ligne pour donner des détails
Il est possible de parcourir l’historique des commits avec git log
:
git log
commit 2ce5ff0 (HEAD -> master)
Author: Quentin Fortier <qpfortier@gmail.com>
Fix out of bound error
commit f0a1b71
Author: Quentin Fortier <qpfortier@gmail.com>
Add README
Note : l’historique de Git a une structure arborescente, constituée (en général) de plusieurs branches. Une nouvelle branche peut être créée lorsque l’on souhaite tester une nouvelle piste sans être sûr qu’elle aboutisse, par exemple. Une fois que le développement de la branche est terminé, on peut la fusionner (merge) avec la branche principale. Pour simplifier, nous utilisons ici une seule branche appelée master (branche principale).
Chaque commit possède un hash permettant d’y faire référence. Par exemple :
git checkout f0a1b71 # revient au commit correspondant
git diff f0a1b71 2ce5ff0 # affiche les différences entre deux commits
À ce stade, le dépôt est stocké en local. Pour travailler à plusieurs sur le même projet, on peut utiliser un serveur distant. Le serveur le plus connu est GitHub. Après avoir créé un dépôt https://github.com/utilisateur/depot.git sur GitHub, on peut le rajouter en tant que dépôt distant, nommé ici origin
:
git remote add origin git@github.com:utilisateur/depot.git
Note : Cette méthode de connection utilise SSH et demande de générer une clé. Il est également possible de se connecter via HTTPS.
Pour envoyer nos commits sur le dépôt distant :
git push origin master # envoie la branche master sur le dépôt distant origin
Il est possible de récupérer un dépôt sur GitHub avec git clone
. Par exemple, le dépôt de NumPy :
git clone git@github.com:numpy/numpy.git
Le code source de NumPy est alors téléchargé dans le dossier numpy
.
Voici un résumé du workflow de base avec git
:
git pull # récupère les derniers commits sur origin
git add fichiers # ajoute des modifications
git commit # crée un commit
git push # envoie un ou plusieurs commits sur origin
Note : Ceci constitue le minimum vital pour l’utilisation de git
. Les choses se compliquent quand il y a des conflits (plusieurs modifications sur la même portion de code) ou lorsque plusieurs branches sont utilisées. Voir le site officiel pour une utilisation plus avancée.
En pratique, de nombreux environnements de développement simplifient l’utilisation de git
via une interface graphique. Par exemple, Git Graph est un plugin de Visual Code permettant d’agir visuellement sur le graphe Git. Voici un extrait du graphe Git de NumPy :
Références
- Python et Visual Code : https://code.visualstudio.com/docs/languages/python
- Dépendances : https://modelpredict.com/python-dependency-management-tools, https://www.codeflow.site/fr/article/pipenv-guide
- Packaging : https://packaging.python.org, https://docs.python.org/fr/3/distributing/index.html
- Git : https://git-scm.com et https://guides.github.com
- https://cjolowicz.github.io/posts/hypermodern-python-01-setup
- Les dessins géniaux de xkcd
-
Python Developers Survey 2019, mené par la Python Software Foundation et Jetbrains, éditeur de PyCharm et CLions, entre autres. ↩
-
même s’il y a des améliorations, voir : https://pyfound.blogspot.com/2020/11/pip-20-3-new-resolver.html ↩
Comments