Identificazione della relazione di dipendenza per i pacchetti python installati con pip


151

Quando eseguo un congelamento del pip vedo un gran numero di pacchetti Python che non ho installato esplicitamente, ad es

$ 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.)

Esiste un modo per determinare perché pip ha installato questi pacchetti dipendenti specifici? In altre parole, come posso determinare il pacchetto padre che aveva questi pacchetti come dipendenze?

Ad esempio, potrei voler usare Twisted e non voglio dipendere da un pacchetto fino a quando non saprò di più su come non disinstallarlo accidentalmente o aggiornarlo.

Risposte:


180

È possibile provare pipdeptree che visualizza le dipendenze come una struttura ad albero, ad esempio:

$ 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

Per farlo funzionare:

pip install pipdeptree


EDIT: come notato da @Esteban nei commenti puoi anche elencare l'albero al contrario con -ro per un singolo pacchetto con -p <package_name>così per trovare quale Werkzeug installato potresti eseguire:

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

6
Credo che per rispondere pienamente alla domanda di @mark che dovresti eseguire: pipdeptree -r "Mostra l'albero delle dipendenze al contrario, cioè le sotto-dipendenze sono elencate con la lista dei pacchetti che ne hanno bisogno sotto di esse".
Esteban,

Come visualizzare l'albero inverso per tutti i pacchetti PyPi, non solo i pacchetti installati localmente?
Tijme,

2
pipdeptreeè grande. Sfortunatamente non sembra prendere in considerazione le dipendenze per i pacchetti installati da conda: ad es. In un conda env dove matplotlibe numpysono stati installati usando pip, ma è scipystato installato usando conda, si scipypresenta nel pipdeptree come privo di dipendenze e dipendenti ( pip show scipymostra anche no requisiti).
djvg,

@Dennis Non l'ho provato, ma potrebbe funzionare per conda github.com/rvalieris/conda-tree
djsutho,

1
Per usarlo in un ambiente virtuale, è necessario fare python -m pipdeptreediversamente (anche quando l'eseguibile è installato su virtualenv) elenca solo le dipendenze del sistema.
Zim

81

Il pip showcomando mostrerà quali pacchetti sono richiesti per il pacchetto specificato (si noti che il pacchetto specificato deve essere già installato):

$ pip show specloud

Package: specloud
Version: 0.4.4
Requires:
nose
figleaf
pinocchio

pip show è stato introdotto nella versione pip 1.4rc5


1
pip showè stato introdotto nella versione 1.4rc5 ed è presente nell'attuale versione 1.4.1
drevicko

10
Questo non risponde esattamente alla mia domanda, perché mostra i figli (dipendenze) per un pacchetto specifico, anziché i genitori. Ma è abbastanza facile mettere insieme qualcosa per controllare le dipendenze di ciascun pacchetto, usando questo comando. Quindi, ad esempio, potrei determinare quale pacchetto installato ha richiesto PyYAML.
Mark Chackerian,

4
Come per il mio commento precedente, questo comando shell scarica tutte le dipendenze per ciascuno dei miei pacchetti installati: $ pip freeze | grep -v "\ -e" | sed s /\=\=.*// | awk 'system ("pip show" $ 1)'
Mark Chackerian,

Una versione aggiornata dello script del mio commento precedente è pip freeze | grep -v "\-e" | sed s/\=\=.*// | awk 'system("pip show " $1)' | grep -E '^(Name:|Requires:)' | sed s/Name:/\\\nName:/ - ma sembra che pipdeptree sia ora una soluzione migliore.
Mark Chackerian,

14

Come ho detto di recente su un thread hn , consiglierò quanto segue:

Avere un requirements.txtfile commentato con le tue dipendenze principali:

## this is needed for whatever reason
package1

Installare le dipendenze: pip install -r requirements.txt. Ora ottieni l'elenco completo delle tue dipendenze con 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

Ciò consente di mantenere la struttura del file con i commenti, separando in modo preciso le dipendenze dalle dipendenze delle dipendenze. In questo modo avrai un momento molto più bello il giorno in cui dovrai rimuoverne uno :)

Nota quanto segue:

  • Puoi avere un requirements.rawcontrollo pulito della versione per ricostruire il tuo completo requirements.txt.
  • Fai attenzione agli URL Git che vengono sostituiti dai nomi delle uova nel processo.
  • Le dipendenze delle tue dipendenze sono ancora in ordine alfabetico, quindi non sai direttamente quale era richiesto da quale pacchetto ma a questo punto non ne hai davvero bisogno.
  • Utilizzare pip install --no-install <package_name>per elencare requisiti specifici.
  • Usa virtualenv se non lo fai.

1
Non capisco perché questo pip freeze -r requirements.txtnon sia ampiamente usato. Molto utile per mantenere le dipendenze e le dipendenze secondarie.
Penkey Suresh,

1
nota minore: pip installnon supporta più --no-install.
Ryan,

7

È inoltre possibile utilizzare un comando a una riga che convoglia i pacchetti nei requisiti per pip show.

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

1
Generalmente non è possibile in quanto il formato di requisito.txt è più complesso di <package_name>==<package_version>.
Piotr Dobrogost,

3

Prima di tutto pip freezemostra tutti i pacchetti attualmente installati Python, non necessariamente usando PIP.

In secondo luogo, i pacchetti Python contengono le informazioni sui pacchetti dipendenti e sulle versioni richieste . Puoi vedere le dipendenze di particolari pkg usando i metodi descritti qui . Quando aggiorni un pacchetto, lo script di installazione come PIP gestirà l'aggiornamento delle dipendenze per te.

Per risolvere l'aggiornamento dei pacchetti, consiglio di utilizzare i file dei requisiti PIP . È possibile definire quali pacchetti e versioni sono necessari e installarli contemporaneamente usando pip install.


3

Usa pipupgrade !

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

pipupgrade visualizza un grafico delle dipendenze ed evidenzia ogni pacchetto per un possibile aggiornamento (basato sul controllo delle versioni semantico). Mostra anche le dipendenze dei bambini in conflitto in modo carino. pipupgradegarantisce inoltre di aggiornare i pacchetti presenti all'interno di più ambienti Python. Compatibile con Python2.7 +, Python3.4 + e pip9 +, pip10 +, pip18 +, pip19 +.

inserisci qui la descrizione dell'immagine


1

(soluzione alternativa, risposta non vera)

Ho avuto lo stesso problema, con lxml non installato e io che volevo sapere chi aveva bisogno di lxml. Non è necessario lxml . Ho finito per aggirare il problema di.

  1. notando dove venivano inseriti i pacchetti del mio sito.

  2. vai lì e grep ricorsivo per l'importazione (l'ultima inversione di grep serve a rimuovere i file di lxml dalla considerazione).

Sì, non una risposta su come usare pip per farlo, ma non ho ottenuto alcun successo dai suggerimenti qui, per qualsiasi motivo.

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

1

Ho scritto una breve sceneggiatura per risolvere questo problema. Il seguente script mostrerà i pacchetti padre (dipendente) per ciascun pacchetto. In questo modo puoi essere sicuro che sia sicuro aggiornare o installare qualsiasi pacchetto particolare. Può essere usato come segue: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)))

Questo non funziona più perché il get_installed_distributions()metodo non è più disponibile. github.com/pypa/pip/issues/5243
Phil Gyford
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.