web-dev-qa-db-fra.com

Python enfer des dépendances: un compromis entre virtualenv et les dépendances globales?

J'ai testé différentes façons de gérer les dépendances de mon projet dans Python jusqu'à présent:

  1. Installer tout global avec pip (économise de l'espace, mais tôt ou tard vous pose des problèmes)
  2. pip & venv ou virtualenv (un peu pénible à gérer, mais ok dans de nombreux cas)
  3. pipenv & pipfile (un peu plus facile que venv/virtualenv, mais lent et certains verrous du fournisseur, les envs virtuels se cachent ailleurs que dans le dossier du projet réel)
  4. conda en tant que gestionnaire de packages et d'environnement (idéal tant que les packages sont tous disponibles en conda, mélanger pip et conda est un peu hacky)
  5. Poésie - je n'ai pas essayé celui-ci
  6. ...

Mon problème avec tout cela (sauf 1.) est que mon espace disque dur se remplit assez rapidement: je ne suis pas développeur, j'utilise Python pour mon travail quotidien. Par conséquent, j'ai des centaines de petits projets qui font tous leur travail. Malheureusement, pour 80% des projets j'ai besoin des "gros" packages: numpy, pandas, scipy, matplotlib - vous l'appelez. Un petit projet typique est d'environ 1000 à 2000 lignes de code, mais a 800 Mo de dépendances de paquet dans venv/virtualenv/pipenv. Virtuellement J'ai environ 100+ Go de mon disque dur rempli avec python dépendances virtuelles.

De plus, l'installation de tous ces éléments dans chaque environnement virtuel prend du temps. Je travaille sous Windows, de nombreux packages ne peuvent pas être facilement installés à partir de pip dans Windows: Shapely, Fiona, GDAL - J'ai besoin des roues précompilées de Christoph Gohlke . C'est facile, mais cela interrompt la plupart des workflows (par exemple pip install -r requirements.txt ou pipenv install du fichier pip). Je sens que j'installe/met à jour 40% des dépendances de packages et seulement 60% de mon temps à écrire du code. De plus, aucun de ces gestionnaires de packages n'aide vraiment à publier et tester le code, j'ai donc besoin d'autres outils, par exemple setuptools, tox, semantic-release, twine...

J'ai parlé à des collègues mais ils sont tous confrontés au même problème et personne ne semble avoir de vraie solution. Je me demandais s'il y avait une approche pour avoir des paquets, par exemple ceux que vous utilisez dans la plupart des projets, installés globalement - par exemple, numpy, pandas, scipy, matplotlib seraient installés avec pip dans C:\Python36\Lib\site-packages ou avec conda dans C:\ProgramData\Miniconda3\Lib\site-packages - ce sont des paquets bien développés qui ne cassent pas souvent les choses. Et si, je voudrais résoudre ce problème de toute façon bientôt dans mes projets.

D'autres choses iraient dans les dossiers virtualenv locaux - je suis tenté de déplacer mon flux de travail actuel de pipenv vers conda.

Une telle approche a-t-elle un sens? Au moins, il y a eu beaucoup de développement récemment en python, peut-être que quelque chose a émergé que je n'ai pas encore vu. Existe-t-il des conseils sur les meilleures pratiques pour configurer des fichiers dans un tel environnement global-local mixte, par exemple comment maintenir setup.py, requirements.txt ou pyproject.toml pour partager des projets de développement via Gitlab, Github, etc.? Quels sont les pièges/mises en garde?

Il y a aussi ce super article de blog de Chris Warrick qui l'explique assez bien.

[Mise à jour]

Après six mois, je peux dire que travailler avec Conda a résolu la plupart de mes problèmes:

  • il fonctionne sur tous les systèmes, WSL, Windows, Linux natif, etc. conda env create -f myenv.yml est le même sur toutes les plateformes
  • la plupart des packages sont déjà disponibles sur conda-forge, il est facile de faire accepter ses propres packages sur conda-forge
  • pour les packages qui ne sont pas sous conda, je peux installer pip dans l'environnement conda et ajouter des packages depuis pypi avec pip. Astuce: conda update --all -n myenv -c conda-forge ne mettra à jour que les paquets de conda, pas ceux installés avec pip. Les dépendances installées par Pip doivent être mises à jour manuellement avec pip install pack_name --upgrade. Notez que l'installation de packages avec pip dans conda est une solution d'urgence qui devrait généralement être évitée
  • Je peux créer strict ou ouvert environment.yml, spécifiant la priorité du canal conda, les packages de conda et les packages de pip
  • Je peux créer des environnements conda à partir de ces yml dans une seule instruction, par exemple pour configurer un environnement de développement dans Gitlab Continuous Integration, en utilisant le Miniconda3 Docker - cela rend les tests très simples et directs
  • les versions des packages dans ymls peuvent être définies comme strictes ou ouvertes, selon la situation. Par exemple. vous pouvez corriger l'env à Python 3.6, mais faites-le récupérer toutes les mises à jour de sécurité dans cette gamme de versions (par exemple 3.6.9)
  • J'ai trouvé que conda résout presque tous les problèmes avec les dépendances compilées en c dans Windows; les envs conda dans Windows permettent de geler python code dans un exécutable (testé!) qui peut être distribué aux utilisateurs finaux de Windows qui ne peuvent pas utiliser les gestionnaires de paquets pour une raison quelconque.
  • concernant le problème des "grandes dépendances": j'ai fini par créer de nombreux environnements de conda spécifiques (c.-à-d. petits) et quelques environnements de conda non spécifiques (c.-à-d. grands): par exemple, j'ai un assez grand jupyter_env, où jupyter lab et la plupart de mes packages scientifiques sont installés (numpy, geos, pandas scipy etc.) - Je l'active chaque fois que j'ai besoin d'accéder à ces outils, je peux les garder en place à ce jour en un seul endroit. Pour le développement de packages spécifiques, j'ai des environnements supplémentaires qui ne sont utilisés que pour les dépendances des packages (par exemple packe1_env). J'ai environ 10 environemnts dans l'ensemble, ce qui est gérable. Certains outils à usage général sont installés dans l'environnement de conda de base, par ex. pylint. Soyez averti: pour faire fonctionner pylint/pycodestyle/autopep8 etc. (par exemple) dans VS Code, il doit être installé sur le même env qui contient les dépendances de code python - sinon, vous obtiendrez des avertissements d'importation non résolus
  • J'ai installé mini conda avec Chocolatey gestionnaire de paquets pour Windows. Je le tiens à jour avec conda update -n base conda, et mes envies avec conda update --all -n myenv -c conda-forge une fois par semaine, fonctionne comme un charme!
  • Nouvelle mise à jour: l'une des fonctionnalités les plus impressionnantes: la nouvelle --stack flag permet d'empiler des environnements conda, par ex. conda activate my_big_env puis conda activate --stack dev_tools_env (à partir du 2019-02-07 ) permet de rendre certains packages à usage général disponibles dans de nombreux environnements
  • Nouvelle mise à jour 2 : j'ai commencé à utiliser conda à partir de Windows Subsystem for Linux (WSL), cela a encore amélioré mon flux de travail de manière significative: les packages sont installés plus rapidement, je peux travailler avec VS Code Insiders dans Windows directement connecté à WSL et il y a beaucoup moins de bugs avec python packages dans l'environnement Linux.
  • oui, je suis tombé sur des problèmes de compatibilité entre certains packages dans un conda env, mais très rarement. Il existe deux approches: s'il s'agit d'un env important qui doit fonctionner de manière stable, activez conda config --env --set channel_priority strict - cela n'installera que les versions compatibles. Avec de très rares et rares combinaisons de packages, cela peut entraîner des conflits de dépendance insolubles (c'est-à-dire que l'env ne peut pas être créé). Dans ce cas, je crée généralement des envs plus petits pour le développement expérimental, avec moins de packages et channel_priority défini sur flexible (par défaut). C'est également une bonne approche pour essayer des versions inférieures python pour les environnements expérimentaux qui ne peuvent pas être résolus avec strict, par exemple conda create -n jupyter_exp_env python=3.6 -c conda-forge. Un hack de dernier recours consiste à installer des packages avec pip, ce qui évite le résolveur de packages de conda (mais peut entraîner des environnements instables et d'autres problèmes, vous avez été averti!). Assurez-vous d'installer explicitement pip dans votre env en premier.

