Hoe de afhankelijkheden van een Python-pakket te vinden

Hoe kun je programmatisch de lijst met afhankelijkheden van een Python-pakket ophalen?

De standaard setup.pyheeft deze gedocumenteerd, maar ik kan geen gemakkelijke manier vinden om deze te openen vanuitPython of de opdrachtregel.

Idealiter zoek ik iets als:

$ pip install somepackage --only-list-deps
kombu>=3.0.8
billiard>=3.3.0.13
boto>=2.26

of:

>>> import package_deps
>>> package = package_deps.find('somepackage')
>>> print package.dependencies
['kombu>=3.0.8', 'billiard>=3.3.0.13', 'boto>=2.26']

Opmerking, ik heb het niet over het importeren van een pakket en het vinden van alle modules waarnaar wordt verwezen. Hoewel dit de meeste afhankelijke pakketten zou kunnen vinden, zou het niet in staat zijn om het minimaal vereiste versienummer te vinden. Dat wordt alleen opgeslagen in setup.py.


Antwoord 1, autoriteit 100%

Naast de opdracht pip show [package name]is er pipdeptree.

Gewoon doen

$ pip install pipdeptree

ren dan

$ pipdeptree

en het zal u uw afhankelijkheden laten zien in een boomvorm, bijvoorbeeld

flake8==2.5.0
  - mccabe [required: >=0.2.1,<0.4, installed: 0.3.1]
  - pep8 [required: !=1.6.0,>=1.5.7,!=1.6.1,!=1.6.2, installed: 1.5.7]
  - pyflakes [required: >=0.8.1,<1.1, installed: 1.0.0]
ipdb==0.8
  - ipython [required: >=0.10, installed: 1.1.0]

Het project bevindt zich op https://github.com/naiquevin/pipdeptree, waar u vind ook gebruiksinformatie.


Antwoord 2, autoriteit 63%

Probeer de opdracht showte gebruiken in pip, bijvoorbeeld:

$ pip show tornado
---
Name: tornado
Version: 4.1
Location: *****
Requires: certifi, backports.ssl-match-hostname

Update(haal deps op met gespecificeerde versie):

from pip._vendor import pkg_resources
_package_name = 'somepackage'
_package = pkg_resources.working_set.by_key[_package_name]
print([str(r) for r in _package.requires()])  # retrieve deps from setup.py

Output: ['kombu>=3.0.8', 
         'billiard>=3.3.0.13', 
         'boto>=2.26']

Antwoord 3, autoriteit 9%

