Identifizieren der Abhängigkeitsbeziehung für Python-Pakete, die mit pip installiert wurden


151

Wenn ich ein Pip Freeze mache, sehe ich eine große Anzahl von Python-Paketen, die ich nicht explizit installiert habe, z

$ pip freeze
Cheetah==2.4.3
GnuPGInterface==0.3.2
Landscape-Client==11.01
M2Crypto==0.20.1
PAM==0.4.2
PIL==1.1.7
PyYAML==3.09
Twisted-Core==10.2.0
Twisted-Web==10.2.0
(etc.)

Gibt es eine Möglichkeit für mich festzustellen, warum pip diese speziellen abhängigen Pakete installiert hat? Mit anderen Worten, wie bestimme ich das übergeordnete Paket, das diese Pakete als Abhängigkeiten hatte?

Zum Beispiel möchte ich möglicherweise Twisted verwenden und mich nicht auf ein Paket verlassen, bis ich mehr darüber weiß, wie ich es nicht versehentlich deinstalliere oder aktualisiere.

Antworten:


180

Sie können pipdeptree ausprobieren, das Abhängigkeiten als Baumstruktur anzeigt, z.

$ pipdeptree
Lookupy==0.1
wsgiref==0.1.2
argparse==1.2.1
psycopg2==2.5.2
Flask-Script==0.6.6
  - Flask [installed: 0.10.1]
    - Werkzeug [required: >=0.7, installed: 0.9.4]
    - Jinja2 [required: >=2.4, installed: 2.7.2]
      - MarkupSafe [installed: 0.18]
    - itsdangerous [required: >=0.21, installed: 0.23]
alembic==0.6.2
  - SQLAlchemy [required: >=0.7.3, installed: 0.9.1]
  - Mako [installed: 0.9.1]
    - MarkupSafe [required: >=0.9.2, installed: 0.18]
ipython==2.0.0
slugify==0.0.1
redis==2.9.1

Um es zum Laufen zu bringen:

pip install pipdeptree


BEARBEITEN: Wie von @Esteban in den Kommentaren angegeben, können Sie den Baum auch umgekehrt mit -roder für ein einzelnes Paket auflisten -p <package_name>, um herauszufinden, welches installierte Werkzeug Sie ausführen können:

$ pipdeptree -r -p Werkzeug
Werkzeug==0.11.15
  - Flask==0.12 [requires: Werkzeug>=0.7]

6
Ich glaube, um die Frage von @mark vollständig zu beantworten, müssten Sie Folgendes ausführen: pipdeptree -r "Zeigt den Abhängigkeitsbaum in umgekehrter Weise an, dh die Unterabhängigkeiten werden mit der Liste der Pakete aufgelistet, die sie darunter benötigen."
Esteban

Wie können Sie den umgekehrten Baum für alle PyPi-Pakete anzeigen, nicht nur für die lokal installierten Pakete?
Tijme

2
pipdeptreeist toll. Leider scheint es nicht für durch Conda installierten Pakete berücksichtigt Abhängigkeiten zu nehmen: zB in ein Conda env wo matplotlibund numpywurden pip installiert wurde, aber scipywurde mit Conda installiert ist , scipyzeigt sich in der pipdeptree wie keine Depencies hat und keine Familienangehörigen (auch pip show scipyzeigt keine Anforderungen).
DJVG

@ Tennis Ich habe es nicht versucht, aber dies könnte für conda github.com/rvalieris/conda-tree
djsutho

1
Um dies in einer virtuellen Umgebung zu verwenden, müssen Sie etwas python -m pipdeptreeanderes tun (auch wenn die ausführbare Datei auf der virtuellen Umgebung installiert ist), in der nur die Systemabhängigkeiten aufgelistet werden.
Zim

81

Der pip showBefehl zeigt an, welche Pakete für das angegebene Paket erforderlich sind (beachten Sie, dass das angegebene Paket bereits installiert sein muss):

$ pip show specloud

Package: specloud
Version: 0.4.4
Requires:
nose
figleaf
pinocchio

pip show wurde in der Pip-Version 1.4rc5 eingeführt


1
pip showwurde in Version 1.4rc5 eingeführt und ist in der (aktuellen Version) 1.4.1
drevicko

10
Dies beantwortet meine Frage nicht genau, da die Kinder (Abhängigkeiten) für ein bestimmtes Paket anstelle der Eltern angezeigt werden. Mit diesem Befehl ist es jedoch einfach genug, etwas zusammen zu werfen, um die Abhängigkeiten der einzelnen Pakete zu überprüfen. So konnte ich beispielsweise feststellen, für welches installierte Paket PyYAML erforderlich ist.
Mark Chackerian

4
Gemäß meinem vorherigen Kommentar löscht dieser Shell-Befehl alle Abhängigkeiten für jedes meiner installierten Pakete: $ pip freeze | grep -v "\ -e" | sed s /\=\=.*// | awk 'system ("pip show" $ 1)'
Mark Chackerian

Eine aktualisierte Version des Skripts aus meinem vorherigen Kommentar ist pip freeze | grep -v "\-e" | sed s/\=\=.*// | awk 'system("pip show " $1)' | grep -E '^(Name:|Requires:)' | sed s/Name:/\\\nName:/ - aber es scheint, dass pipdeptree jetzt eine bessere Lösung ist.
Mark Chackerian

14

Wie ich kürzlich in einem hn-Thread sagte , empfehle ich Folgendes:

Haben Sie eine kommentierte requirements.txtDatei mit Ihren Hauptabhängigkeiten:

## this is needed for whatever reason
package1