Un inconvénient général est que le conda devient un peu lent lors de l'utilisation du grand canal de conda-forge. Ils sont y travaillent , mais en même temps, l'indice de conda-forge se développe très rapidement.

16
Alex

Problème

Vous avez répertorié un certain nombre de problèmes qu'aucune approche ne peut résoudre complètement:

  • espace

'J'ai besoin des "gros" packages: numpy, pandas, scipy, matplotlib ... Virtuellement, j'ai environ 100+ Go de mon disque dur rempli de python dépendances virtuelles)

  • le temps

... l'installation de tous ces éléments dans chaque environnement virtuel prend du temps

  • publication

... aucun de ces gestionnaires de packages n'a vraiment aidé à publier et tester le code ...

  • workflow

Je suis tenté de déplacer mon flux de travail actuel de pipenv vers conda.

Heureusement, ce que vous avez décrit n'est pas tout à fait le problème de dépendance classique qui afflige les gestionnaires de packages - dépendances circulaires, épinglage des dépendances, versioning, etc.


Détails

J'ai utilisé conda sur Windows depuis de nombreuses années sous des restrictions similaires avec un succès raisonnable. Conda a été initialement conçu pour faciliter l'installation des paquets liés à scipy. C'est toujours le cas.

Si vous utilisez la "pile scipy" (scipy, numpy, pandas, ...), conda est votre choix le plus fiable.