Korte samenvatting van de methoden die zijn gevonden en getest op de Windows-computer:

  1. Ontdek het json-bestand van PyPI: https://pypi.org/pypi/<package>/<version>/json(#7)

  2. Controleer /site-packages/<package-version>.dist-info/METADATA(#13, pre-installatie vereist)

  3. pip install --no-install <package>: verouderd (#11)

  4. pip install --download <package>: verouderd (#12)

  5. pip show <package>(#1, #2, pre-installatie vereist)

  6. Schrijf een script met import pipen pip._vendor.pkg_resources: verouderd (#6)

  7. Schrijf een script met import pkg_resourcesvan het pakket setuptools(#4 , pre-installatie vereist)

  8. https://libraries.io/(#5)

  9. Gebruik pipdeptree-pakket (#3, #8, pre-installatie vereist)

  10. Gebruik Johnnydep-pakket (#10): de test loopt in veel gevallen vast.

  11. conda info [package_name]: verouderd (#9)

  12. conda search [package_name] --info

  • Houd er rekening mee dat extra pakketten kunnen worden vermeld: vc2015_runtime, python_abi, libflang, en etc.
  • Houd er rekening mee dat deze methode verschillende pakketten kan weergeven, afhankelijk van de build en het kanaal.
    bijv. conda search "Django==3.2" --info -c conda-forge
django 3.2 pyhd3eb1b0_0
-----------------------
file name   : django-3.2-pyhd3eb1b0_0.conda
...
timestamp   : 2021-04-06 20:19:41 UTC
dependencies:
  - asgiref
  - psycopg2
  - python
  - pytz
  - sqlparse
django 3.2 pyhd8ed1ab_0
-----------------------
file name   : django-3.2-pyhd8ed1ab_0.tar.bz2
...
timestamp   : 2021-04-07 21:15:25 UTC
dependencies:
  - asgiref >=3.3.2,<4
  - python >=3.6
  - pytz
  - sqlparse >=0.2.2

Nog iets om op te merken is dat elke methode een ander resultaat kan opleveren.

Bijvoorbeeld requests/setup.pyidentificeert chardet, idna, urllib3en certifizijn vereist. Bovendien extra pakketten pyOpenSSL, cryptography, socks, PySocks, win-inet-ptonkan nodig zijn.

  • Methoden 1 en 2 stemmen ermee in.
  • Methode 8 somt ze gewoon allemaal op (druk op de knop Afhankelijkheden verkennen blijft hangen).
  • Methode 12 vermeldt gewoon chardet, idna, urllib3en certifi.
  • Methode 5 en 7 vermelden geen afhankelijkheid als requestsis geïnstalleerd met behulp van pipin de Linux-docker.
  • Methode 5, 7, 9 en 10 vermelden chardet, idna, urllib3en certifiindien requestsis geïnstalleerd in de conda-omgeving van de Windows-machine.

Antwoord 4, autoriteit 8%

Heel wat antwoorden hier laten zien dat pip wordt geïmporteerd voor gebruik in programma’s. De documentatie voor pip raadt dit gebruik van pip ten zeerste af.

In plaats van toegang te krijgen tot pkg_resourcesvia de pip-import, kun je pkg_resourcesrechtstreeks importeren en dezelfde logica gebruiken (wat eigenlijk een van de voorgestelde oplossingen in de pip is). docs gelinkt voor iedereen die pakketmeta-informatie programmatisch wil zien) .

import pkg_resources
_package_name = 'yourpackagename'
def get_dependencies_with_semver_string():
    package = pkg_resources.working_set.by_key[_package_name]
    return [str(r) for r in package.requires()]

Als u problemen ondervindt om erachter te komen wat uw pakketnaam is, implementeert de WorkingSet-instantie die wordt geretourneerd door pkg_resources.working_set__iter__dus je kunt ze allemaal afdrukken en hopelijk de jouwe daar vinden 🙂

d.w.z.

import pkg_resources
def print_all_in_working_set():
    ws = pkg_resources.working_set
    for package_metadata in ws:
        print(package_metadata)

Dit werkt met zowel python 2 als 3 (hoewel je de printinstructies voor python2 moet aanpassen).


Antwoord 5, autoriteit 6%

Gebruik https://libraries.io/. Het is een goede plek om afhankelijkheden te onderzoeken voordat je pip installeert.

Bijv. Typ google-cloud-storage en zoek, dan kun je de pagina voor de bibliotheek vinden (https:// libraries.io/rubygems/google-cloud-storage). Selecteer de versie waarvan u de afhankelijkheden wilt verkennen uit de ‘Releases’ (standaard is de nieuwste), Onder ‘Afhankelijkheden’ vindt u de afhankelijkheidslijst en hun ondersteunde versies.


Antwoord 6, autoriteit 3%

(DIT IS EEN OUDER ANTWOORD EN MOET WORDEN VERMIJDEN VOOR MODERNE PIP-VERSIES EN HIER WORDEN GELADEN VOOR VERWIJZING NAAR OUDERE PIP-VERSIES)
Het antwoord van Alex is goed (+1). In python:

pip._vendor.pkg_resources.working_set.by_key['twisted'].requires()

zou iets moeten retourneren als

[Requirement.parse('zope.interface>=3.6.0')]

waarbij twisted de naam van het pakket is, die je in het woordenboek kunt vinden:

pip._vendor.pkg_resources.WorkingSet().entry_keys

om ze allemaal op te sommen:

dict = pip._vendor.pkg_resources.WorkingSet().entry_keys
for key in dict:
    for name in dict[key]:
        req =pip._vendor.pkg_resources.working_set.by_key[name].requires()
        print('pkg {} from {} requires {}'.format(name,
                                                  key,
                                                  req))

zou je lijsten als deze moeten geven:

pkg pyobjc-framework-syncservices from /System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC requires [Requirement.parse('pyobjc-core>=2.5.1'), Requirement.parse('pyobjc-framework-Cocoa>=2.5.1'), Requirement.parse('pyobjc-framework-CoreData>=2.5.1')]

Antwoord 7, autoriteit 2%

Er is de leuke tool johnnydep. Het voordeel hiervan is dat het te inspecteren pakket niet geïnstalleerd hoeft te worden.

pip install johnnydep

Gebruik het als:

johnnydep deepspeech-tflite

Antwoord 8

Probeer dit volgens dit artikelin python:

import pip 
installed_packages = pip.get_installed_distributions()
installed_packages_list = sorted(["%s==%s" % (i.key, i.version)
     for i in installed_packages]) 
print(installed_packages_list)

Het wordt weergegeven als:

['behave==1.2.4', 'enum34==1.0', 'flask==0.10.1', 'itsdangerous==0.24', 
 'jinja2==2.7.2', 'jsonschema==2.3.0', 'markupsafe==0.23', 'nose==1.3.3', 
 'parse-type==0.3.4', 'parse==1.6.4', 'prettytable==0.7.2', 'requests==2.3.0',
 'six==1.6.1', 'vioozer-metadata==0.1', 'vioozer-users-server==0.1', 
 'werkzeug==0.9.4']

Antwoord 9

De standaardbibliotheek biedt importlib.metadata.requires()sinds versie 3.8 en later:

In [1]: from importlib.metadata import requires
In [2]: requires('pytype')
Out[2]:
['attrs (>=21.2.0)',
 'importlab (>=0.6.1)',
 'libcst',
 'ninja (>=1.10.0.post2)',
 'pyyaml (>=3.11)',
 'six',
 'tabulate',
 'toml',
 'typed-ast (>=1.4.3)',
 'dataclasses ; python_version < "3.7"']

Voor oudere Python-versies is er de importlib-metadatabeschikbaar. Verwante sectie in Python-documenten: Distributievereisten.

Als je de strings moet ontleden die worden geretourneerd door requires(), raad ik je ten zeerste aan om de packaging-bibliotheek te gebruiken sinds de packaging.requirementsmodule is een referentie-implementatie van PEP 508. Voorbeeld met een complexe specificatiereeks voor afhankelijkheid:

In [3]: from packaging.requirements import Requirement
In [4]: spec = 'requests [security,test] (>=2.21.0) ; implementation_name == "cpython"'
In [5]: r = Requirement(spec)
In [6]: r.name
Out[6]: 'requests'
In [7]: r.specifier
Out[7]: <SpecifierSet('>=2.21.0')>
In [8]: r.extras
Out[8]: {'security', 'test'}
In [9]: r.marker
Out[9]: <Marker('implementation_name == "cpython"')>

Other episodes