Identificar la relación de dependencia para los paquetes python instalados con pip

151

Cuando hago una congelación de pip, veo una gran cantidad de paquetes de Python que no instalé explícitamente, p. Ej.

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

¿Hay alguna manera de determinar por qué pip instaló estos paquetes dependientes particulares? En otras palabras, ¿cómo determino el paquete principal que tenía estos paquetes como dependencias?

Por ejemplo, podría querer usar Twisted y no quiero depender de un paquete hasta que sepa más sobre no desinstalarlo o actualizarlo accidentalmente.

Mark Chackerian
fuente

Respuestas:

180

Puede probar pipdeptree que muestra las dependencias como una estructura de árbol, por ejemplo:

$ 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

Para ejecutarlo:

pip install pipdeptree


EDITAR: como señaló @Esteban en los comentarios, también puede enumerar el árbol al revés -ro para un solo paquete -p <package_name>para encontrar qué Werkzeug instalado puede ejecutar:

$ pipdeptree -r -p Werkzeug
Werkzeug==0.11.15
  - Flask==0.12 [requires: Werkzeug>=0.7]
djsutho
fuente
66
Creo que para responder completamente a la pregunta de @mark que necesitaría ejecutar: pipdeptree -r "Muestra el árbol de dependencias de manera inversa, es decir, las subdependencias se enumeran con la lista de paquetes que las necesitan debajo de ellas".
Esteban
¿Cómo puede ver el árbol inverso para todos los paquetes de PyPi, no solo los paquetes instalados localmente?
Tijme
2
pipdeptreees genial. Por desgracia, no parece tener en cuenta las dependencias de los paquetes instalados por Conda: por ejemplo, en un Conda env donde matplotliby numpyse han instalado con PIP, pero scipyse instaló usando Conda, scipyaparece en la pipdeptree como no tener depencies y sin dependientes (también pip show scipyaparece Sin requisitos).
djvg
@ Dennis No lo he probado, pero esto podría funcionar para conda github.com/rvalieris/conda-tree
djsutho
1
Para usar esto en un entorno virtual, debe hacer lo python -m pipdeptreecontrario (incluso cuando el ejecutable esté instalado en virtualenv) solo enumera las dependencias del sistema.
Zim
81

El pip showcomando mostrará qué paquetes son necesarios para el paquete especificado (tenga en cuenta que el paquete especificado ya debe estar instalado):

$ pip show specloud

Package: specloud
Version: 0.4.4
Requires:
nose
figleaf
pinocchio

pip show se introdujo en la versión pip 1.4rc5

BernardoBarreto
fuente
1
pip showse introdujo en la versión 1.4rc5, y está presente en la versión 1.4.1 (actual a partir de la escritura)
drevicko
10
Esto no responde a mi pregunta exactamente, porque muestra los hijos (dependencias) para un paquete específico, en lugar de los padres. Pero es bastante fácil juntar algo para verificar las dependencias de cada paquete, usando este comando. Entonces, por ejemplo, podría determinar qué paquete instalado requería PyYAML.
Mark Chackerian
44
Según mi comentario anterior, este comando de shell descarga todas las dependencias para cada uno de mis paquetes instalados: $ pip freeze | grep -v "\ -e" | sed s /\=\=.*// | awk 'system ("pip show" $ 1)'
Mark Chackerian
Una versión actualizada del script de mi comentario anterior es pip freeze | grep -v "\-e" | sed s/\=\=.*// | awk 'system("pip show " $1)' | grep -E '^(Name:|Requires:)' | sed s/Name:/\\\nName:/ , pero parece que pipdeptree ahora es una mejor solución.
Mark Chackerian
14

Como dije recientemente en un hilo hn , recomendaré lo siguiente:

Tenga un requirements.txtarchivo comentado con sus principales dependencias:

## this is needed for whatever reason
package1

Instalar sus dependencias: pip install -r requirements.txt. Ahora obtienes la lista completa de tus dependencias 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

Esto le permite mantener su estructura de archivos con comentarios, separando muy bien sus dependencias de las dependencias de sus dependencias. De esta manera, tendrás un momento mucho más agradable el día que necesites eliminar uno de ellos :)

Tenga en cuenta lo siguiente:

  • Puede tener una limpieza requirements.rawcon control de versiones para reconstruir su completo requirements.txt.
  • Tenga cuidado con las URL de git reemplazadas por nombres de huevo en el proceso.
  • Las dependencias de sus dependencias todavía están ordenadas alfabéticamente, por lo que no sabe directamente cuál fue requerido por qué paquete, pero en este punto realmente no lo necesita.
  • Úselo pip install --no-install <package_name>para enumerar requisitos específicos.
  • Use virtualenv si no lo hace.
Maxime R.
fuente
1
Simplemente no entiendo por qué esto pip freeze -r requirements.txtno se usa ampliamente. Muy útil para mantener las dependencias y subdependencias.
Penkey Suresh
1
nota menor: pip installya no es compatible --no-install.
Ryan
7

También puede usar un comando de una línea que canaliza los paquetes en requisitos para mostrar pip.

cut -d'=' -f1 requirements.txt | xargs pip show
biophetik
fuente
1
Generalmente no puede, ya que el formato de require.txt es más complejo que <package_name>==<package_version>.
Piotr Dobrogost
3

En primer lugar, pip freezemuestra todos los paquetes actualmente instalados en Python, no necesariamente usando PIP.

En segundo lugar, los paquetes de Python contienen la información sobre los paquetes dependientes, así como las versiones requeridas . Puede ver las dependencias de un paquete en particular utilizando los métodos descritos aquí . Cuando actualiza un paquete, el script de instalación como PIP se encargará de la actualización de las dependencias por usted.

Para resolver la actualización de paquetes, recomiendo usar archivos de requisitos PIP . Puede definir qué paquetes y versiones necesita e instalarlos de una vez usando pip install.

Mariusz Jamro
fuente
3

Use pipupgrade !

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

pipupgrade muestra un gráfico de dependencia y resalta cada paquete para una posible actualización (basada en versiones semánticas). También muestra dependencias secundarias conflictivas de una manera bonita. pipupgradeTambién se asegura de actualizar los paquetes presentes en múltiples entornos Python. Compatible con Python2.7 +, Python3.4 + y pip9 +, pip10 +, pip18 +, pip19 +.

ingrese la descripción de la imagen aquí

Achilles Gasper Rasquinha
fuente
1

(solución alternativa, respuesta no verdadera)

Tuve el mismo problema, con lxml no instalándose y yo queriendo saber quién necesitaba lxml. No quién lxml necesitaba . Terminé evitando el problema por.

  1. observando dónde se colocaban los paquetes de mi sitio.

  2. vaya allí y grep recursivo para la importación (el último grep's --invert-match sirve para eliminar los propios archivos lxml de la consideración).

Sí, no hay una respuesta sobre cómo usar pip para hacerlo, pero no obtuve ningún éxito de las sugerencias aquí, por alguna razón.

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

Escribí un guión rápido para resolver este problema. La siguiente secuencia de comandos mostrará los paquetes principales (dependientes) de cualquier paquete dado. De esta manera, puede estar seguro de que es seguro actualizar o instalar cualquier paquete en particular. Se puede usar de la siguiente manera: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)))
Seis
fuente
Esto ya no funciona porque el get_installed_distributions()método ya no está disponible. github.com/pypa/pip/issues/5243
Phil Gyford