Installieren Sie Ihre Abhängigkeiten : pip install -r requirements.txt. Jetzt erhalten Sie die vollständige Liste Ihrer Abhängigkeiten mit pip freeze -r requirements.txt:

## this is needed for whatever reason
package1==1.2.3

## The following requirements were added by pip --freeze:
package1-dependency1==1.2.3
package1-dependency1==1.2.3

Auf diese Weise können Sie Ihre Dateistruktur mit Kommentaren beibehalten und Ihre Abhängigkeiten von den Abhängigkeiten Ihrer Abhängigkeiten trennen. Auf diese Weise haben Sie eine viel schönere Zeit an dem Tag, an dem Sie eine davon entfernen müssen :)

Beachte das Folgende:

  • Sie können eine saubere requirements.rawVersionskontrolle durchführen, um Ihre vollständige Version wiederherzustellen requirements.txt.
  • Achten Sie darauf, dass Git-URLs dabei nicht durch Eiernamen ersetzt werden.
  • Die Abhängigkeiten Ihrer Abhängigkeiten sind immer noch alphabetisch sortiert, sodass Sie nicht direkt wissen, welche von welchem ​​Paket benötigt wurde, aber zu diesem Zeitpunkt benötigen Sie sie nicht wirklich.
  • Verwenden Sie pip install --no-install <package_name>diese Option, um bestimmte Anforderungen aufzulisten.
  • Verwenden Sie virtualenv, wenn Sie dies nicht tun.

1
Ich verstehe nur nicht, warum dies pip freeze -r requirements.txtnicht weit verbreitet ist. Sehr nützlich für die Pflege der Abhängigkeiten und Unterabhängigkeiten.
Penkey Suresh

1
kleine Anmerkung: pip installnicht mehr unterstützt --no-install.
Ryan

7

Sie können auch einen einzeiligen Befehl verwenden, der die Pakete in den Anforderungen an pip show weiterleitet.

cut -d'=' -f1 requirements.txt | xargs pip show

1
Im Allgemeinen ist dies nicht möglich, da das Format der Anforderung.txt komplexer ist als <package_name>==<package_version>.
Piotr Dobrogost

3

Zunächst pip freezewerden alle derzeit installierten Python-Pakete angezeigt, die nicht unbedingt PIP verwenden.

Zweitens enthalten Python-Pakete Informationen zu abhängigen Paketen sowie erforderliche Versionen . Sie können die Abhängigkeiten eines bestimmten Pakets mit den hier beschriebenen Methoden anzeigen . Wenn Sie ein Paket aktualisieren, übernimmt das Installationsskript wie PIP das Upgrade von Abhängigkeiten für Sie.

Um die Aktualisierung von Paketen zu lösen, empfehle ich die Verwendung von PIP-Anforderungsdateien . Sie können definieren, welche Pakete und Versionen Sie benötigen, und diese sofort mithilfe von pip install installieren.


3

Verwenden pipupgrade !

$ pip install pipupgrade
$ pipupgrade --format tree --all --check

pipupgrade zeigt ein Abhängigkeitsdiagramm an und hebt jedes Paket für eine mögliche Aktualisierung hervor (basierend auf der semantischen Versionierung). Außerdem werden widersprüchliche untergeordnete Abhängigkeiten auf hübsche Weise angezeigt. pipupgradestellt außerdem sicher, dass Pakete aktualisiert werden, die in mehreren Python-Umgebungen vorhanden sind. Kompatibel mit Python2.7 +, Python3.4 + und pip9 +, pip10 +, pip18 +, pip19 +.

Geben Sie hier die Bildbeschreibung ein


1

(Problemumgehung, keine wahre Antwort)

Hatte das gleiche Problem, da lxml nicht installiert wurde und ich wissen wollte, wer lxml benötigt. Nicht wer lxml brauchte . Das Problem wurde umgangen.

  1. Feststellen, wo meine Site-Pakete abgelegt wurden.

  2. Gehen Sie dorthin und rekursives grep für den Import (das --invert-match des letzten grep dient dazu, die eigenen Dateien von lxml aus der Betrachtung zu entfernen).

Ja, keine Antwort darauf, wie man Pip verwendet, aber ich habe aus irgendeinem Grund keinen Erfolg mit den Vorschlägen hier erzielt.

 site-packages me$ egrep -i --include=*.py  -r -n lxml . | grep import | grep --invert-match /lxml/

1

Ich habe ein schnelles Skript geschrieben, um dieses Problem zu lösen. Das folgende Skript zeigt die übergeordneten (abhängigen) Pakete für ein bestimmtes Paket an. Auf diese Weise können Sie sicher sein, dass ein Upgrade oder die Installation eines bestimmten Pakets sicher ist. Es kann wie folgt verwendet werden:dependants.py PACKAGENAME

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""Find dependants of a Python package"""

import logging
import pip
import pkg_resources
import sys

__program__ = 'dependants.py'


def get_dependants(target_name):
    for package in pip._internal.utils.misc.get_installed_distributions():
        for requirement_package in package.requires():
            requirement_name = requirement_package.project_name
            if requirement_name == target_name:
                yield package.project_name


# configure logging
logging.basicConfig(format='%(levelname)s: %(message)s',
                    level=logging.INFO)

try:
    target_name = sys.argv[1]
except IndexError:
    logging.error('missing package name')
    sys.exit(1)

try:
    pkg_resources.get_distribution(target_name)
except pkg_resources.DistributionNotFound:
    logging.error("'%s' is not a valid package", target_name)
    sys.exit(1)

print(list(get_dependants(target_name)))

Dies funktioniert nicht mehr, da die get_installed_distributions()Methode nicht mehr verfügbar ist. github.com/pypa/pip/issues/5243
Phil Gyford
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.