Pipenv: guide du nouvel outil de packaging Python
Pipenv est un outil de packaging pour Python qui résout certains problèmes courants associés au flux de travail typique utilisantpip
,virtualenv
et le bon vieuxrequirements.txt
.
En plus de résoudre certains problèmes courants, il consolide et simplifie le processus de développement en un seul outil en ligne de commande.
Ce guide passe en revue les problèmes que Pipenv résout et comment gérer vos dépendances Python avec Pipenv. De plus, il couvrira comment Pipenv s'intègre aux méthodes précédentes pour la distribution depackage.
Free Bonus:Click here to get access to a free 5-day class qui vous montre comment éviter les problèmes courants de gestion des dépendances avec des outils tels que Pip, PyPI, Virtualenv et les fichiers d'exigences.
Problèmes résolus par Pipenv
Pour comprendre les avantages de Pipenv, il est important de parcourir les méthodes actuelles de packaging et de gestion des dépendances en Python.
Commençons par une situation typique de gestion de packages tiers. Nous allons ensuite construire notre chemin vers le déploiement d'une application Python complète.
Gestion des dépendances avecrequirements.txt
Imaginez que vous travaillez sur un projet Python qui utilise un package tiers commeflask
. Vous devrez spécifier cette exigence afin que d'autres développeurs et systèmes automatisés puissent exécuter votre application.
Vous décidez donc d'inclure la dépendanceflask
dans un fichierrequirements.txt
:
flask
Très bien, tout fonctionne bien localement, et après avoir piraté votre application pendant un certain temps, vous décidez de la déplacer en production. Voici où les choses deviennent un peu effrayantes…
Le fichierrequirements.txt
ci-dessus ne spécifie pas la version deflask
à utiliser. Dans ce cas,pip install -r requirements.txt
installera la dernière version par défaut. C'est correct, sauf s'il y a des changements d'interface ou de comportement dans la dernière version qui cassent notre application.
Pour cet exemple, disons qu’une nouvelle version deflask
a été publiée. Cependant, il n'est pas rétrocompatible avec la version que vous avez utilisée pendant le développement.
Maintenant, disons que vous déployez votre application en production et faites unpip install -r requirements.txt
. Pip obtient la dernière version non rétrocompatible deflask
, et juste comme ça, votre application s'arrête… en production.
“But hey, it worked on my machine!” - J'y suis moi-même et ce n'est pas une sensation formidable.
À ce stade, vous savez que la version deflask
que vous avez utilisée pendant le développement a bien fonctionné. Donc, pour réparer les choses, vous essayez d'être un peu plus précis dans vosrequirements.txt
. Vous ajoutez unversion specifier à la dépendanceflask
. Ceci est également appelépinning une dépendance:
flask==0.12.1
L'épinglage de la dépendanceflask
à une version spécifique garantit qu'unpip install -r requirements.txt
configure la version exacte deflask
que vous avez utilisée pendant le développement. Mais est-ce vraiment le cas?
Gardez à l'esprit queflask
lui-même a également des dépendances (quepip
installe automatiquement). Cependant,flask
lui-même ne spécifie pas les versions exactes de ses dépendances. Par exemple, il autorise n'importe quelle version deWerkzeug>=0.14
.
Encore une fois, pour les besoins de cet exemple, disons qu’une nouvelle version deWerkzeug
a été publiée, mais elle introduit un bogue stoppeur dans votre application.
Lorsque vous effectuezpip install -r requirements.txt
en production cette fois, vous obtiendrezflask==0.12.1
puisque vous avez épinglé cette exigence. Cependant, malheureusement, vous obtiendrez la dernière version boguée deWerkzeug
. Encore une fois, le produit se casse dans la production.
Le vrai problème ici est quethe build isn’t deterministic. Ce que je veux dire par là, c'est que, étant donné la même entrée (le fichierrequirements.txt
), pip ne produit pas toujours le même environnement. Pour le moment, vous ne pouvez pas facilement reproduire l'environnement exact que vous avez sur votre machine de développement en production.
La solution typique à ce problème consiste à utiliserpip freeze
. Cette commande vous permet d'obtenir les versions exactes de toutes les bibliothèques tierces actuellement installées, y compris les sous-dépendances pip installées automatiquement. Vous pouvez donc tout geler en cours de développement pour vous assurer d'avoir le même environnement en production.
L'exécution depip freeze
entraîne des dépendances épinglées que vous pouvez ajouter à unrequirements.txt
:
click==6.7
Flask==0.12.1
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
Werkzeug==0.14.1
Avec ces dépendances épinglées, vous pouvez vous assurer que les packages installés dans votre environnement de production correspondent exactement à ceux de votre environnement de développement, afin que votre produit ne se casse pas de manière inattendue. Cette «solution», malheureusement, conduit à une toute nouvelle série de problèmes.
Maintenant que vous avez spécifié les versions exactes de chaque package tiers, vous êtes responsable de la mise à jour de ces versions, même si ce sont des sous-dépendances deflask
. Que faire si une faille de sécurité est découverte dansWerkzeug==0.14.1
que les responsables du package ont immédiatement corrigée dansWerkzeug==0.14.2
? Vous devez vraiment mettre à jour versWerkzeug==0.14.2
pour éviter tout problème de sécurité découlant de la version antérieure non corrigée deWerkzeug
.
Tout d'abord, vous devez savoir qu'il y a un problème avec la version que vous avez. Ensuite, vous devez obtenir la nouvelle version dans votre environnement de production avant que quelqu'un exploite le trou de sécurité. Vous devez donc modifier manuellement vosrequirements.txt
pour spécifier la nouvelle versionWerkzeug==0.14.2
. Comme vous pouvez le voir dans cette situation, la responsabilité de rester à jour avec les mises à jour nécessaires incombe à vous.
La vérité est que vous ne vous souciez vraiment pas de la version deWerkzeug
installée tant qu'elle ne rompt pas votre code. En fait, vous voulez probablement la dernière version pour vous assurer d'obtenir des corrections de bogues, des correctifs de sécurité, de nouvelles fonctionnalités, plus d'optimisation, etc.
La vraie question est:“How do you allow for deterministic builds for your Python project without gaining the responsibility of updating versions of sub-dependencies?”
Alerte spoiler: La réponse simple est d'utiliser Pipenv.
Développement de projets avec différentes dépendances
Commençons un peu pour parler d'un autre problème courant qui survient lorsque vous travaillez sur plusieurs projets. Imaginez queProjectA
a besoin dedjango==1.9
, mais queProjectB
a besoin dedjango==1.10
.
Par défaut, Python essaie de stocker tous vos packages tiers dans un emplacement à l'échelle du système. Cela signifie que chaque fois que vous souhaitez basculer entreProjectA
etProjectB
, vous devez vous assurer que la bonne version dedjango
est installée. Cela rend la transition entre les projets pénible car vous devez désinstaller et réinstaller les packages pour répondre aux exigences de chaque projet.
La solution standard consiste à utiliser unvirtual environment qui possède son propre exécutable Python et un stockage de packages tiers. De cette façon,ProjectA
etProjectB
sont correctement séparés. Vous pouvez désormais facilement basculer entre les projets, car ils ne partagent pas le même emplacement de stockage de package. PackageA
peut avoir n'importe quelle version dedjango
dont il a besoin dans son propre environnement, etPackageB
peut avoir ce dont il a besoin totalement séparé. Un outil très courant pour cela estvirtualenv
(ouvenv
en Python 3).
Pipenv a intégré la gestion de l'environnement virtuel de sorte que vous disposez d'un seul outil pour la gestion de vos packages.
Résolution des dépendances
Qu'est-ce que j'entends par résolution de dépendance? Supposons que vous ayez un fichierrequirements.txt
qui ressemble à ceci:
package_a
package_b
Disons quepackage_a
a une sous-dépendancepackage_c
, etpackage_a
nécessite une version spécifique de ce package:package_c>=1.0
. À son tour,package_b
a la même sous-dépendance mais a besoin depackage_c<=2.0
.
Idéalement, lorsque vous essayez d'installerpackage_a
etpackage_b
, l'outil d'installation examine les exigences pourpackage_c
(étant>=1.0
et<=2.0
) et sélectionne un version qui remplit ces conditions. Vous espérez que l'outil résout les dépendances pour que votre programme fonctionne à la fin. C'est ce que j'entends par «résolution de dépendance».
Malheureusement, pip lui-même n’a pas de résolution de dépendance réelle pour le moment, mais il existe unopen issue pour le prendre en charge.
La façon dont pip gérerait le scénario ci-dessus est la suivante:
-
Il installe
package_a
et recherche une version depackage_c
qui remplit la première condition (package_c>=1.0
). -
Pip installe ensuite la dernière version de
package_c
pour répondre à cette exigence. Supposons que la dernière version depackage_c
soit 3.1.
C'est là que le problème commence (potentiellement).
Si la version depackage_c
sélectionnée par pip ne répond pas aux exigences futures (telles quepackage_b
nécessitantpackage_c<=2.0
), l'installation échouera.
La «solution» à ce problème est de spécifier la plage requise pour la sous-dépendance (package_c
) dans le fichierrequirements.txt
. De cette façon, pip peut résoudre ce conflit et installer un package qui répond à ces exigences:
package_c>=1.0,<=2.0
package_a
package_b
Comme avant, vous vous préoccupez maintenant directement des sous-dépendances (package_c
). Le problème avec ceci est que sipackage_a
modifie son exigence sans que vous le sachiez, les exigences que vous avez spécifiées (package_c>=1.0,<=2.0
) peuvent ne plus être acceptables et l'installation peut échouer… à nouveau. Le vrai problème est qu'une fois de plus, vous êtes responsable de rester à jour avec les exigences des sous-dépendances.
Idéalement, votre outil d'installation serait suffisamment intelligent pour installer des packages répondant à toutes les exigences sans que vous spécifiiez explicitement les versions de sous-dépendance.
Présentation de Pipenv
Maintenant que nous avons résolu les problèmes, voyons comment Pipenv les résout.
Commençons par l'installer:
$ pip install pipenv
Une fois que vous avez fait cela, vous pouvez effectivement oublierpip
puisque Pipenv agit essentiellement comme un remplaçant. Il introduit également deux nouveaux fichiers, lePipfile
(qui est censé remplacerrequirements.txt
) et lePipfile.lock
(qui permet des constructions déterministes).
Pipenv utilise lespip
etvirtualenv
sous le capot mais simplifie leur utilisation avec une interface de ligne de commande unique.
Exemple d'utilisation
Commençons par créer votre superbe application Python. Tout d'abord, créez un shell dans un environnement virtuel pour isoler le développement de cette application:
$ pipenv shell
Cela créera un environnement virtuel s'il n'en existe pas déjà. Pipenv crée tous vos environnements virtuels dans un emplacement par défaut. Si vous souhaitez modifier le comportement par défaut de Pipenv, il existe desenvironmental variables for configuration.
Vous pouvez forcer la création d'un environnement Python 2 ou 3 avec les arguments--two
et--three
respectivement. Sinon, Pipenv utilisera tout ce quevirtualenv
trouve par défaut.
Remarque: si vous avez besoin d'une version plus spécifique de Python, vous pouvez fournir un argument
--python
avec la version dont vous avez besoin. Par exemple:--python 3.6
Vous pouvez maintenant installer le package tiers dont vous avez besoin,flask
. Oh, mais vous savez que vous avez besoin de la version0.12.1
et non de la dernière version, alors allez-y et soyez précis:
$ pipenv install flask==0.12.1
Vous devriez voir quelque chose comme ceci dans votre terminal:
Adding flask==0.12.1 to Pipfile's [packages]...
Pipfile.lock not found, creating...
Vous remarquerez que deux fichiers sont créés, unPipfile
etPipfile.lock
. Nous allons les examiner de plus près dans une seconde. Installons un autre package tiers,numpy
, pour quelques calculs. Vous n'avez pas besoin d'une version spécifique, alors n'en spécifiez pas:
$ pipenv install numpy
Si vous souhaitez installer quelque chose directement à partir d'un système de contrôle de version (VCS), vous pouvez! Vous spécifiez les emplacements de la même manière que vous le feriez avecpip
. Par exemple, pour installer la bibliothèquerequests
à partir du contrôle de version, procédez comme suit:
$ pipenv install -e git+https://github.com/requests/requests.git#egg=requests
Notez l'argument-e
ci-dessus pour rendre l'installation modifiable. Actuellement,this is required pour que Pipenv effectue la résolution des sous-dépendances.
Supposons que vous ayez également des tests unitaires pour cette application géniale et que vous souhaitiez utiliserpytest
pour les exécuter. Vous n’avez pas besoin depytest
en production, vous pouvez donc spécifier que cette dépendance est uniquement destinée au développement avec l’argument--dev
:
$ pipenv install pytest --dev
Fournir l'argument--dev
placera la dépendance dans un emplacement spécial[dev-packages]
dans lesPipfile
. Ces packages de développement ne sont installés que si vous spécifiez l'argument--dev
avecpipenv install
.
Les différentes sections séparent les dépendances nécessaires uniquement au développement de celles nécessaires au fonctionnement réel du code de base. En règle générale, cela serait accompli avec des fichiers d'exigences supplémentaires tels quedev-requirements.txt
outest-requirements.txt
. Maintenant, tout est consolidé dans un seulPipfile
sous différentes sections.
D'accord, alors supposons que tout fonctionne dans votre environnement de développement local et que vous êtes prêt à le mettre en production. Pour ce faire, vous devez verrouiller votre environnement afin de vous assurer d'avoir le même en production:
$ pipenv lock
Cela créera / mettra à jour vosPipfile.lock
, que vous n’aurez jamais besoin de modifier manuellement. Vous devez toujours utiliser le fichier généré.
Maintenant, une fois que vous avez obtenu votre code etPipfile.lock
dans votre environnement de production, vous devez installer le dernier environnement réussi enregistré:
$ pipenv install --ignore-pipfile
Cela indique à Pipenv d'ignorer lesPipfile
pour l'installation et d'utiliser ce qui se trouve dans lesPipfile.lock
. Compte tenu de cesPipfile.lock
, Pipenv créera exactement le même environnement que celui que vous aviez lorsque vous avez exécutépipenv lock
, les sous-dépendances et tout.
Le fichier de verrouillage permet des constructions déterministes en prenant un instantané de toutes les versions des packages dans un environnement (similaire au résultat d'unpip freeze
).
Supposons maintenant qu'un autre développeur souhaite apporter quelques ajouts à votre code. Dans cette situation, ils obtiendraient le code, y compris lesPipfile
, et utiliseraient cette commande:
$ pipenv install --dev
Cela installe toutes les dépendances nécessaires au développement, qui incluent à la fois les dépendances régulières et celles que vous avez spécifiées avec l'argument--dev
pendantinstall
.
Lorsqu'une version exacte n'est pas spécifiée dans le Pipfile, la commande
install
donne la possibilité aux dépendances (et sous-dépendances) de mettre à jour leurs versions.
Ceci est une note importante car elle résout certains des problèmes précédents dont nous avons discuté. Pour le démontrer, supposons qu'une nouvelle version de l'une de vos dépendances devienne disponible. Comme vous n'avez pas besoin d'une version spécifique de cette dépendance, vous ne spécifiez pas de version exacte dans lesPipfile
. Lorsque vouspipenv install
, la nouvelle version de la dépendance sera installée dans votre environnement de développement.
Maintenant, vous apportez vos modifications au code et exécutez des tests pour vérifier que tout fonctionne toujours comme prévu. (Vous avez des tests unitaires, non?) Maintenant, comme avant, vous verrouillez votre environnement avecpipenv lock
, et unPipfile.lock
mis à jour sera généré avec la nouvelle version de la dépendance. Comme précédemment, vous pouvez répliquer ce nouvel environnement en production avec le fichier de verrouillage.
Comme vous pouvez le voir dans ce scénario, vous n'avez plus à forcer les versions exactes dont vous n'avez pas vraiment besoin pour vous assurer que vos environnements de développement et de production sont les mêmes. Vous n'avez pas non plus besoin de vous tenir au courant de la mise à jour des sous-dépendances dont vous "ne vous souciez pas". Ce flux de travail avec Pipenv, combiné à vos excellents tests, résout les problèmes de faire manuellement toute votre gestion des dépendances.
Approche de résolution des dépendances de Pipenv
Pipenv tentera d'installer des sous-dépendances qui satisfont à toutes les exigences de vos dépendances principales. Cependant, s'il existe des dépendances conflictuelles (package_a
a besoin depackage_c>=1.0
, maispackage_b
a besoin depackage_c<1.0
), Pipenv ne pourra pas créer un fichier de verrouillage et affichera une erreur comme ce qui suit:
Warning: Your dependencies could not be resolved. You likely have a mismatch in your sub-dependencies. You can use $ pipenv install --skip-lock to bypass this mechanism, then run $ pipenv graph to inspect the situation. Could not find a version that matches package_c>=1.0,package_c<1.0
Comme le dit l'avertissement, vous pouvez également afficher un graphique de dépendance pour comprendre vos dépendances de niveau supérieur et leurs sous-dépendances:
$ pipenv graph
Cette commande imprimera une structure arborescente montrant vos dépendances. Voici un exemple:
Flask==0.12.1 - click [required: >=2.0, installed: 6.7] - itsdangerous [required: >=0.21, installed: 0.24] - Jinja2 [required: >=2.4, installed: 2.10] - MarkupSafe [required: >=0.23, installed: 1.0] - Werkzeug [required: >=0.7, installed: 0.14.1] numpy==1.14.1 pytest==3.4.1 - attrs [required: >=17.2.0, installed: 17.4.0] - funcsigs [required: Any, installed: 1.0.2] - pluggy [required: <0.7,>=0.5, installed: 0.6.0] - py [required: >=1.5.0, installed: 1.5.2] - setuptools [required: Any, installed: 38.5.1] - six [required: >=1.10.0, installed: 1.11.0] requests==2.18.4 - certifi [required: >=2017.4.17, installed: 2018.1.18] - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4] - idna [required: >=2.5,<2.7, installed: 2.6] - urllib3 [required: <1.23,>=1.21.1, installed: 1.22]
À partir de la sortie depipenv graph
, vous pouvez voir les dépendances de niveau supérieur que nous avons installées précédemment (Flask
,numpy
,pytest
etrequests
), et en dessous vous pouvez voir les packages dont ils dépendent.
De plus, vous pouvez inverser l'arborescence pour afficher les sous-dépendances avec le parent qui l'exige:
$ pipenv graph --reverse
Cet arbre inversé peut être plus utile lorsque vous essayez de comprendre des sous-dépendances conflictuelles.
Le Pipfile
Pipfile a l'intention de remplacerrequirements.txt
. Pipenv est actuellement l'implémentation de référence pour l'utilisation dePipfile
. Il semble très probable quepip
itself will be able to handle these files. En outre, il convient de noter quePipenv is even the official package management tool recommended by Python itself.
La syntaxe desPipfile
estTOML et le fichier est séparé en sections. [dev-packages]
pour les packages de développement uniquement,[packages]
pour les packages minimum requis, et[requires]
pour d'autres exigences comme une version spécifique de Python. Voir un exemple de fichier ci-dessous:
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[dev-packages]
pytest = "*"
[packages]
flask = "==0.12.1"
numpy = "*"
requests = {git = "https://github.com/requests/requests.git", editable = true}
[requires]
python_version = "3.6"
Idéalement, vous ne devriez pas avoir de sous-dépendances dans vosPipfile
. Ce que je veux dire par là, c'est que vous ne devez inclure que les packages que vous importez et utilisez réellement. Inutile de conserverchardet
dans votrePipfile
simplement parce qu’il s’agit d’une sous-dépendance derequests
. (Pipenv l'installera automatiquement.) LesPipfile
devraient transmettre les dépendances de niveau supérieur requises par votre paquet.
Le Pipfile.lock
Ce fichier permet des constructions déterministes en spécifiant les exigences exactes pour reproduire un environnement. Il contient des versions exactes des packages et des hachages pour prendre en charge une vérification plus sécurisée, quipip
itself now supports également. Un exemple de fichier pourrait ressembler à ce qui suit. Notez que la syntaxe de ce fichier est JSON et que j'ai exclu des parties du fichier avec...
:
{
"_meta": {
...
},
"default": {
"flask": {
"hashes": [
"sha256:6c3130c8927109a08225993e4e503de4ac4f2678678ae211b33b519c622a7242",
"sha256:9dce4b6bfbb5b062181d3f7da8f727ff70c1156cbb4024351eafd426deb5fb88"
],
"version": "==0.12.1"
},
"requests": {
"editable": true,
"git": "https://github.com/requests/requests.git",
"ref": "4ea09e49f7d518d365e7c6f7ff6ed9ca70d6ec2e"
},
"werkzeug": {
"hashes": [
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b",
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c"
],
"version": "==0.14.1"
}
...
},
"develop": {
"pytest": {
"hashes": [
"sha256:8970e25181e15ab14ae895599a0a0e0ade7d1f1c4c8ca1072ce16f25526a184d",
"sha256:9ddcb879c8cc859d2540204b5399011f842e5e8823674bf429f70ada281b3cc6"
],
"version": "==3.4.1"
},
...
}
}
Notez la version exacte spécifiée pour chaque dépendance. Même les sous-dépendances commewerkzeug
qui ne sont pas dans nosPipfile
apparaissent dans cePipfile.lock
. Les hachages sont utilisés pour garantir que vous récupérez le même package que lors du développement.
Il convient de noter à nouveau que vous ne devez jamais modifier ce fichier à la main. Il est destiné à être généré avecpipenv lock
.
Fonctionnalités supplémentaires de Pipenv
Ouvrez un package tiers dans votre éditeur par défaut avec la commande suivante:
$ pipenv open flask
Cela ouvrira le packageflask
dans l'éditeur par défaut, ou vous pouvez spécifier un programme avec une variable d'environnementEDITOR
. Par exemple, j'utiliseSublime Text, donc je viens de définirEDITOR=subl
. Il est donc très simple de fouiller dans les éléments internes d'un package que vous utilisez.
Vous pouvez exécuter une commande dans l'environnement virtuel sans lancer de shell:
$ pipenv run
Recherchez les vulnérabilités de sécurité (et les exigences dePEP 508) dans votre environnement:
$ pipenv check
Supposons maintenant que vous n'ayez plus besoin d'un package. Vous pouvez le désinstaller:
$ pipenv uninstall numpy
De plus, supposons que vous souhaitiez effacer complètement tous les packages installés de votre environnement virtuel:
$ pipenv uninstall --all
Vous pouvez remplacer--all
par--all-dev
pour simplement supprimer les packages de développement.
Pipenv prend en charge le chargement automatique des variables d'environnement lorsqu'un fichier.env
existe dans le répertoire de niveau supérieur. De cette façon, lorsque vouspipenv shell
pour ouvrir l'environnement virtuel, il charge vos variables d'environnement à partir du fichier. Le fichier.env
ne contient que des paires clé-valeur:
SOME_ENV_CONFIG=some_value
SOME_OTHER_ENV_CONFIG=some_other_value
Enfin, voici quelques commandes rapides pour savoir où se trouvent les choses. Comment savoir où se trouve votre environnement virtuel:
$ pipenv --venv
Comment savoir où se trouve votre maison de projet:
$ pipenv --where
Distribution de colis
Vous vous demandez peut-être comment tout cela fonctionne si vous avez l'intention de distribuer votre code sous forme de package.
Oui, je dois distribuer mon code sous forme de package
Comment Pipenv fonctionne-t-il avec les fichierssetup.py
?
Il y a beaucoup de nuances à cette question. Tout d'abord, un fichiersetup.py
est nécessaire lorsque vous utilisezsetuptools
comme système de construction / distribution. C'est la norme de facto depuis un certain temps maintenant, maisrecent changes a rendu l'utilisation desetuptools
facultative.
Cela signifie que les projets commeflit peuvent utiliser les nouveauxpyproject.toml
pour spécifier un système de construction différent qui ne nécessite pas desetup.py
.
Cela étant dit, dans un proche avenir,setuptools
et unsetup.py
qui l'accompagne resteront le choix par défaut pour de nombreuses personnes.
Voici un flux de travail recommandé lorsque vous utilisez unsetup.py
pour distribuer votre package:
-
setup.py
-
Le mot clé
install_requires
doit inclure le package“minimally needs to run correctly.” -
Pipfile
-
Représente les exigences concrètes de votre colis
-
Extrayez les dépendances minimales requises de
setup.py
en installant votre package à l'aide de Pipenv:-
Utilisez
pipenv install '-e .'
-
Cela se traduira par une ligne dans vos
Pipfile
qui ressemble à quelque chose comme"e1839a8" = {path = ".", editable = true}
.
-
-
Pipfile.lock
-
Détails pour un environnement reproductible généré à partir de
pipenv lock
Pour clarifier, mettez vos exigences minimales ensetup.py
au lieu de directement avecpipenv install
. Utilisez ensuite la commandepipenv install '-e .'
pour installer votre package comme modifiable. Cela obtient toutes les exigences desetup.py
dans votre environnement. Ensuite, vous pouvez utiliserpipenv lock
pour obtenir un environnement reproductible.
Je n'ai pas besoin de distribuer mon code sous forme de package
Génial! Si vous développez une application qui n’est pas destinée à être distribuée ou installée (un site Web personnel, une application de bureau, un jeu ou similaire), vous n’avez pas vraiment besoin d’unsetup.py
.
Dans cette situation, vous pouvez utiliser la combinaisonPipfile
/Pipfile.lock
pour gérer vos dépendances avec le flux décrit précédemment pour déployer un environnement reproductible en production.
J'ai déjà unrequirements.txt
. Comment puis-je convertir enPipfile
?
Si vous exécutezpipenv install
, il devrait détecter automatiquement lesrequirements.txt
et les convertir enPipfile
, en produisant quelque chose comme ce qui suit:
requirements.txt found, instead of Pipfile! Converting… Warning: Your Pipfile now contains pinned versions, if your requirements.txt did. We recommend updating your Pipfile to specify the "*" version, instead.
Prenez note de l'avertissement ci-dessus.
Si vous avez épinglé des versions exactes dans votre fichierrequirements.txt
, vous souhaiterez probablement modifier vosPipfile
pour ne spécifier que les versions exactes dont vous avez vraiment besoin. Cela vous permettra de bénéficier des avantages réels de la transition. Par exemple, supposons que vous disposez des éléments suivants, mais que vous n’avez pas vraiment besoin de la version exacte denumpy
:
[packages]
numpy = "==1.14.1"
Si vous n'avez pas d'exigences de version spécifiques pour vos dépendances, vous pouvez utiliser le caractère générique*
pour indiquer à Pipenv que n'importe quelle version peut être installée:
[packages]
numpy = "*"
Si vous vous sentez nerveux à l'idée d'autoriser une version avec les*
, il est généralement prudent de spécifier une version supérieure ou égale à la version sur laquelle vous vous trouvez déjà afin de pouvoir toujours profiter des nouvelles versions:
[packages]
numpy = ">=1.14.1"
Bien sûr, rester à jour avec les nouvelles versions signifie également que vous êtes responsable de vous assurer que votre code fonctionne toujours comme prévu lorsque les packages changent. Cela signifie qu'une suite de tests est essentielle à l'ensemble de ce flux Pipenv si vous souhaitez garantir le bon fonctionnement des versions de votre code.
Vous autorisez les packages à se mettre à jour, exécutez vos tests, assurez-vous qu'ils réussissent tous, verrouillez votre environnement, puis vous pouvez rester tranquille en sachant que vous n'avez pas introduit de changements de rupture. Si les choses se cassent à cause d'une dépendance, vous avez des tests de régression à écrire et potentiellement plus de restrictions sur les versions des dépendances.
Par exemple, sinumpy==1.15
est installé après l'exécution depipenv install
et qu'il casse votre code, ce que vous remarquerez, espérons-le, pendant le développement ou pendant vos tests, vous avez quelques options:
-
Mettez à jour votre code pour qu'il fonctionne avec la nouvelle version de la dépendance.
Si la rétrocompatibilité avec les versions précédentes de la dépendance n'est pas possible, vous devrez également remplacer la version requise dans vos
Pipfile
:[packages] numpy = ">=1.15"
-
Restreignez la version de la dépendance dans les
Pipfile
à<
la version qui vient de casser votre code:[packages] numpy = ">=1.14.1,<1.15"
L'option 1 est préférée car elle garantit que votre code utilise les dépendances les plus à jour. Cependant, l'option 2 prend moins de temps et ne nécessite pas de modifications de code, juste des restrictions sur les dépendances.
Vous pouvez également installer à partir de fichiers d'exigences avec le même argument-r
quepip
prend:
$ pipenv install -r requirements.txt
Si vous avez undev-requirements.txt
ou quelque chose de similaire, vous pouvez également les ajouter auxPipfile
. Ajoutez simplement l'argument--dev
pour qu'il soit placé dans la bonne section:
$ pipenv install -r dev-requirements.txt --dev
De plus, vous pouvez aller dans l'autre sens et générer des fichiers d'exigences à partir d'unPipfile
:
$ pipenv lock -r > requirements.txt
$ pipenv lock -r -d > dev-requirements.txt
Et après?
Il me semble qu'une progression naturelle pour l'écosystème Python serait un système de construction qui utilise lesPipfile
pour installer les dépendances minimales requises lors de la récupération et de la construction d'un package à partir d'un index de package (comme PyPI). Il est important de noter à nouveau que lePipfile design specification est toujours en développement et que Pipenv n'est qu'une implémentation de référence.
Cela étant dit, je pourrais voir un futur où la sectioninstall_requires
desetup.py
n’existe pas, et où lePipfile
est référencé pour des exigences minimales à la place. Ou lesetup.py
a complètement disparu, et vous obtenez des métadonnées et d'autres informations d'une manière différente, en utilisant toujours lesPipfile
pour obtenir les dépendances nécessaires.
Est-ce que Pipenv vaut le détour?
Absolument. Même s'il s'agit simplement d'un moyen de consolider les outils que vous utilisez déjà (pip
&virtualenv
) dans une seule interface. Mais c’est beaucoup plus que cela. Avec l'ajout desPipfile
, vous ne spécifiez que les dépendances dont vous avez vraiment besoin.
Vous n'avez plus le mal de tête de gérer vous-même les versions de tout pour vous assurer de pouvoir répliquer votre environnement de développement. Avec lesPipfile.lock
, vous pouvez développer l'esprit tranquille en sachant que vous pouvez reproduire exactement votre environnement n'importe où.
En plus de tout cela, il semble très probable que le formatPipfile
sera adopté et pris en charge par des outils Python officiels commepip
, il serait donc avantageux d'être en avance sur le jeu. Oh, et assurez-vous également de mettre à jour tout votre code vers Python 3:2020 is coming up fast.
Références, lectures complémentaires, discussions intéressantes, etc.
Free Bonus:Click here to get access to a free 5-day class qui vous montre comment éviter les problèmes courants de gestion des dépendances avec des outils tels que Pip, PyPI, Virtualenv et les fichiers d'exigences.