Conda peut :

  • installer des packages scipy
  • installer des extensions C et des packages non Python (nécessaires pour exécuter numpy et d'autres packages)
  • intégrer des packages de conda, des canaux de conda (vous devriez vérifier cela) et pip pour accéder aux packages
  • séparation des dépendances avec les environnements virtuels

Conda ne peut pas :

  • aide à la publication du code

Env reproductibles

Les étapes suivantes devraient aider à reproduire virtualenvs si nécessaire:

  • N'installez pas de paquets scipy avec pip. Je comptais sur conda pour faire le gros du travail. C'est beaucoup plus rapide et plus stable. Vous pouvez installer des packages moins courants dans des environnements conda.
  • À l'occasion, un package pip peut entrer en conflit avec des packages conda dans un environnement (voir notes de version traitant de ce problème).

Évitez les problèmes de pip:

Je me demandais s'il y avait une approche pour avoir des paquets, par exemple ceux que vous utilisez dans la plupart des projets, installés à l'échelle mondiale ... D'autres choses iraient dans les dossiers virtualenv locaux

A. Faites un environnement de travail distinct de votre environnement de base, par ex. workenv. Considérez ceci comme votre envoi "global" pour faire une grande partie de votre travail quotidien.

> conda create -n workenv python=3.7 numpy pandas matplotblib scipy
> activate workenv
(workenv)>

B. Tester les installations de packages de pip inhabituels (ou de packages de conda lourds) dans un clone de l'environnement de travail

> conda create --name testenv --clone workenv
> activate testenv
(testenv)> pip install pint

Vous pouvez également créer de nouveaux environnements avec un minimum de packages à l'aide d'un requirements.txt fichier

C. Faites une sauvegarde des dépendances dans un requirements.txt- fichier similaire appelé environment.yaml par virtualenv. Créez éventuellement un script pour exécuter cette commande par environnement. Voir docs . Créez des environnements dans le futur à partir de ce fichier:

> conda create --name testenv --file environment.yml
> activate testenv
(testenv)> conda list

Publication

Le problème de l'emballage est un problème continu et distinct qui a gagné du terrain avec l'avènement de pyproject.toml fichier via PEP 518 (voir le sujet article de blog de l'auteur B. Cannon). Des outils de packaging tels que flit ou poetry ont adopté cette convention moderne pour effectuer des distributions et les publier sur un serveur ou un index de packaging (PyPI ). Le pyproject.toml le concept tente de s'éloigner du traditionnel setup.py fichiers avec une dépendance spécifique à setuptools.

Dépendances

Des outils tels que pipenv et poetry ont une approche moderne unique pour résoudre le problème de dépendance via un fichier "lock". Ce fichier vous permet de suivre et de reproduire l'état de vos graphiques de dépendance, quelque chose de nouveau dans le monde de l'emballage Python jusqu'à présent (voir plus sur Pipfile vs setup.pyici ). De plus, certains prétendent que vous pouvez toujours utiliser ces outils en conjonction avec conda, même si je n'ai pas testé l'étendue de ces allégations. Le fichier de verrouillage n'est pas encore standardisé, mais selon le développeur principal B. Canon dans une interview on L'avenir de Python packaging =, (~ 33m) "J'aimerais nous y amener."

Résumé

Si vous travaillez avec n'importe quel paquet de la pile scipy, utilisez conda ( Recommandé):

  • Pour économiser de l'espace, du temps et des problèmes de workflow, utilisez conda ou miniconda.
  • Pour résoudre le déploiement d'applications ou l'utilisation d'un fichier "verrouillé" sur vos dépendances, tenez compte des éléments suivants conjointement avec conda:
    • pipenv: utilisez pour déployer et créer Pipfile.lock
    • poetry: utilisez pour déployer et créer poetry.lock
  • Pour publier une bibliothèque sur PyPI, pensez à:
    • pipenv: développer via pipenv install -e. et publier manuellement avec ficelle
    • flit: empaqueter et * publier automatiquement
    • poetry: empaqueter automatiquement et publier

Voir aussi

  • Entretien en balado avec B. Cannon sur le problème général de l'emballage, pyproject.toml , verrouiller les fichiers et outils .
  • Interview en podcast avec K. Reitz discutant de l'emballage outils (pipenv vs pip, 37m) et de l'environnement de développement.
4
pylang

Je me demandais s'il y avait une approche pour avoir des paquets, par exemple ceux que vous utilisez dans la plupart des projets, installés à l'échelle mondiale ... D'autres choses iraient dans les dossiers virtualenv locaux

Oui, virtualenv prend en charge cela. Installez globalement les packages nécessaires globalement, puis, chaque fois que vous créez un virtualenv, fournissez le --system-site-packages option pour que le virtualenv résultant puisse toujours utiliser les packages installés globalement. Lorsque vous utilisez tox, vous pouvez définir cette option dans les virtualenvs créés en incluant sitepackages=true dans le [testenv] sections).

10
jwodder

Une mise à jour sur mes progrès:

Le gestionnaire de paquets Conda s'est avéré mieux fonctionner que pipenv pour les raisons suivantes:

  • par défaut, les dépendances globales sont disponibles à partir d'environnements virtuels conda
  • il est plus rapide que pipenv lors de l'installation/mise à jour des dépendances
  • combiner pip et conda n'est vraiment pas si problématique, pour tout ce qui comprend un package conda, installez avec conda, sinon installez simplement avec pip
  • en utilisant environment.yml, il est possible d'avoir un environnement et des dépendances recréés sur Linux et Windows en quelques secondes - environment.yml permet de spécifier les dépendances pip et conda séparément (par exemple, cela résout les problèmes ci-dessus avec Fiona, Shapely , GDal etc. sous Windows, en utilisant des versions conda)
  • conda résout la plupart des difficultés de maintenance des packages/dépendances sur toutes les plateformes (par exemple linux, mac, win)
  • ce n'était pas un problème d'avoir conda (par exemple miniconda) installé côte à côte sur une installation indépendante python et utilisez conda via conda run
  • si environnements.yml est manquant, il est possible de créer un env à partir de requirements.txt (conda create -n new environment --file requirements.txt)

Malheureusement, le processus de création du environment.yml Ne semble pas vraiment décrit de manière cohérente nulle part. Après un certain temps, j'ai réalisé que le fichier créé automatiquement (conda env export environment.yml) devrait être modifié manuellement pour contenir la liste de dépendances la moins possible (et laisser conda résoudre le reste à l'installation). Sinon, le fichier environment.yml ne sera pas compatible entre les systèmes.

Quoi qu'il en soit, ce flux de travail résout la plupart de mes problèmes décrits ci-dessus et je suis plutôt content de ne plus avoir besoin d'utiliser pipenv ou virtualenv.

Il y a encore quelques inconvénients,

  1. Il faut maintenir les dépendances dans plusieurs fichiers:

    • setup.py
    • environment.yml
  2. Il n'est pas possible d'exécuter un programme directement (par exemple avec un raccourci) dans son environnement, par exemple cela fonctionne sans problème avec pipenv run, mais:
    • conda run Ne sera pas automatiquement source activate env
    • c'est un problème ouvert et peut être résolu un jour
  3. cx_freeze n'inclura pas correctement les dépendances globales de l'extérieur conda env
  4. conda sera difficile si vous avez besoin de dépendances qui nécessitent une compilation (par exemple C-Extensions, etc.), voir ci-dessous ou ici
1
Alex