Piratage de maya
J'ai appris quelques leçons qui ont abouti à ma proposition suivante d'utilisation recommandée de pipenv
dans les bibliothèques python. Je m'attends à ce que d'autres examinent la proposition et si nous parvenons à un accord, le texte (mis à jour) pourrait se retrouver dans des documents pipenv
.
pipenv
modèles et anti-modèles pour le projet de bibliothèque pythonÉDITER
Ce qui suit s'applique le mieux aux bibliothèques python générales (principalement Open Source), qui sont censées s'exécuter sur différentes versions de python et systèmes d'exploitation. Les bibliothèques développées dans un environnement d'entreprise strict peuvent être des cas différents (n'oubliez pas de consulter toutes les sections Problèmes de toute façon).
FIN DE MODIFICATION
TL;DR : L'ajout pipenv
fichiers gardez Pipfile
, Pipfile.lock
et .env
hors du contrôle des sources de la bibliothèque.
Vous pourrez utiliser toute la puissance de pipenv
quels que soient les fichiers résidant dans .gitignore
.
Par bibliothèque python setup.py
, ciblé pour la distribution et l'utilisation sur diverses plates-formes différant par la version python et/ou le système d'exploitation.
Exemples : maya
, requests
, flask
etc.
De l'autre côté (pas de bibliothèque python), il existe des applications ciblées pour un interpréteur python spécifique, un système d'exploitation et souvent déployées dans un environnement strictement cohérent.
pipfile
décrit très bien ces différences dans Pipfile vs setup.py .
pipenv
(outil de déploiement)Je suis tout à fait d'accord sur l'affirmation selon laquelle pipenv
est un outil de déploiement car il permet de :
Pipfile.lock
) pour le déploiement de l'environnement virtuelCela aide lorsque l'on doit déployer une application ou développer dans un environnement python très cohérent entre plusieurs développeurs.
Appeler l'outil de packaging pipenv
est trompeur si l'on s'attend à ce qu'il crée des bibliothèques python ou qu'il soit profondément impliqué dans leur création. Oui, pipenv
peut aider beaucoup (dans le développement local de bibliothèques) mais peut éventuellement nuire (souvent dans les tests CI lorsqu'il est utilisé sans réflexion approfondie).
TL;DR : pipenv
fournit un environnement sécurisé via l' application de dépendances concrètes approuvées décrites dans le fichier Pipfile.lock
et la bibliothèque python est uniquement autorisée à définir des dépendances abstraites (ne peut donc pas fournir Pipfile.lock
).
pipenv
brille dans les scénarios de déploiement en suivant ces étapes :
Pipfile
)Pipfile.lock
Pipfile.lock
comme définition de l'environnement python approuvépipenv sync
pour appliquer "l'or" Pipfile.lock
ailleurs en obtenant un environnement python identique.Avec le développement de la bibliothèque python, on ne peut pas atteindre une telle sécurité, car les bibliothèques ne doivent pas définir de dépendances concrètes . Le non-respect de cette règle (en essayant ainsi de déclarer des dépendances concrètes par la bibliothèque python) entraîne des problèmes tels que :
setup.py
briséessetup.py
doit définir toutes les dépendances abstraites via install_requires
.
Si Pipfile
définit également ces dépendances, cela peut facilement masquer des problèmes tels que :
install_requires
Pipfile
définit des règles spécifiques (plages de versions, etc.) pour une dépendance et pas install_requires
.Pour l'éviter, suivez ces règles :
Pipfile
[packages]
dans Pipfile
doit être soit vide, soit définir une seule dépendance sur la bibliothèque elle-même.Pipfile.lock
dans le référentielConserver Pipfile.lock
(généralement pour des « raisons de sécurité ») dans le référentiel de la bibliothèque est incorrect, car :
Pour l'éviter, il faut :
Pipfile.lock
du référentiel et ajoutez-le dans .gitignore
tox
(cacher usedevelop
)Si tox.ini
contient dans sa section commands
entrées telles que :
pipenv install
pipenv install --dev
pipenv lock
c'est souvent un problème, car :
pipenv install
n'installera que la bibliothèque elle-même, et tox
fait (par défaut) aussi. En dehors de la duplicité, cela empêche également usedevelop=True
et usedevelop=False
dans tox.ini
car Pipenv
ne peut l'exprimer que dans une variante (et tox.ini
permet des différences dans différents environnements).Pour l'éviter, il faut :
pipenv
dans tox.ini
. Voir les demandes tox.inipipenv
échouepipenv
est en cours de développement et les choses se cassent parfois. Si un tel problème casse votre build CI, il y a un échec qui pourrait être évité en n'utilisant pas pipenv
et en utilisant des outils traditionnels (qui sont souvent un peu plus matures).
Pour l'éviter, il faut :
pipenv
dans un script de construction CI, tox.ini
ou un endroit similaire. Savez-vous quelle valeur vous obtenez en l'ajoutant? Le travail pourrait-il être fait avec l'outillage existant?Les questions clés concernant le rôle de pipenv
dans le développement de la bibliothèque Python sont :
pipenv
apporte vraiment ? R : Outil de gestion Virtualenv.pipenv
? R : Gérer virtualenv.Quelques autres détails et astuces suivent.
pipenv
n'ajoutera aucune sécurité à votre forfaitNe le poussez pas dans le projet simplement parce que tout le monde le fait ou parce que vous attendez une sécurité supplémentaire. Cela vous décevra.
La sécurisation à l'aide de dépendances concrètes (et approuvées) aura lieu dans une phase ultérieure dans l'application qui va utiliser votre bibliothèque.
Pipfile
, Pipfile.lock
et .env
hors du référentielMettez les fichiers dans .gitignore
.
Pipfile
est facile à recréer comme démontré ci-dessous car la plupart ou toutes les exigences sont déjà définies dans votre setup.py
. Et le fichier .env
contient probablement des informations privées, qui ne doivent pas être partagées.
Garder ces fichiers hors du référentiel évitera tous les problèmes qui peuvent survenir avec les builds CI lors de l'utilisation de pipenv
dans des situations qui ne sont pas appropriées.
pipenv
comme boîte à outils privée du développeurpipenv
peut simplifier le travail du développeur en tant qu'outil de gestion de virtualenv.
L'astuce consiste à apprendre comment recréer rapidement vos fichiers associés (privés) pipenv
, par exemple :
$ cd <project_repository>
$ # your library will bring the dependencies (via install_requires in setup.py)
$ pipenv install -e .
$ # add more dev tools you preffer
$ pipenv install --dev ipython pdbpp
$ # start hacking
$ pipenv shell
...
Utilisez le fichier .env
si vous avez besoin d'une méthode pratique pour configurer les variables d'environnement.
N'oubliez pas : gardez l'utilisation de pipenv
hors de vos builds CI et votre vie sera plus simple.
setup.py
pour déclarer des dépendances supplémentairesDans votre setup.py
utilisez la section extras_requires
:
from setuptools import setup
setup(
name='mypackage',
....,
install_requires=["jinja2", "simplejson"],
extras_require={
'tests': ['pytest', 'pyyaml'],
'pg': ['psycopg2'],
},
....
)
Pour installer toutes les dépendances déclarées pour tests
supplémentaires :
$ pipenv install -e .[tests]
Notez qu'il inclura toujours les dépendances install_requires
.
Cette méthode ne permet pas de diviser les dépendances en sections par défaut et dev, mais cela ne doit pas poser de réel problème dans les scénarios attendus.
C'est très impressionnant, merci beaucoup pour la compilation. Je vais certainement revoir plus en détail dans un peu
/cc @uranusjr @jtratner @ncoghlan
Quelques références à des problèmes de maya
:
pendulum>=1.0
dans setup.py : la version était dans Pipfile mais manquait dans setup.py)pipenv
cassé toute la course de Travis)J'aime ça aussi. Peut-être devrions-nous ajouter cela à la documentation de Pipenv, ou même au Python Packaging User Guide .
Le corollaire du conseil ci-dessus semble être "renoncer aux constructions d'IC déterministes/reproductibles", ce qui me semble être un très grand anti-modèle.
Que proposez-vous comme alternative qui permettrait encore le déterminisme ?
@tsiq-oliverc Les builds déterministes ont leur place en ce moment, une application est à construire.
Imaginez la tentative suivante d'effectuer des constructions vraiment déterministes de la bibliothèque python :
Pipfile.lock
Pipfile.lock
résultant des dépendances abstraites de la bibliothèque définies dans Pipfile
Pipfile.lock
distinctes définies dans le référentiel. Notez que la construction automatique de Pipfile.lock
lors de la construction de CI n'ajoute aucun déterminismeC'est beaucoup d'efforts supplémentaires. Et ce que vous obtenez est une bibliothèque, qui sera installée dans un contexte différent (par exemple, une semaine plus tard, l'installation standard prendra une dépendance mise à niveau ou deux) et qui n'obtiendra rien du fait que vous avez utilisé Pipfile.lock
, qui est pour le moment obsolète.
Le conflit réside dans le fait que la bibliothèque ne doit jamais définir de dépendances strictes à l'intérieur.
Si vous pensez qu'il existe une autre alternative pour obtenir des constructions déterministes pour la bibliothèque python - décrivez-la.
@vlcinsky - Si un consommateur de votre bibliothèque utilise différentes versions de dépendances, etc., cela est hors de votre contrôle. Je suis donc d'accord qu'il n'y a aucun moyen possible pour un mainteneur de bibliothèque de gérer cela.
Mais l'objectif ici est vraisemblablement d'une portée beaucoup plus petite. En particulier, je considérerais les objectifs d'un mainteneur de bibliothèque comme les suivants (qui sont à peu près des équivalences) :
Si l'une de ces trois choses ne tient pas, cela me semble contraire au contrôle qualité.
Alors oui, je dirais que si vous garantissez la prise en charge des variantes Python A, B et C à votre consommateur, et qu'elles se comportent suffisamment différemment pour qu'un fichier de verrouillage (etc.) ne le coupe pas, alors vous devriez avoir trois fichiers de verrouillage (ou peu importe).
Cependant, je n'ai pas assez utilisé Pipenv pour savoir à quel point ce serait facile dans la pratique.
J'envisage actuellement d'ajouter des Pipfile
s à quelques projets de bibliothèque pour le système CI également.
J'ai absolument besoin du verrouillage des dépendances (+ hachage) pour me conformer aux directives de sécurité à l'échelle de l'entreprise et je n'ai actuellement pas besoin de tester avec différentes versions de Python, car il n'y en a qu'une qui est officiellement prise en charge. Et le fait que pipenv simplifie la configuration d'un environnement de développement local, y compris virtualenv, est un bel effet secondaire.
Et ce que vous obtenez est une bibliothèque, qui sera installée dans un contexte différent (par exemple, une semaine plus tard, l'installation standard récupérera une dépendance mise à niveau ou deux) et qui n'obtiendra rien du fait que vous avez utilisé
Pipfile.lock
, qui est pour le moment obsolète.
Ce n'est pas universellement vrai. Dans le monde des logiciels d'entreprise, vous avez toujours des environnements très spécifiques qui sont officiellement pris en charge et un problème de sécurité dans une dépendance entraîne la mise à jour de votre produit plutôt que la mise à jour de la dépendance par le client lui-même.
(Oui, je parle d'une bibliothèque, pas d'une application ici...)
@ Moritz90, votre scénario concerne la bibliothèque python dans un environnement d'entreprise et pipenv
peut aider car il s'agit d'un environnement beaucoup plus déterministe.
Ma description vise les bibliothèques python générales telles que flask
, request
, maya
etc. où le contexte est beaucoup plus variable. En essayant de résoudre quelques problèmes dans maya
j'ai été frustré d'apprendre que, dans de nombreux cas, l'utilisation de pipenv
introduisait de vrais problèmes (cachant généralement des problèmes qui seraient normalement détectés) tout en n'apportant pas grand-chose ni aucun ajout valeur.
Obtenir des builds déterministes est une bonne chose, mais cela entraîne des coûts. Et si c'est mal fait, vous pouvez payer un supplément pour un résultat de qualité inférieure - et c'est ce que je voulais éviter.
Je dirais que c'est l'un des cas où nous ne voulons pas que les versions soient absolument déterministes. Si vous n'épinglez pas vos dépendances avec ==
, vous vous engagez à maintenir la prise en charge de plusieurs versions par défaut et devez concevoir la bibliothèque de cette façon. Une mise à niveau de dépendance interrompant la construction sur CI est en fait une bonne chose car elle expose un bogue dans la bibliothèque. Des dépendances complètement déterministes (telles que gérées par Pipenv) masqueraient cela. Il serait quand même avantageux de pouvoir être déterministe quand on le veut, ce n'est généralement pas le mieux.
@uranusjr - Bien sûr. Je suis d'accord que si le désir est "des constructions non déterministes", alors le conseil en haut peut bien avoir du sens. En fait, c'est presque une équivalence logique, et on pourrait l'énoncer beaucoup plus succinctement : "Si vous ne voulez pas de builds déterministes, alors n'utilisez pas d'outil ( pipenv
) dont le but est d'assurer des builds déterministes" .
Mais ce n'est certainement pas un objectif souhaitable en général.
@tsiq-oliverc belle définition de la portée - il prend en charge une discussion ciblée. J'ajouterais une autre exigence : le déterminisme CI ne doit pas masquer les problèmes possibles au sein de la bibliothèque testée.
Si nous utilisons Pipenv.lock
, créons virtualenv sur cette base et exécutons le test CI de la bibliothèque, nous avons fait une partie de la fonctionnalité que la bibliothèque est censée faire - installer les dépendances appropriées. Si la bibliothèque est en quelque sorte cassée à cet égard, l'environnement préinstallé masquerait ce problème.
Il me semble plus important de détecter les problèmes au sein d'une bibliothèque que d'exécuter CI de manière déterministe. S'il existe un moyen de faire les deux (par exemple, exécuter le test derrière l'index pypi privé, qui pourrait également prendre en charge le déterminisme), je n'ai aucun problème, mais s'il y a un conflit, j'ai mes priorités.
Ne vous méprenez pas : il n'y a aucun désir d'exécuter des builds non déterministes, mon désir est d'exécuter des builds CI, qui détecteront autant de problèmes que possible.
@vlcinsky Bien sûr, je voulais juste partager mon expérience pour m'assurer que la documentation mise à jour le reflète également. La documentation actuelle explique très bien les compromis :
Pour les bibliothèques, définissez les dépendances abstraites via install_requires dans setup.py. [...]
Pour les applications, définissez les dépendances et où les obtenir dans le Pipfile et utilisez ce fichier pour mettre à jour l'ensemble des dépendances concrètes dans Pipfile.lock. [...]
Bien sûr, Pipfile et pipenv sont toujours utiles pour les développeurs de bibliothèques, car ils peuvent être utilisés pour définir un environnement de développement ou de test.
Et, bien sûr, il y a des projets pour lesquels la distinction entre bibliothèque et application n'est pas si claire.
(Souligné la partie qui s'applique dans mon cas.)
Je veux juste m'assurer que ça reste comme ça. Je pense que votre message d'origine contient trop de déclarations générales sans avertissement selon lequel vous parlez d'un projet open source qui va être publié sur PyPI.
@ Moritz90 Je suis tout à fait d'accord. J'essayais de mettre en évidence cet objectif, mais je peux le rendre encore plus visible.
@ Moritz90 J'ai ajouté une note d'introduction reflétant votre commentaire.
@vlcinsky - Cela a du sens. Je comprends que vous n'avez pas explicitement voulez construit non-déterministe, mais je pense qu'il est inéluctablement équivalent à ce que vous voulez ( par exemple à des problèmes de capture lorsque la mise à jour vos dépendances en amont).
En réfléchissant à voix haute, quelle est la meilleure façon de résoudre ces deux objectifs contradictoires ? Une possibilité est d'avoir un processus d'IC en deux phases :
Pipfile.lock
dans votre repo, il est donc entièrement reproductible.pipenv update
puis exécute les tests, de sorte qu'il récupère la dernière de toutes vos dépendances (ce qui est fondamentalement le même que le comportement sans fichier de verrouillage, je pense?).@tsiq-oliverc Pour obtenir des versions déterministes, je penserais à la configuration suivante :
pipenv
Utiliser pipenv
pour effectuer l'installation est similaire à ce que l'installation de la bibliothèque elle-même doit faire, mais c'est définitivement différent car c'est un code différent qui fait le travail.
$ git clone <repo_url> <project_dir>
$ cd <project_dir>
$ pip install pipenv
$ $ # clean pypi cache and make it ready to cache somehow - not described here
$ pipenv install -e .[test]
$ # if we need extra testing packages in pipenv
$ pipenv install <extra_test_packages>
$ # record current requirements expressed in `Pipfile.lock`
$ pipenv lock
$ # if needed, record the `Pipfile.lock` somewhere
Les résultats d'un tel travail sont :
Pipfile.lock
tant que dépendances enregistrées (peut aider les développeurs à reproduire facilement l'environnement)il y a des phases :
tox
, pip
etc. en utilisant uniquement notre cache pypi localpipenv
)Pipfile.lock
enregistre les packages pypi qui ont été utilisés pour installer la bibliothèque. Il peut être utilisé pour reproduire l'environnement sur le site du développeur.Un autre avantage est que cette configuration ne nécessite pas que les développeurs maintiennent Pipfile
ou Pipfile.lock
. De plus, l'exécution des tests dans différents contextes est toujours la même ( Pipfile.lock
est toujours reconstruit dans un contexte donné).
Le cache pypi est la partie qui nécessite quelques recherches. Je suppose qu'un simple répertoire serait suffisant et peut-être que pipenv
est déjà prêt à vous aider. Peut-être que le numéro 1731 est la partie manquante.
En tant que package qui résout les dépendances, bon nombre de nos propres tests reposent sur des constructions déterministes, c'est-à-dire en prenant des éléments connus et en s'attendant à un graphe résolu. Nous utilisons pytest-pypi
pour cela.
J'adore la discussion animée sur ce sujet. Je pense que la nuance est importante et vous devriez toujours tester les dépendances connues ainsi que celles non épinglées
vous devriez toujours tester les dépendances connues ainsi que celles non épinglées
Je seconde cette suggestion. C'est une bonne idée de toujours avoir un "bon état connu" explicite pour les versions reproductibles et de simplifier le débogage au cas où une mise à jour casse quelque chose en plus de s'assurer que les nouvelles versions mineures/correctives de bogues fonctionnent également.
(À mon avis très personnel, la situation idéale serait que le gestionnaire de paquets installe les dernières versions mineures par défaut afin que les bibliothèques puissent toujours spécifier les versions de dépendances concrètes avec lesquelles elles ont été testées, mais je me rends compte que c'est une opinion très controversée et que tout le monde à suivre sever.)
@Moritz90 @techalchemy @uranusjr @tsiq-oliverc
Voici mon résumé de la discussion précédente.
Pipfile.lock
?Chaque système d'exploitation et interpréteur python pris en charge contribuent à la matrice des contextes d'exécution possibles.
Par exemple, Flask prend en charge (au moins les éléments CI visibles dans le référentiel):
Il fait 9 contextes d'exécution différents qui peuvent différer.
Chaque contexte d'exécution peut avoir des Pipfile.lock
.
Qui les entretiendra ?
Les options sont :
Pipfile.lock
pour la plate-forme de développement principale (quelle plate-forme aime être ignorée ?)Proposition : Laissez CI générer le fichier par pipenv install -e .
. Ne l'incluez pas dans le dépôt, aidez les développeurs à choisir le bon Pipfile.lock
à la suite des builds automatisés.
Lors de la résolution d'un problème, qui peut être causé par des changements de dépendances sur pypi, le développeur peut avoir besoin d'un moyen simple pour reproduire l'environnement à partir du test ayant échoué.
Proposition:
Pipfile.lock
par pipenv install -e .
suivi de pipenv lock
.Pipfile.lock
du test ayant échoué.Pipfile.lock
dans tox.ini
.setup.py
casséLa bibliothèque setup.py
peut être cassée (dépendance manquante dans install_requires
, spécificateur de version manquant, etc.) et le test CI ne doit pas masquer ce problème (en préinstallant les dépendances omises seules).
Proposition:
pipenv install -e .
pour fournir le même résultat qu'une installation simple (il y a actuellement quelques problèmes avec cela).pipenv
) et comparez éventuellement que la sortie pip freeze
résultante est un sous-ensemble de ce qui est installé par pipenv
.Certaines mises à jour de dépendances peuvent casser la bibliothèque qui l'utilise. CI doit détecter l'échec sur un tel problème.
Proposition:
Pipfile.lock
, ce n'est pas un problème (car nous fonctionnons de toute façon en mode non épinglé)Dans tous les modes proposés, j'ai essayé d'éviter de garder des fichiers pipenv
dans le référentiel, évitant ainsi aux développeurs de maintenir ce truc vraiment complexe (automatisation !!!).
Contrairement à mon texte d'origine, les 2e et 3e modes utilisent pipenv
dans les scripts CI.
Package simple avec un plus petit nombre de dépendances qui ne changent pas souvent.
Exécutez simplement comme avant l'ère pipenv
et gardez les choses simples pour nous.
Les rares cas où les dépendances causeront des problèmes sont faciles à résoudre et ne justifient pas de rendre CI plus complexe.
Chaque fois que le test CI est exécuté, générez un nouveau Pipfile.lock
qui décrit complètement l'environnement utilisé pour le moment.
Le Pipfile.lock
deviendra l'artefact CI.
Si les choses tournent mal, le développeur peut choisir Pipfile.lock
dans une version cassée, l'appliquer localement et effectuer les tests et les corrections.
Si quelqu'un veut déployer, Pipfile.lock
du dernier build réussi peut être utilisé.
Lorsque le changement de dépendances est un réel problème, CI doit créer Pipfile.lock
une fois et le conserver pendant une certaine période (un mois ?).
Cela rend la configuration de CI plus difficile, car il doit y avoir au moins deux tâches différentes (une générant Pipfile.lock
, l'autre l'appliquant et l'utilisant dans les tests).
Attention : Pipfile.lock
doit être mis à jour également pour le moment, setup.py
modifie les dépendances.
Notez que l'ère glaciaire nécessite Scrat le type de test écureuil qui ignore le statut gelé et vérifie les versions non épinglées.
Comme on le voit, le déterminisme et la complexité croissent mode par mode.
Ma proposition serait :
Tous les gains coûtent quelque chose.
Si l'objectif ici est de mettre à jour les conseils contenus dans la documentation, alors honnêtement, il semble irresponsable de dire quelque chose de radicalement différent de "Suivez les meilleures pratiques (versions reproductibles) par défaut, jusqu'à ce que vous n'ayez pas le choix".
@vlcinsky Sous le titre "Mode: Générer et sceller", il peut être judicieux de mentionner que le dernier Pipfile.lock
réussi doit toujours être conservé, par exemple en le déclarant comme un artefact Jenkins. Avec ce changement, il serait bon de recommander cette configuration pour la plupart des projets. Comme @tsiq-oliverc, je ne recommanderais jamais le premier mode.
Plus j'y pense, plus j'ai l'impression que cette documentation deviendra une section expliquant pourquoi l'utilisation de pipenv
pour les builds CI est une excellente idée, même si vous développez une bibliothèque.
@tsiq-oliverc la grande majorité des packages python généraux sont en mode "Run, Forrest, Run". J'ai aidé quelques-uns de ces packages à introduire tox
et pytest
, car je sentais que cela contribuerait à la qualité du package et parce que j'avais une idée assez claire de la façon dont cela pourrait être bien fait.
Maintenant, il existe un autre excellent outil et je me demande comment utiliser correctement pipenv
dans les projets python généraux pour contribuer à sa qualité. Je veux trouver une ou deux recettes qui fonctionnent bien, qui soient justifiées et faciles à suivre.
Que dirais-je au projet Flask ?
Pipfile.lock
fichiers et mettre en place une politique de mise à jour ?Pipfile.lock
artefact L'objectif est de trouver un style de travail fonctionnel. Si ça se termine par doc, sympa, sinon pas de problème.
@vlcinsky Je dirais que (1) et (4) devraient être la recommandation pour de tels projets. Bien que sans Pipfile.lock
préexistant, vous ne saurez pas à l'avance les versions utilisées dans la construction (ce qui est bien en dehors des environnements d'entreprise), vous obtiendrez toujours un résultat reproductible si vous générez et archivez le fichier de verrouillage pendant la construction.
Edit : La version tl; dr de ma recommandation serait :
pipenv
peut vous aider à atteindre cet objectif.Pipfile.lock
dans votre référentiel et utilisez-le pour le déploiement. (Ceci est déjà couvert par la documentation existante.)Pipfile.lock
à la volée dans votre build CI et archivez-la pour plus tard.(Bien sûr, la documentation réelle devrait avoir un peu plus de détails et d'exemples.)
@ Moritz90 J'ai modifié le "Générer et sceller" comme vous l'avez proposé.
Re (1) : facile à dire, impossible à exécuter sans être plus précis.
Re (4) : oui, je pense aussi que "Générer et sceller" est le mode le plus faisable. Mais en cas de Flask je n'oserai pas (du moins pas pour le moment).
Re préexistant Pipfile.lock
dans un environnement d'entreprise : il doit être créé d'une manière ou d'une autre, (semi)manuellement ou automatiquement. Je suppose que dans un environnement d'entreprise, vous n'installez pas directement à partir de pypi public mais en utilisez un privé et qui ne fournit que des packages approuvés ( devpi-server
fournit un excellent service en ce sens - plusieurs index, volatilité contrôlée des packages publiés, approbations pour les packages, etc.) Si le processus de construction de Pipfile.lock
s'exécute dans un tel environnement, il ne peut utiliser que ce qui est approuvé, donc si une nouvelle version doit y apparaître, quelqu'un doit se lever et la faire approuver. La construction suivante de CI testera qu'elle ne casse pas les choses. Et avec pipenv check
test des problèmes de sécurité peut également être automatisé.
Je suppose qu'un tel flux de travail serait plus sécurisé que quelqu'un qui le crée (semi) manuellement. Mais ma connaissance de l'environnement d'entreprise est très limitée.
Bonjour l'équipe pipenv. Je partage beaucoup de ce qui est dit dans ce texte, cela aide beaucoup tout développeur à mieux comprendre les limites de Pipfile/pipenv lors du développement d'une bibliothèque. Je veux voir ce texte ou une partie de ce texte intégré dans la documentation officielle de pipenv.
J'ai l'amendement suivant dont je voudrais discuter :
Pour notre package python interne, entièrement réutilisable, publié sur notre pypi interne, etc, et même pour mes propres packages python (ex: cfgtree , txrwlock , pipenv-to-requirements ), j'utilise un package que certains connaissent peut-être déjà ou même utilisent , qui résume ces détails et facilite la vie du développeur python : PBR.
PBR lit essentiellement requirements.txt
trouvé dans le dossier racine d'un paquet de distribution et l'injecte dans le install_requires
du setup.py
. Le développeur doit simplement maintenir un requirements.txt
avec des déclarations de dépendance lâches. Jusqu'à ce que le support de Pipfile
soit intégré officiellement dans PBR, je dois utiliser pipenv-to-requirements qui génère automatiquement requirements.txt
partir de Pipfile
afin qu'ils soient tous les deux synchronisés et tous les deux engagés dans la source, et PBR effectue l'injection correctement une fois le package de distribution construit. Je pense que l'on pourrait utiliser pipenv
pour générer ce requirements.txt
Je travaille sur un support de Pipfile pour PBR, afin qu'il puisse lire le Pipfile
(et non le fichier de verrouillage) et l'injecter dans install_requires
comme il le fait avec requirements.txt
.
Je ne sais pas si d'autres packages similaires existent, car il fait également d'autres choses que les gens pourraient ne pas vouloir (version de l'historique de git, génération automatique d'AUTEURS et de ChangLog).
Mais à la fin, je pense vraiment qu'il est tellement plus facile d'écrire, de maintenir et de gérer la gestion des versions d'une bibliothèque Python, je serais triste de ne pas partager cette expérience. Je le promeut comme le moyen "recommandé" d'écrire des bibliothèques python modernes sur mon entreprise.
Je reconnais que c'est comme "tricher" sur toutes les difficultés concernant la bibliothèque et pipenv, mais à la fin, le travail est terminé et les développeurs sont heureux de l'utiliser jusqu'à présent. Une partie de la formation python, que je donne au nouveau développeur python de mon entreprise, consiste à écrire d'abord une bibliothèque python en maintenant install_requires
manuellement, puis à passer à PBR
pour voir comment cela devient plus facile ( et franchement je suis fan de la fonctionnalité de
Une partie de la raison de déclarer les dépendances des bibliothèques à l'aide d'un fichier dédié également aux bibliothèques est de pouvoir utiliser des outils tels que readthedocs ou pyup (même si pyup a plus de sens lorsqu'il est lié à une application).
Je ne veux pas nécessairement promouvoir cette méthode comme la manière "standard" de faire un package python, c'est en fait la manière "OpenStack", mais je partagerais mon expérience, et si d'autres ont une expérience similaire ou contradictoire, je serai heureux de les entendre et de mettre à jour mon point de vue.
Equipe, que pensez-vous d'une sorte de rubrique "communauté" sur la documentation ? Pour que des utilisateurs comme moi puissent partager son expérience sur la façon dont il utilise pipenv, sans nécessairement l'aval complet de l'équipe pipenv ?
PS: je peux déplacer ceci vers un problème dédié si vous ne voulez pas polluer ce fil
@vlcinsky (1) est très facile à exécuter - placez votre fichier de verrouillage dans votre référentiel.
Je pense que ce que vous voulez dire à la place, c'est qu'il est impossible de donner des conseils précis une fois que cette stratégie de base n'est plus suffisante. C'est certainement vrai, mais c'est parce que le problème spécifique diffère probablement au cas par cas.
Ou pour le dire autrement, la solution dépend des garanties supplémentaires que vous souhaitez que votre flux de travail CI fournisse.
@gsemet tu sais quoi ? Tous mes packages python créés au cours des deux dernières années sont basés sur pbr
- c'est vraiment génial. Et je suis vos tentatives pour prendre en charge Pipfile dans pbr chaque fois que je le peux (un pouce levé, des votes, etc.).
En cas de problème (recherche de pipenv
modèles et anti-modèles pour les bibliothèques python générales), j'ai intentionnellement omis pbr
pour deux raisons :
pbr
pour d'autres raisons (vous les avez mentionnées) et cela détournerait probablement la discussionD'un autre côté, j'attends avec impatience votre recette pour les amateurs de pbr. je vais le lire.
@tsiq-oliverc vous avez mis le doigt sur le clou :
C'est exactement le problème qui m'a motivé à commencer ce numéro. Si vous relisez le début de ce problème, vous trouverez une description de quelques cas, où l'ajout de Pipfile.lock
peut casser vos tests CI (soit casser l'exécution de la construction, soit masquer les problèmes, qui seraient autrement détectés, soit installer de mauvaises dépendances pour un contexte donné...).
Si vous me montrez un dépôt, où cela est fait correctement (bibliothèque générale de python), je serais heureux. Ou je démontrerais quels risques il y a ou quelles choses sont inachevées.
Frais ! Je maintiens également cet emporte-pièce :)
@vlcinsky D'accord ,
Pour autant que je sache, voici les symptômes spécifiques de votre message d'origine :
pipenv install -e .
, n'est-ce pas ?@tsiq-oliverc Je dois dire que vos commentaires m'ont inspiré et je sais qu'ils ont contribué à un niveau plus élevé de reproductibilité de la solution proposée.
Ce qui suit est lié à votre proposition de placer le fichier de verrouillage ( Pipfile.lock
) dans le référentiel pour assurer la répétabilité :
re Cacher les dépendances de setup.py cassées. . Les pipenv install -e .
suivent ce que je propose, mais notez que ce n'est pas l'utilisation de Pipfile.lock
, c'est une méthode pour le (re)créer. Si quelqu'un garde Pipenv.lock
et l'utilise pour créer virtualenv avant d'installer le package, le problème est présent.
re Les dépendances sont susceptibles d'être invalides pour différentes versions de python ou dans un autre système d'exploitation . Les exemples sont nombreux : doit
installé pour Python 2.7 doit être une ancienne version car la plus récente a abandonné la prise en charge de Python 2.x. watchdog
dépendance de
re Les développeurs sont obligés de mettre à jour .. Imaginez la bibliothèque Open Source avec 15 contributeurs. Il est si facile d'oublier de régénérer Pipfile.lock
par un nouveau venu ou un développeur de base fatigué. Par exemple, dans le package maya
, on m'a demandé de régénérer le Pipfile.lock
car une nouvelle dépendance a été ajoutée à setup.py
. Était-ce nécessaire ? L'ai-je bien mis à jour ? L'ai-je mis à jour pour tous les contextes d'exécution pris en charge ? Les réponses sont non, pas sûr, non. Quoi qu'il en soit, merci pour votre proposition (elle m'a inspiré pour la solution décrite à côté de votre commentaire).
re Concurrence avec tox : Tox permet la création de plusieurs virtualenvs et l'automatisation de l'exécution des tests en leur sein. Typique tox.ini
définit différents virtualenvs pour python 2.7, 3.4, 3.5, 3.6 et tout autre dont vous avez besoin, et permet d'y installer le package et d'exécuter la suite de tests. C'est un outil puissant de testeurs sérieux. pipenv
n'est pas l'outil à cet effet, mais peut interférer dans l'installation des éléments nécessaires. D'une certaine manière, j'ai suivi vos conseils et j'ai proposé d'utiliser un outil supérieur (tox) sur pipenv
dans la mesure du possible.
re Pipenv échoue. C'est vraiment malheureux. J'ai eu un test CI (basé sur tox) qui fonctionnait bien sur localhost, mais lorsqu'il était exécuté via Travis, il échouait en raison d'un problème pipenv
. Si je veux l'utiliser maintenant, l'épinglage n'aide pas tant que le correctif n'est pas publié. Mais c'est comme ça que ça se passe - j'attendrai.
Notez que certaines parties de mon message d'origine devront être mises à jour comme il semble, en utilisant pipenv
dans les scripts CI a sa place justifiée (configuration virtualenv "scellant" pour une éventuelle utilisation ultérieure).
@tsiq-oliverc Alors que j'ai d'abord aimé votre suggestion de tester à la fois le "bien connu" et les dernières versions, je trouve de plus en plus difficile de justifier l'effort à mesure que j'y pense. Je pense que vous devriez décider de faire l'un ou l'autre, pas les deux.
La seule chose que vous gagnez est que vous saurez immédiatement si un échec a été causé par une mise à jour de dépendance ou un changement de code. Mais vous pouvez obtenir la même chose en effectuant simplement des commits séparés (lors de la mise à jour manuelle des dépendances verrouillées) ou en essayant de reproduire le bogue avec le dernier fichier de verrouillage produit par une construction réussie (en utilisant toujours les dernières versions). Et dans les environnements restreints, vous ne pouvez pas « simplement mettre à jour » de toute façon...
@vlcinsky Bien que je sois d'accord avec votre point de vue général sur les différences entre les environnements, l'argument "un fichier de verrouillage par configuration" me semble être un homme de paille. En pratique, vous pourrez partager les fichiers de verrouillage entre au moins certains des environnements.
Une question en suspens à laquelle personne n'a encore répondu est de savoir comment traiter le cas où vous devez tous les deux tester dans un environnement différent et verrouiller vos dépendances. Je dois admettre que je ne connais rien à propos de tox
part que ça existe, mais il semble qu'il y ait un besoin d'une sorte de colle entre tox
et pipenv
cela résout ce problème en quelque sorte.
@Moritz90
Concernant les trop nombreuses variantes de Pipfile.lock
servant d'homme de paille (pour garder les autres hors de mon champ) :
J'ai pris le projet flask
(le considérant comme très mature) et j'ai effectué des tests toxicologiques :
Ici, vous voyez la liste des variantes testées (juste localement sur Linux, multipliez-la par 3 car Windows et OSX feront le même ensemble de tests mais peuvent entraîner des environnements différents).
Il y a 16 tests différents sur un système d'exploitation, 5 d'entre eux ont échoué car je ne les ai pas installés (c'est bien), l'un traite de la documentation de construction (cela nécessite une bibliothèque imporable) et un autre une couverture (qui nécessite également une bibliothèque importable ):
coverage-report: commands succeeded
docs-html: commands succeeded
py27-devel: commands succeeded
py27-lowest: commands succeeded
py27-simplejson: commands succeeded
py27: commands succeeded
py35: commands succeeded
py36-devel: commands succeeded
py36-lowest: commands succeeded
py36-simplejson: commands succeeded
py36: commands succeeded
ERROR: py34: InterpreterNotFound: python3.4
ERROR: pypy-devel: InterpreterNotFound: pypy
ERROR: pypy-lowest: InterpreterNotFound: pypy
ERROR: pypy-simplejson: InterpreterNotFound: pypy
ERROR: pypy: InterpreterNotFound: pypy
Pour chacun des virtualenvs créés, j'ai créé requirements.txt
fichier pip freeze > {venv_name}.txt
Ensuite, les hachages calculés pour les fichiers, triés en fonction des valeurs de hachage, de sorte que tous les mêmes seront regroupés. Voici l'homme de paille :
b231a4cc8f30e3fd1ca0bfb0397c4918f5ab5ec3e56575c15920809705eb815e py35.txt
b231a4cc8f30e3fd1ca0bfb0397c4918f5ab5ec3e56575c15920809705eb815e py36.txt
cdf69aa2a87ffd0291ea65265a7714cc8c417805d613701af7b22c8ff2b5c0e4 py27-devel.txt
dfe27df6451f10a825f4a82dfe5bd58bd91c7e515240e1b102ffe46b4c358cdf py36-simplejson.txt
e48cd24ea944fc9d8472d989ef0094bf42eb55cc28d7b59ee00ddcbee66ea69f py36-lowest.txt
f8c745d16a20390873d146ccb50cf5689deb01aad6d157b77be203b407e6195d py36-devel.txt
053e107ac856bc8845a1c8095aff6737dfb5d7718b081432f7a67f2125dc87ef docs-html.txt
45b90aa0885182b883b16cb61091f754b2d889036c94eae0f49953aa6435ece5 py27-simplejson.txt
48bd0f6e66a6374a56b9c306e1c14217d224f9d42490328076993ebf490d61b5 coverage-report.txt
564580dad87c793c207a7cc6692554133e21a65fd4dd6fc964e5f819f9ab249c py27.txt
8b8ff4633af0897652630903ba7155feee543a823e09ced63a14959b653a7340 py27-lowest.txt
Effrayant, n'est-ce pas ? De tous les tests, seuls deux partagent les mêmes dépendances figées.
C'est la réalité de la bibliothèque python générale avec une bonne suite de tests. Vous admettrez probablement maintenant qu'il s'agit de quelque chose de très différent de la bibliothèque python testée dans un environnement d'entreprise.
Vérification de jinja2
, qui semble être une bête beaucoup plus simple :
coverage-report: commands succeeded
py26: commands succeeded
py27: commands succeeded
py33: commands succeeded
py35: commands succeeded
py36: commands succeeded
ERROR: docs-html: commands failed
ERROR: py34: InterpreterNotFound: python3.4
ERROR: pypy: InterpreterNotFound: pypy
En voyant les sommes de contrôle, je suis surpris que py27.txt et py26.txt diffèrent :
047a880804009107999888a3198f319e5bbba2fa461b74cfdfdc81384499864e py26.txt
047a880804009107999888a3198f319e5bbba2fa461b74cfdfdc81384499864e py33.txt
047a880804009107999888a3198f319e5bbba2fa461b74cfdfdc81384499864e py35.txt
047a880804009107999888a3198f319e5bbba2fa461b74cfdfdc81384499864e py36.txt
48bd0f6e66a6374a56b9c306e1c14217d224f9d42490328076993ebf490d61b5 coverage-report.txt
743ad9e4b59d19e97284e9a5be7839e39e5c46f0b9653c39ef8ca89c7b0bc417 py27.txt
@vlcinsky C'est vraiment effrayant. Je me demande si Flask est un cas spécial ou si c'est en fait la norme, mais vous m'avez définitivement prouvé que j'avais tort.
J'espère maintenant que notre bibliothèque Python ne souffrira pas du même problème un jour et que les différences y seront plus gérables.
@ Moritz90 Votre bibliothèque interne dessert un public complètement différent, vous pouvez donc vous permettre de garder le contexte d'exécution beaucoup plus étroit.
Les bibliothèques python générales sont souvent flexibles et configurables, par exemple Flask permet d'installer et d'utiliser des analyseurs json alternatifs, ce qui est couvert par un test séparé.
On peut en apprendre beaucoup sur les tests et la toxicité grâce aux tox.ini
de Flask
les variantes de test les plus basses prennent soin de tester par rapport à la version de dépendance la plus ancienne.
devel teste la version de développement des dépendances principales.
Je dirais que Flask est au niveau de complexité le plus élevé et présente une suite de tests minutieuse.
Le tox.ini de la pyramide montre un nombre similaire d'environnements (ils visent également une couverture de code à 100%).
Le tox.ini de maya est très frais (2 jours) et simple, même ici, il y a 4 environnements différents et py27 diffère en termes d'exigences gelées de py35 et py36.
@Moritz90
Concernant la colle entre pipenv et tox
pipenv --man
montre quelques instructions, comment utiliser pipenv
dans les commandes tox.ini
tox.ini
fichier pipenv
.
pipenv
a une grande fonctionnalité, que lorsqu'il est exécuté dans virtualenv déjà activé (ce qui est le cas dans le test basé sur la toxicité), il s'installe dans un environnement virtuel donné. C'est vraiment sympa.
Comme nous avons probablement besoin de Pipfile.lock
générés, un effort supplémentaire doit être fait pour l'obtenir et le déplacer au bon endroit (ag in .tox/py36/Pipfile.lock
pour éviter l'écrasement en suivant le test. Cela sera possible, mais une certaine simplification serait peut-être une astuce avec une variable d'environnement pour l'emplacement de Pipfile
le rendrait encore plus simple.
@vlcinsky
pipenv install -e .
une fois afin que setup.py soit maintenant suivi via votre fichier de verrouillage. Et puis exécutez pipenv install
chaque fois que vous ajoutez de nouveaux packages à setup.py.pipenv --deploy
est conçu pour attraper cela. Exécutez-le dans votre CI !update-all-lockfiles.sh
localement et exécuter pipenv --deploy
sur votre CI pour détecter les erreurs.@ Moritz90 - D'accord, l'approche "en deux phases" peut être excessive dans la plupart des cas. En particulier, si vous effectuez des mises à jour « manuelles » délibérées/intentionnelles de votre fichier de verrouillage, cela est totalement inutile.
Plus généralement, il serait bon de s'assurer que cette "proposition" se concentre sur les choses qui sont en fait des problèmes difficiles (à mon avis, c'est (A) desservant plusieurs environnements, (B) voulant détecter les changements dans les dépendances en amont). Cela ne devrait pas être basé sur des choses transitoires (bugs dans Pipenv) ou des malentendus potentiels sur la façon dont l'outil est destiné à être utilisé.
Mais même pour ces problèmes "difficiles", le cadrage devrait ressembler à "dans certains cas complexes, vous pouvez trouver qu'un flux de travail Pipenv de base est insuffisant, alors voici quelques points à considérer". OMI, cela ne devrait pas être présenté comme l'approche par défaut (car la plupart des gens n'auront pas ces préoccupations).
L'exemple de documentation fourni par @vlcinsky deviendrait plus simple et moins déroutant si Pipenv/Pipfile permettait la gestion de lib-dependencies
, app-dependencies
et dev-dependencies
. Les documents pourraient ressembler à ceci :
Utilisez l'option lib-dependencies
si votre package est une bibliothèque partagée. Exemple Pipfile
:
[lib-dependencies]
some-lib=="*"
another-lib=="*"
yet-another-one==">=1.0"
[dev-dependencies]
some-dev-tool=="1.1"
Pour les bibliothèques partagées, il est important de garder les plages de versions inférieures à [lib-dependencies]
aussi larges que possible, afin d'éviter les conflits de versions sur le système consommateur.
Si votre package est une application (destinée à être installée par pipenv sur le système cible) qui nécessite des versions de dépendance exactes, vous devez utiliser l'option [app-dependencies]
. Exemple Pipfile
:
[app-dependencies]
some-lib=="1.0.12"
another-lib=="1.*"
yet-another-one=="2.0"
[dev-dependencies]
some-dev-tool=="1.1"
/Fin de l'exemple de document
Une autre approche pourrait être un Pipfile.lib
et un Pipfile.app
.
Je pense que quelque chose comme ça omettrait le besoin d'un morceau de sections anti-modèle et d'outils tiers pour combler le vide.
Appeler l'outil d'emballage pipenv est trompeur si l'on s'attend à ce qu'il crée des bibliothèques python ou qu'il soit profondément impliqué dans leur création.
Je pense qu'il s'agit d'un vrai problème, ce qui entraîne beaucoup de confusion. Surtout parmi les personnes habituées aux gestionnaires de packages dans d'autres langages de programmation (par exemple, JS, Rust, Elm). Cela m'a pris plusieurs mois et une lecture occasionnelle des problèmes de GIthub, jusqu'à ce que je réalise que j'utilisais Pipenv et setup.py dans le mauvais sens.
@féluxe
Votre [lib-dependencies]
ou Pipfile.lib
est ce que nous avons aujourd'hui en Pipfile
(en tant que dépendances abstraites - en étant aussi larges que possible).
Votre [app-dependencies]
ou Pipfile.app
est ce que nous avons dans Pipfile.lock
(en tant que dépendances spécifiques).
pipenv
et ses fichiers peuvent être utilisés dans deux situations différentes : développer une bibliothèque ou préparer le déploiement d'une application, mais probablement pas pour les deux à la fois. Pour cette raison, je ne vois pas de bonnes raisons d'ajouter des sections supplémentaires dans Pipenv
. Il est de la responsabilité des développeurs de savoir quel type d'objectif le Pipfile
va servir.
Je pense qu'il s'agit d'un vrai problème, ce qui entraîne beaucoup de confusion. Surtout parmi les personnes habituées aux gestionnaires de packages dans d'autres langages de programmation (par exemple, JS, Rust, Elm). Cela m'a pris plusieurs mois et une lecture occasionnelle des problèmes de GIthub, jusqu'à ce que je réalise que j'utilisais Pipenv et setup.py dans le mauvais sens.
D'accord. La solution en trois sections est également une solution très intéressante que je n'ai jamais envisagée, et elle semble correcte et (étonnamment !) simple.
Venant moi-même d'un environnement Python, j'ai toujours eu l'impression que le package.json de Node le faisait mal (Rust est meilleur car il a un compilateur et un éditeur de liens, et peut résoudre ce problème à un stade ultérieur). Traiter les dépendances app et lib de la même manière ne fonctionnera tout simplement pas pour un langage de script comme Python, du moins dans un sens abstrait, c'est-à-dire que cela pourrait fonctionner pour vous, mais un outil générique comme Pipenv ne peut pas le faire car il doit être générique.
Bien que j'aime la solution en trois sections dans son concept, il s'agit toujours d'un changement plutôt incompatible avec l'écosystème existant. Il y a déjà setup.py, setup.cfg et (potentiellement) pyproject.toml remplissant cet espace. Si Pipenv (Pipfile, pour être exact) veut se déplacer dans l'espace, il doit se consolider avec des projets connexes, tels que pip (le support de la bibliothèque devrait idéalement être pris en charge directement par celui-ci) et flit .
Comme je l'ai mentionné dans d'autres problèmes concernant la gestion des dépendances lib/app, cette discussion doit être transmise à pypa-dev (la liste de diffusion) et/ou au processus PEP, afin qu'elle puisse être mieux entendue par les autres parties et les personnes concernées, avant Pipenv (Pipfile) peut se déplacer dans toutes les directions.
@vlcinsky
Votre [lib-dependencies] ou Pipfile.lib est ce que nous avons aujourd'hui dans Pipfile (en tant que dépendances abstraites - aussi larges que possible).
Désolé si ce n'était pas clair. Mes lib-dependencies
sont censés être ce que les gens mettent actuellement dans setup.py
/ install_requires
. Peut-être que pypi-dependencies
serait un meilleur nom pour ce que je voulais dire.
@uranusjr
Il y a déjà setup.py, setup.cfg et (potentiellement) pyproject.toml remplissant cet espace.
Pipenv (l'outil de ligne de commande) pourrait interfacer setup.py
. Seule la section de dépendance de setup.py
devrait être déplacée vers Pipfile. Du moins dans mon imagination :)
Comme je l'ai mentionné dans d'autres problèmes concernant la gestion des dépendances lib/app, cette discussion doit être transmise à pypa-dev (la liste de diffusion) et/ou au processus PEP, afin qu'elle puisse être mieux entendue par les autres parties et les personnes concernées, avant Pipenv (Pipfile) peut se déplacer dans toutes les directions.
Ok, désolé de déranger ;) Si je trouve un peu de temps, j'écrirai quelque chose pour la liste de diffusion.
Dans le cadre de cette proposition, cependant, je suggérerais qu'elle se concentre sur les meilleures pratiques actuellement possibles, au lieu d'entrer dans le trou du lapin de l'élaboration d'un nouveau flux de travail pour l'ensemble de la communauté d'emballage Python. Il serait plus productif de proposer une meilleure pratique dans les contraintes actuelles, puis de lancer la discussion pour des améliorations.
@uranusjr - Je viens d'un milieu "compilé", donc je suis curieux de savoir pourquoi c'est le cas ?
Traiter les dépendances app et lib de la même manière ne fonctionnera tout simplement pas pour un langage de script comme Python
@tsiq-oliverc Étant donné que les meilleures pratiques d'application vous obligent à épingler vos dépendances, les bibliothèques commenceraient également à épingler les leurs, si elles utilisent la même source de fichiers d'exigences. Cela conduirait à des problèmes de résolution des dépendances.
Supposons que mon application a deux dépendances A et B, les deux dépendent de C, mais A épingle v1, tandis que B épingle v2. Les langages compilés permettent à la chaîne d'outils de détecter cela au moment de la compilation et de le résoudre de plusieurs manières. Rust, par exemple, le fait pendant le temps de liaison : l'exécutable de fin contiendrait deux copies de C (v1 et v2), avec A et B liés à chacun d'eux. Dans le pays C++, cela serait résolu avec des bibliothèques dynamiques ; la recherche de symboles est effectuée encore plus tard (au moment de l'exécution), mais l'idée est la même : le compilateur sait ce dont vous avez besoin (à partir de l'interface que vous utilisez) et peut agir en conséquence.
Les langages de script ne peuvent pas faire cela car ils ne savent pas ce que vous voulez vraiment faire jusqu'à ce qu'ils atteignent réellement l'appel. Node contourne cela en supposant toujours que les dépendances sont incompatibles (A et B obtiennent toujours leur propre C, même si les deux copies sont identiques), mais cela conduit à une nouvelle classe de problèmes et entraîne des hacks gênants comme des dépendances entre pairs que tout le monde (J'espère ?) d'accord sont terribles. Python ne veut probablement pas y aller (il ne le peut pas, de toute façon, car cela casserait probablement toutes les installations Python existantes).
Une autre façon de contourner ce problème est de faire quelque chose d'intelligent dans les outils d'empaquetage qui "détache" la version de dépendance. Bundler (de Ruby) le fait en quelque sorte, en recommandant aux gens de ne pas inclure le fichier de verrouillage dans la gem, afin que Bundler puisse utiliser les versions non épinglées dans Gemfile, au lieu des versions épinglées dans Gemfile.lock. Mais les gens ont tendance à ignorer les conseils et à faire ce qu'ils veulent, vous obtenez donc toujours des versions épinglées partout.
J'étais probablement un peu trop fort pour dire que cela ne fonctionnera tout simplement pas . Mais au moins tous les essais précédents ont échoué, et beaucoup de ceux qui ont essayé sont des gens très intelligents, beaucoup plus intelligents que moi. Je ne pense pas que cela puisse être fait, personnellement, et je continuerais à penser de cette façon jusqu'à ce que je voie la proposition très brillante qui le fait réellement.
@tsiq-oliverc Pieter Hintjens a écrit quelque part un concept de "Les commentaires sont les bienvenus sous forme de pull request"
J'aime ça parce que ça déplace l'attention des conseils philosophiques vers des choses vraiment tangibles et pratiques. Et cela limite également le nombre de commentaires car un commentateur apprend souvent au passage que l'idée est incomplète ou en quelque sorte brisée dans l'usage réel.
Je vous ai demandé un exemple de bibliothèque python, où pipenv
est utilisé correctement (ou du moins utilisé) et vous n'en avez fourni aucun.
Vous commentez les qualités tox
mais admettez que vous ne les connaissez pas, répétant encore quelque chose sur les meilleures pratiques dans le monde du développement de packages python.
Vous dites que Flask
est peut-être un cas spécial. J'ai donc cherché sur Github des projets python en utilisant le mot "bibliothèque", triés en fonction du nombre de fourches (car cela reflète probablement le nombre de personnes qui font du développement avec), ignoré toutes les "listes de quelque chose" et compté le nombre d'environnements pour un OS (généralement Linux) :
Le nombre réel d'environnements dans lesquels exécuter des tests sera principalement 2 (+Windows) ou 3 (+OSX) fois plus élevé.
tox
est utilisé dans 2 projets sur 3 (je ne le compare pas à Travis ou Appveyor car ils font un autre niveau de test à côté).
Le nombre d'environnements à tester est assez élevé, Flask n'est certainement pas le plus sauvage.
Le nombre d'environnements pour lesquels définir des dépendances fixes n'est vraiment pas gérable manuellement.
Déposer simplement Pipfile.lock
dans un référentiel est assez facile, mais cela n'apporte aucune amélioration magique (si oui, montrez-moi un scénario réel, quand cela améliorera la situation).
Peut-être connaissez-vous la règle d'or du monde "compilé" et pensez-vous que le déterminisme (ou la répétabilité) est également un must pour Python. Comme vous le voyez, de nombreux projets Python vivent plutôt bien sans cela, il se peut donc que la règle d'or ne s'applique pas aussi strictement ici.
Je serai heureux si nous trouvons l'utilisation de pipenv
pour les bibliothèques python, ce qui améliorera la situation. Et je veux empêcher l'utilisation, qui nuirait à la qualité globale.
Pour atteindre cet objectif, mon approche consiste à itérer sur les questions :
@féluxe
Désolé si ce n'était pas clair. Mes dépendances lib sont censées être ce que les gens mettent actuellement dans setup.py / install_requires. Peut-être que les dépendances pypi seraient un meilleur nom pour ce que je voulais dire.
Voir pbr
discussion dans ce numéro. C'est l'effort de prendre en charge les dépendances de bibliothèque par Pipfile.
Je pense qu'un Pipfile
ne doit pas être utilisé à deux fins (lib et app), ces choses doivent être faites séparément. Si vous pensez que c'est vraiment nécessaire, pourriez-vous décrire le but d'un projet qui l'utilise ? J'essaie généralement de séparer les projets de développement et de déploiement de bibliothèques car ils ont une utilisation assez différente dans le temps.
@vlcinsky Je ne sais pas vraiment où vous voulez en venir (je ne sais pas quel genre de relations publiques vous demandez !), alors je vais me retirer de cette conversation pour le moment.
Pour reformuler le TL;DR de ma position :
@uranusjr Compris . Bien que je ne pense pas qu'il y ait quelque chose de spécifique à la langue ici, c'est simplement que différentes communautés se sont installées sur différentes heuristiques pour traiter un problème sans solution générique - si vous avez des conflits de version, vous avez un problème.
Maven/Java (par exemple) vous oblige à y penser au moment de la construction. La méthode NPM signifie que vous rencontrez des problèmes d'exécution si les versions incompatibles traversent une interface. La résolution d'exécution (par exemple, Python, les bibliothèques dynamiques) signifie qu'un dépendant peut planter/etc. si la version de dépendance n'est pas ce à quoi elle s'attendait.
@vlcinsky
Voir la discussion pbr dans ce numéro. C'est l'effort de prendre en charge les dépendances de bibliothèque par Pipfile.
pbr semble gentil et tout, mais il entre dans la catégorie que j'essayais d'aborder avec ceci:
Je pense que quelque chose comme ça omettrait le besoin d'un morceau de sections anti-modèle et d'outils tiers pour combler le vide.
Je pense que de tels outils ne devraient pas être nécessaires en premier lieu.
Si vous pensez que c'est vraiment nécessaire, pourriez-vous décrire le but d'un projet qui l'utilise ? J'essaie généralement de séparer les projets de développement et de déploiement de bibliothèques car ils ont une utilisation assez différente dans le temps.
En ce qui concerne les packages pypi, j'ai fini par utiliser Pipenv pour gérer les dépendances de développement, Pipfile
pour décrire les dépendances de développement, setup.py
pour décrire les dépendances de lib avec install_requires
et setuptools
dans setup.py
pour publier mon package exécutant pipenv run python setup.py bdist_wheel upload
. C'est ce que je considère comme compliqué.
Dans d'autres langues modernes, je dois apprendre un outil de ligne de commande (gestionnaire de packages) et un format de fichier de dépendance. La documentation est en un seul endroit et plus facile à suivre et un nouveau venu résoudra tout cela en quelques heures. Il s'agit de npm init
, npm install foo --dev
, npm publish
. Pipenv/Pipfile peut déjà en faire la plupart, s'il pouvait tout faire, des problèmes comme celui-ci n'existeraient pas.
Je réitère mon appel à une sorte de section/wiki "communauté" pour cette discussion. Il y a plusieurs "modèles" qui peuvent être légitimes et certains d'entre nous pourraient vouloir partager leur "façon de faire des bibliothèques python", certains comme moi avec pbr, et d'autres pourraient avoir un très bon modèle. Mais une page à l'intérieur du document pipenv, je ne sais pas si c'est une bonne idée.
PS : pour préparer la migration vers le nouveau pypi, vous devez utiliser de la ficelle et non python setup.py upload. L'utilisation de "upload" doit être considérée comme un anti-modèle.
Peut-être que pipenv peut développer une commande "publier" ?
@feluxe Vous voudrez peut-être jeter un œil à la poésie . Je viens de tomber dessus et il semble que c'est ce que vous cherchez.
Il fait ce que fait pipenv
et plus et il semble qu'ils le fassent mieux, notamment en ce qui concerne la gestion des dépendances (du moins c'est ce qu'ils prétendent). Il fait la gestion des dépendances, l'empaquetage et la publication d'un seul outil poetry
.
Je me demande si pipenv
et poetry
pourraient rassembler leurs efforts pour enfin donner à Python un véritable gestionnaire de paquets.
Je tiens à me répéter avant que cette discussion n'aille trop loin. Pipenv ne peut pas simplement développer une commande publish
, ou faire quoi que ce soit qui essaie de prendre en charge le devoir d'emballage. Cela ne ferait que fragmenter davantage l'écosystème, car tout le monde ne le fait pas de cette façon, et les dépendances des applications et des bibliothèques étant théoriquement différentes, vous ne pouvez pas dire à quelqu'un de les fusionner une fois la distinction faite dans son flux de travail.
Il peut sembler que presque tout le monde est d'accord avec cette fusion, mais la vérité est qu'il y a beaucoup plus de gens qui ne se joignent pas à cette discussion parce que les choses fonctionnent pour eux et qu'ils font autre chose. Je l'ai dit à plusieurs reprises : les discussions sur l'amélioration de la conception des chaînes d'outils et des formats de fichiers devraient avoir lieu quelque part plus haut dans la hiérarchie des emballages Python, de sorte qu'elles soient davantage exposées aux personnes qui conçoivent des éléments plus fondamentaux sur lesquels Pipenv s'appuie. S'il vous plaît, prenez la discussion là-bas. Il ne sert à rien de le suggérer ici, car Pipenv n'est pas en mesure de le changer.
Je l'ai dit à plusieurs reprises : les discussions sur l'amélioration de la conception des chaînes d'outils et des formats de fichiers devraient avoir lieu quelque part plus haut dans la hiérarchie des emballages Python, de sorte qu'elles soient davantage exposées aux personnes qui conçoivent des éléments plus fondamentaux sur lesquels Pipenv s'appuie.
Je suis d'accord pour dire que la discussion sur ce bogue devient incontrôlable maintenant que l'empaquetage et la publication sont apparus (ce bogue ne concerne que la gestion des dépendances !), mais pourriez-vous s'il vous plaît nous indiquer le bon endroit pour avoir cette discussion ? Les gens l'ont ici parce que pipenv est considéré comme un pas indispensable dans la bonne direction, pas parce qu'ils veulent imposer des responsabilités supplémentaires aux mainteneurs de pipenv.
Edit : Désolé, j'ai dû manquer le post dans lequel tu as fait exactement ça en lisant les nouveaux commentaires la première fois.
Dans le cadre de cette proposition, cependant, je suggérerais qu'elle se concentre sur les meilleures pratiques actuellement possibles, au lieu d'entrer dans le trou du lapin de l'élaboration d'un nouveau flux de travail pour l'ensemble de la communauté d'emballage Python. Il serait plus productif de proposer une meilleure pratique dans les contraintes actuelles, puis de lancer la discussion pour des améliorations.
Je suis tout à fait d'accord avec cela. Nous devons d'abord déterminer quel est le meilleur flux de travail possible pour les responsables de bibliothèque en ce moment avant de proposer de grands projets. Concentrons-nous à nouveau sur cela, comme nous l'avons fait au début de ce fil. Je ne pense pas que nous ayons encore atteint une conclusion.
Retour au sujet : citant le message de
Une autre façon de contourner ce problème est de faire quelque chose d'intelligent dans les outils d'empaquetage qui "détache" la version de dépendance. Bundler (de Ruby) le fait en quelque sorte, en recommandant aux gens de ne pas inclure le fichier de verrouillage dans la gem, afin que Bundler puisse utiliser les versions non épinglées dans Gemfile, au lieu des versions épinglées dans Gemfile.lock. Mais les gens ont tendance à ignorer les conseils et à faire ce qu'ils veulent, vous obtenez donc toujours des versions épinglées partout.
J'étais probablement un peu trop fort pour dire que cela ne fonctionnera tout simplement pas. Mais au moins tous les essais précédents ont échoué
Je ne vois toujours pas pourquoi la recommandation officielle pour les bibliothèques pour l'instant ne peut pas être d'utiliser pipenv
pour leurs builds CI, mais gardez le Pipfile.lock
hors du contrôle de source. Puisque, comme quelques personnes l'ont souligné, pipenv
n'a actuellement rien à voir avec le processus d'empaquetage, nous ne devrions pas rencontrer le problème que vous avez décrit ci-dessus.
Et je ne vois pas non plus pourquoi c'est un argument contre la définition de vos dépendances abstraites dans le même fichier que les applications utilisent pour définir leurs dépendances abstraites. Ce n'est pas grave si pipenv
ne veut pas implémenter une solution élaborée pour intégrer le Pipfile
avec setup.py
, mais je ne vois pas pourquoi c'est une mauvaise idée en général.
@vlcinsky
Je pense qu'un Pipfile ne doit pas être utilisé à deux fins (lib et app), ces choses doivent être faites séparément.
Voir mon post ci-dessus. Pourriez-vous s'il vous plaît expliquer pourquoi vous pensez cela? Je ne vois tout simplement aucun inconvénient en principe. À l'heure actuelle, ce peut être une mauvaise idée d'inclure un Pipfile
, car vous devrez alors définir les dépendances de la même manière dans deux fichiers différents, mais je n'ai encore vu aucun argument qui explique pourquoi ce serait une mauvaise idée d'utiliser le Pipfile
pour les déclarations de dépendances en général.
Notez que j'ai déjà convenu que Pipfile.lock
ne devrait pas être dans le contrôle de source pour les bibliothèques, sauf si vous êtes dans la même situation que moi.
Edit : De plus, s'il s'avère que pipenv
lui-même a réellement besoin de connaître la différence, vous pouvez simplement introduire quelque chose comme le champ crate-type
cargo avant de commencer à introduire app-dependencies
et lib-dependencies
- cela semble trop compliqué.
@ Moritz90 Plusieurs listes de diffusion de Python seraient de bons endroits pour tenir cette discussion.
pypa-dev est le plus précis pour les discussions centrées sur l'emballage Python et l'écosystème qui l'entoure. Je commencerais probablement ici si je devais poster une discussion similaire.
python-ideas est un endroit pour discuter d'idées et a une visibilité assez élevée pour l'ensemble de la communauté Python. Ce serait également un bon point de départ si vous souhaitez pousser cela au niveau PEP (éventuellement, vous le feriez, je pense).
@tsiq-oliverc
Par relations publiques, je veux dire : montrez un exemple prouvant que votre concept est viable.
Alors récupérez une bibliothèque existante, forkez-la, appliquez votre (1) - vous dites que ce sera facile avec pipenv
et montrez-moi. J'ai essayé assez fort et j'ai des difficultés.
Si votre (2) signifie "quelqu'un d'autre doit faire le travail", votre PR n'existera pas.
En (3) vous parlez de "petit sous-ensemble de cas" sans donner de nombre réel. Toutes les meilleures bibliothèques que j'ai décrites en ce qui concerne le nombre de virtualenvs sont-elles considérées comme un "petit sous-ensemble" ?
Pour conclure cette discussion, j'ai créé un bref résumé de ce qui a été trouvé au cours de la discussion.
pipenv
(anti)motifs pour les bibliothèques et applications pythonJ'ai un peu changé d'orientation : il ne parle pas seulement des bibliothèques Python (générales), mais aussi des applications car il était plutôt bon marché de les inclure et cela montre bien les différences.
J'ai intentionnellement exclu tout ce qui proposait des changements dans l'outillage existant tel que pipenv
, tox
etc.
pipenv
et qu'est-ce que ce n'est pasPipfile.lock
.Le produit (logiciel python) est soit prêt à être utilisé dans un autre produit (donc une bibliothèque), soit il s'agit d'une application finale prête à être exécutée.
Personnellement, je pense que même les "bibliothèques d'entreprise" entrent dans la catégorie des bibliothèques (les mêmes règles s'appliquent, seul le nombre de contextes d'exécution est plus petit).
pipenv install <package>
donc "mettre le paquet en jeu (résolution des versions pour les autres bibliothèques)"pipenv sync
donc "appliquer des dépendances concrètes"dépendances concrètes : doit épingler les versions, idéalement avec les hachages des bibliothèques utilisées
pipenv
artefacts :Pipfile
: dépendances abstraites
Pipfile.lock
: dépendances concrètes (verrouillées)"tox
ou un logiciel de test similairepipenv
et de dépendances concrètes (peut convenir aux bibliothèques)Pipfile
dans le référentielPipfile.lock
créé par pipenv install -e .
Pipfile.lock
documente (scelle) l'environnement et permet la reproduction ultérieure de virtualenv pour analyser les problèmes.Mode : "L'âge de glace"
setup.py
install_requires
) le changement ou le package dépendant sur pypi est mis à jour, régénérer Pipfile.lock
par pipenv install -e .
pipenv sync Pipfile.lock
Pipfile.lock
manuellement par le développeur (peut fonctionner pour les applications)
application : déterminisme (exécuté exactement de la même manière dans le contexte d'exécution sélectionné)
public pypi (faible déterminisme, les packages sont mis à jour à tout moment)
Pipfile.lock
) : déterminisme totalPipfile.lock
:déployer l'application en production
pbr
bibliothèque requirements.txt
. La mise à jour de la lecture Pipfile
est en route.
poetry
package essaie quelque chose de similaire à pyenv
"drop lockfile into repo" et vous obtenez des builds déterministes :
Pipfile.lock
. Sérieusement : flask
montre sur ses 11 environnements virtuels différents (sur un seul système d'exploitation) 10 dépendances verrouillées différentes. Qui va les créer et les engager ?Pipfile.lock
(mais généré par le script CI) permettant de régénérer le virtualenv ailleurs.Pipfile.lock
dans le référentiel de la bibliothèquesetup.py
.Pipfile
dans le référentiel de la bibliothèquesetup.py
), il peut masquer une déclaration de dépendance setup.py
cassée.Pipfile
par pipenv install -e .
ou pipenv install -e .[tests]
si vous avez également besoin de tester les dépendances et qu'elles sont déclarées comme des extras "tests" dans le setup.py
pipenv install <something>
dans les scripts CIpipenv
).Les bibliothèques Python (en particulier les plus générales) présentent un nombre étonnamment élevé de contextes d'exécution. La raison en est qu'avec les bibliothèques, l'objectif est une flexibilité éprouvée dans différentes conditions. La flexibilité semble plus importante que les constructions déterministes. Pour les personnes venant du monde de la "compilation", cela peut sembler être un très mauvais anti-modèle. Le fait est que la plupart (éventuellement toutes) des bibliothèques python ne fournissent pas de versions déterministes (si vous en connaissez, faites-le moi savoir) et Python se débrouille toujours très bien. Les raisons pour lesquelles les applications Python sont toujours vivantes peuvent être : python en tant que langage de script diffère du monde compilé. L'autre raison pourrait être que le déterminisme peut (doit) être résolu une étape plus tard dès que l'application (construite à partir d'un ensemble de bibliothèques) résoudra l'exigence (naturelle et justifiée) de déterminisme.
Pour les applications, la situation est juste à l'opposé et ici le déterminisme est vraiment facile à atteindre avec des outils tels que pipenv
.
Que faire ensuite?
Merci à tous pour la discussion très inspirante - je me sens comme un message "Je suis totalement perdu dans ce sujet" remanié trois fois - ce qui signifie naturellement que nous nous sommes améliorés.
@vlcinsky poetry
n'a rien à voir avec pyenv
. C'est un peu comme pipenv
(mais avec une bien meilleure implémentation concernant la gestion des bibliothèques et des applications, IMO) mais avec la partie packaging et publication.
Vous avez un fichier pyproject.toml
qui définit votre projet et ses dépendances (dépendances abstraites) et un pyproject.lock
qui décrit les dépendances épinglées et sont épinglés pour toute version de python et plate-forme le pyproject.toml
fichier a spécifié afin de n'avoir qu'un seul fichier de verrouillage déterministe pour éviter les problèmes auxquels pipenv
est confronté. Uniquement lors de l'installation, poetry
vérifiera les packages à installer en les comparant à l'environnement.
Et lorsqu'il packagera votre bibliothèque, il utilisera les dépendances abstraites (et non celles épinglées) afin que vous conserviez la flexibilité lors de la distribution de votre package (via PyPI par exemple).
L'avantage de ceci est qu'il utilisera des dépendances abstraites pour les bibliothèques et le fichier de verrouillage pour les applications. C'est le meilleur des deux mondes.
La poésie
Essentiellement, nous consacrons beaucoup de temps et d'efforts à la résilience pour que les petits projets qui font des revendications élevées n'aient pas à consacrer autant d'efforts parce que les gens ne frappent pas les cas extrêmes. Si vous pensez vraiment qu'un autre outil vous offre le meilleur de tous les mondes, alors je vous encourage à l'utiliser - pipenv lui-même ne va pas gérer l'emballage pour vous à court terme, voire jamais.
@techalchemy Je ne vends rien, vraiment, je pipenv
.
Et poetry
fait des dépendances d'épingles dans pyproject.lock
, tout comme pipenv
dans Pipfile.lock
. Vous avez donc une reproduction exactement comme le fournit pipenv
. Si vous avez un fichier de verrouillage, il sera utilisé et installera une dépendance épinglée et si je ne me trompe pas, c'est aussi ce que fait pipenv
.
La seule fois où il utilise des dépendances abstraites, c'est lorsqu'il conditionne le projet pour la distribution (donc essentiellement pour les bibliothèques) car dans ce cas, vous ne voulez pas de dépendances épinglées.
@vlcinsky Il reste encore quelques points à régler, corriger ou développer, mais je tiens toujours à ce que cela se fasse sous forme de documentation, Pipenv ou autre. Seriez-vous intéressé par l'envoi d'une pull request ? Je serais plus qu'heureux d'aider à étoffer l'article.
Concernant la poésie, je ne suis pas personnellement un fan dans son ensemble, mais elle fait beaucoup de choses correctes. Il ne devrait probablement pas être mentionné dans la documentation de Pipenv car il viole quelques bonnes pratiques que les développeurs de Pipenv veulent inciter les gens vers, mais il devrait être mentionné si la discussion a lieu dans pypa-dev ou similaire, pour fournir une image complète de la façon dont l'emballage l'écosystème l'est actuellement.
la poésie peut également utiliser plus d'attention et de contribution. Ce serait le mieux pour la communauté, y compris Pipenv. Avec des choix viables, les gens peuvent peser sur leurs choix au lieu d'entrer dans Pipenv la tête la première et de se plaindre de ne pas faire ce qu'ils attendent. Une bonne concurrence entre les bibliothèques peut également stimuler des améliorations techniques sur le front de la résolution des dépendances, ce que Pipenv et la poésie font tous les deux (et ni parfaitement). Nous pouvons apprendre beaucoup les uns des autres.
@uranusjr Oui, je pense que peu de choses ont été clarifiées et méritent d'être partagées avec un public plus large. Votre aide est vraiment la bienvenue.
Qu'en est-il de la « rédaction de la documentation en binôme » ? Je pense qu'en ce moment il serait plus efficace de travailler dessus à petite échelle de deux personnes seulement.
Les réflexions à faire sont (éventuellement avec une ou deux itérations) :
Si vous avez envie de l'écrire vous-même (sur la base de ce qui a été discuté) et de m'avoir comme critique, je ne me plaindrais pas.
Je vous contacterai par e-mail pour convenir des prochaines actions.
@vlcinsky Je suis également disponible en tant que @uranusjr
sur PySlackers (un espace de travail Slack) si vous préférez l'interaction en temps réel. Pipenv y a un canal ( #pipenv
).
@uranusjr C'est ce que je voulais dire par rassembler des efforts. Python a désespérément besoin d'un bon gestionnaire de paquets comme cargo. L'écosystème Python est pâle par rapport aux autres langages en raison de l'absence d'une façon standard de faire les choses. Et pipenv
n'aidera pas avec ça, je pense.
Ce qui me dérange, c'est que pipenv
s'annonce comme the officially recommended Python packaging tool
alors que ce n'est pas un outil de packaging, loin de là, ce qui est trompeur pour les utilisateurs. C'est simplement un gestionnaire de dépendances couplé à un gestionnaire virtualenv.
De plus, vous dites qu'il a été inspiré par cargo, npm, fil qui sont des outils d'emballage avec des gestionnaires de dépendances alors que la tuyauterie ne l'est pas.
Et voici le défaut de pipenv
, cela brouille les cartes puisque les gens feront toujours les mêmes erreurs qu'avant avec requirements.txt
vs setup.py
. Les projets seront toujours mal emballés avec des dépendances mal définies dans leurs setup.py
cause de cela. C'est ce que des projets comme cargo ont bien fait : ils gèrent tous les aspects du développement de projets/d'applications pour assurer une cohérence alors qu'un projet comme pipenv
ne le fait pas.
Et quand tu dis :
ce que Pipenv et la poésie font tous les deux (et ni parfaitement)
Que veux-tu dire? D'après ce que j'ai vu, leur gestionnaire de dépendances est beaucoup plus résistant que celui fourni par pipenv
. Le seul inconvénient est qu'ils utilisent l'API PyPI JSON qui n'a parfois pas d'informations de dépendance en raison de packages mal publiés.
Quoi qu'il en soit, je pense, comme vous l'avez dit, que les deux projets peuvent apprendre l'un de l'autre.
Et, encore une chose, quel est l'avenir de pipenv si, finalement, pip gère les Pipfile
? Sera-ce juste un gestionnaire de virtualenv?
Si le gestionnaire de dépendances de poésie s'appuie sur l'API json, ce n'est pas seulement parfois faux en raison de « packages mal publiés », il sera très limité dans ce qu'il peut réellement résoudre correctement. L'api de l'entrepôt json publie les dépendances _les plus récentes_ même si vous avez affaire à une ancienne version, et c'est s'il contient ces informations. Nous avions aussi l'habitude d'intégrer l'API json, c'était super car c'était rapide, mais l'équipe d'infrastructure nous a dit de ne pas lui faire confiance. Il semble un peu fallacieux d'appeler quelque chose de résilient s'il s'appuie sur une source peu fiable pour commencer.
En fin de compte, les défis consistent à créer un graphe de dépendances qui a exécuté un fichier d'installation car actuellement, c'est ainsi que fonctionne l'empaquetage. Il n'y a tout simplement aucun moyen de contourner cela. Un graphique de dépendance qui se résout sur ma machine peut être différent de celui qui se résout sur votre machine, même pour le même package.
Il est facile de faire signe à la main et de dire "Eh bien, cela ne fait-il pas de pipenv un gestionnaire de virtualenv si pip peut lire un pipfile ?" Non. Pipenv est un gestionnaire de dépendances. Il gère les environnements idempotents et génère un fichier de verrouillage reproductible. Je me rends compte que cela doit vous sembler trivial parce que vous le supprimez et réduisez cet outil à un gestionnaire de virtualenv, mais ce n'est pas le cas. Nous résolvons les fichiers de verrouillage et incluons des marqueurs pour les versions de python que vous n'avez pas, que vous n'utilisez pas, et les gardons disponibles afin que vous puissiez déployer et reproduire avec précision sur les plates-formes et les versions de python. Nous utilisons plusieurs méthodes de résolution, notamment la gestion des roues et des fichiers locaux, des référentiels vcs (nous résolvons également le graphique là-bas), des artefacts distants, des packages pypi, des index privés, etc.
À la fin de la journée, pip _sera_ gérer les fichiers pip, c'est le plan, c'est le plan depuis que le format a été créé. Mais c'est la même chose que de demander « mais qu'en est-il du moment où pip peut gérer les fichiers d'exigences ? » La question est fondamentalement identique. Pip peut installer ce format. Cela ne concerne pas vraiment les fonctionnalités que j'ai décrites, à part le fait que nous installons également les fichiers (en utilisant pip, soit dit en passant).
@techalchimie
L'api de l'entrepôt json publie les dépendances les plus récentes même si vous avez affaire à une ancienne version, et c'est s'il a cette information du tout
C'est tout simplement faux, vous pouvez obtenir des dépendances de version spécifiques en appelant https://pypi.org/pypi/{project}/{release}/json
. Si vous appelez simplement https://pypi.org/pypi/{project}/json
vous n'obtiendrez que les dernières dépendances, mais vous pouvez en fait obtenir le bon ensemble de dépendances.
Et la partie packaging/publication des projets python a vraiment besoin d'être améliorée car au final elle profitera à tout le monde, puisqu'elle permettra d'utiliser l'API JSON de manière fiable.
Il gère les environnements idempotents et génère un fichier de verrouillage reproductible.
Nous résolvons les fichiers de verrouillage et incluons des marqueurs pour les versions de python que vous n'avez pas, que vous n'utilisez pas, et les gardons disponibles afin que vous puissiez déployer et reproduire avec précision sur les plates-formes et les versions de python.
Et il en va de même pour poetry
. Et vous pouvez l'empêcher d'utiliser l'API JSON pour utiliser la même méthode de résolution que pipenv
(à l'aide de pip-tools). Voir https://github.com/sdispater/poetry/issues/37#issuecomment -379071989 et il sera toujours plus résistant que pipenv
(https://github.com/sdispater/poetry#dependency-resolution )
@zface Je dirai ceci une dernière fois, veuillez le porter quelque part plus haut dans la hiérarchie. Pipenv ne prétend pas être l'outil d'empaquetage Python officiellement recommandé ; il dit cela parce que dites-le aux responsables qui recommandent Pipenv . S'il vous plaît, ne mettez pas ces choses sur Pipenv dev. Ce n'est pas le bon endroit pour se plaindre, et vous ne pouvez pas obtenir de résolutions pour vos plaintes ici. Vous pouvez également obtenir de meilleures réponses aux questions techniques que vous vous posez. Il s'agit d'un outil de suivi des problèmes pour Pipenv, et non d'un forum de discussion pour les outils d'empaquetage Python et comment l'empaquetage Python est fait.
Pipenv ne s'appuie pas uniquement sur des outils pip pour la résolution, veuillez arrêter de réduire notre logiciel à une seule doublure qui démontre un manque de compréhension. Je connais très bien le fonctionnement de l'api PyPI, j'ai parlé directement à l'équipe qui l'a implémentée.
C'est tout simplement faux,
Ce genre d'attitude n'est pas le bienvenu ici. Ne présumez pas que nous ne comprenons pas de quoi nous parlons. Veuillez pratiquer la courtoisie.
il sera toujours plus résistant que pipenv (https://github.com/sdispater/poetry#dependency-resolution)
Pipenv n'aplatit actuellement pas les graphiques de dépendance. Souligner un problème spécifique où un arbre a été aplati et prétendre que l'ensemble de l'outil est donc à la fois meilleur et plus résistant est insensé, vous prouvez encore et encore que vous êtes simplement là pour insulter pipenv et promouvoir la poésie. S'il vous plaît, passez votre chemin, ce comportement n'est pas le bienvenu.
Je suis d'accord que la discussion est hors sujet, qui essayait de capitaliser les "bonnes pratiques" autour de pipenv.
Cependant,
[...] vous ferez toujours les mêmes erreurs qu'avant avec requirements.txt vs setup.py. Les projets seront toujours mal emballés avec des dépendances mal définies dans leur setup.py à cause de cela.
Je partage cet avis, amener de nouveaux développeurs à packager avec succès leur propre code Python est en fait complexe, trop complexe, nécessite de lire beaucoup de documentation en ligne.
Mais ce n'est pas à pipenv ou à toute autre dépendance de package de gérer cela entièrement. Nous ne pouvions pas réécrire l'histoire. Nous, en tant que communauté, devons trouver un moyen de moderniser la chaîne d'outils Python, étape par étape.
Et pipenv (et probablement la poésie) est un très bon pas en avant.
Avoir à maintenir d'un côté Pipfile
pour l'application et setup.py
pour les bibliothèques de l'autre côté, est une évidence. Peu importe à quel point nous expliquons avec beaucoup de mots et de longs articles et guides de bonnes pratiques, c'est trop complexe pour ce que c'est. Je suis tout à fait d'accord que c'est comme ça pour le moment, mais cela ne devrait pas nous empêcher d'imaginer une voie meilleure et plus sûre.
Au final, en tant que développeur, je veux un seul outil, peut-être avec deux modes différents, pour m'aider et me simplifier la vie au maximum.
Cela devrait être un moyen d'extraire uniquement la partie qui effectue le requirements.txt/Pipfile
partir de bibliothèques telles que PBR pour proposer une sorte de 'easy setup.py', un wrapper compatible avec Pipfile autour de install_requires
, sans tous les comportements indésirables apportés par pbr, et emballez-les dans un wrapper setuptools dédié qui ne fait que cela.
Ainsi, nous serions en mesure d'avoir le meilleur de chaque monde :
Pipfile
(versionné dans les bibliothèques et les applications)Pipfile.lock
(versionné uniquement pour les applications)pipfile_setuptools
, install_requires_pipfile
?) qui serait une dépendance de premier niveau dont le travail consiste uniquement à injecter Pipfile
dans install_requires
.C'est un autre projet qui ne serait pas lié à pipenv
, mais qui nécessite toujours une bibliothèque d'analyseur générique Pipfile
. Qu'est-ce que tu penses?
@gsemet D'après ce que j'ai compris, PyPA a essayé de remplir cela avec pyproject.toml à la place, dirigé par flit . Vous devrez d'abord leur en parler (sur pypa-dev ou distutils-sig) avant de continuer à utiliser Pipfile comme format source. En ce qui concerne l'analyse de Pipfile (et le fichier de verrouillage), elle est gérée dans pypa/pipfile (que les fournisseurs de Pipenv fournissent la logique d'analyse de base).
Edit : Veuillez m'envoyer un message si vous décidez de démarrer une discussion à ce sujet dans l'une ou l'autre liste de diffusion. J'ai quelques idées sur la façon dont nous pouvons réunir les deux parties de la distribution d'emballage Python.
Je dois admettre que je suis un peu triste de voir les dépendances déclarées dans pyproject.toml
(qui prend les rôles de setup.cfg
fait par PBR), alors que PyPa prend également en charge Pipfile
....
Merci pour le pointeur vers flit et pipfile. Il y a aussi le pipenvlib de Kennethreitz qui semble plus léger.
Le setup.cfg de PBR semble plus complet par rapport à la documentation officielle (ex : data_files
) et réutiliser un fichier déjà partagé avec plusieurs outils (flake8, pytest, ...) peut utiliser le même fichier, réduisant le nombre de fichier à la racine d'un projet python)
Commentaire le plus utile
@ Moritz90 Plusieurs listes de diffusion de Python seraient de bons endroits pour tenir cette discussion.
pypa-dev est le plus précis pour les discussions centrées sur l'emballage Python et l'écosystème qui l'entoure. Je commencerais probablement ici si je devais poster une discussion similaire.
python-ideas est un endroit pour discuter d'idées et a une visibilité assez élevée pour l'ensemble de la communauté Python. Ce serait également un bon point de départ si vous souhaitez pousser cela au niveau PEP (éventuellement, vous le feriez, je pense).