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.

Mark Chackerian
quelle

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]
djsutho
quelle
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

BernardoBarreto
quelle
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.
Maxime R.
quelle
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
Biophetik
quelle
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.

Mariusz Jamro
quelle
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

Achilles Gasper Rasquinha
quelle
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/
JL Peyret
quelle
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)))
Sechs
quelle
Dies funktioniert nicht mehr, da die get_installed_distributions()Methode nicht mehr verfügbar ist. github.com/pypa/pip/issues/5243
Phil Gyford