Mengidentifikasi hubungan ketergantungan untuk paket python yang diinstal dengan pip


151

Ketika saya melakukan pembekuan pip saya melihat sejumlah besar paket Python yang saya tidak instal secara eksplisit, misalnya

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

Apakah ada cara bagi saya untuk menentukan mengapa pip menginstal paket dependen khusus ini? Dengan kata lain, bagaimana cara menentukan paket induk yang memiliki paket-paket ini sebagai dependensi?

Misalnya, saya mungkin ingin menggunakan Twisted dan saya tidak ingin bergantung pada suatu paket sampai saya tahu lebih banyak tentang tidak sengaja menghapus atau memutakhirkannya.

Jawaban:


180

Anda dapat mencoba pipdeptree yang menampilkan dependensi sebagai struktur pohon, misalnya:

$ 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

Untuk menjalankannya:

pip install pipdeptree


EDIT: seperti yang dicatat oleh @Esteban di komentar Anda juga dapat membuat daftar pohon secara terbalik dengan -ratau untuk satu paket dengan -p <package_name>begitu untuk menemukan Werkzeug yang diinstal, Anda dapat menjalankan:

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

6
Saya percaya untuk sepenuhnya menjawab pertanyaan @mark yang perlu Anda jalankan: pipdeptree -r "Menunjukkan pohon dependensi dengan cara terbalik, yaitu. Sub-dependensi terdaftar dengan daftar paket yang membutuhkannya di bawahnya."
Esteban

Bagaimana Anda bisa melihat pohon terbalik untuk semua paket PyPi, tidak hanya paket yang diinstal secara lokal?
Tijme

2
pipdeptreebagus. Sayangnya itu tampaknya tidak memperhitungkan dependensi akun untuk paket yang diinstal oleh conda: mis. Di conda env di mana matplotlibdan numpydiinstal menggunakan pip, tetapi scipydiinstal menggunakan conda, scipymuncul di pipdeptree sebagai tidak memiliki depency dan tidak ada tanggungan (juga pip show scipymenunjukkan tidak ada Persyaratan).
djvg

@Dennis Saya belum mencobanya tetapi ini mungkin bekerja untuk conda github.com/rvalieris/conda-tree
djsutho

1
Untuk menggunakan ini dalam lingkungan virtual, Anda perlu melakukan python -m pipdeptreesebaliknya (bahkan ketika executable diinstal ke virtualenv) hanya mencantumkan dependensi sistem.
Zim

81

The pip showperintah akan menunjukkan apa yang diperlukan paket untuk paket tertentu (catatan bahwa paket tertentu harus sudah diinstal):

$ pip show specloud

Package: specloud
Version: 0.4.4
Requires:
nose
figleaf
pinocchio

pip show diperkenalkan dalam versi pip 1.4rc5


1
pip showdiperkenalkan di versi 1.4rc5, dan hadir di (saat ini saat penulisan) 1.4.1
drevicko

10
Ini tidak menjawab pertanyaan saya persis, karena itu menunjukkan anak-anak (dependensi) untuk paket tertentu, bukan orang tua. Tetapi cukup mudah untuk melempar sesuatu bersama untuk memeriksa dependensi setiap paket, menggunakan perintah ini. Jadi, misalnya, saya bisa menentukan paket yang diinstal yang membutuhkan PyYAML.
Mark Chackerian

4
Sesuai komentar saya sebelumnya, perintah shell ini membuang semua dependensi untuk setiap paket saya yang terinstal: $ pip freeze | grep -v "\ -e" | sed s /\=\=.*// | awk 'system ("pip show" $ 1)'
Mark Chackerian

Versi skrip yang diperbarui dari komentar saya sebelumnya adalah pip freeze | grep -v "\-e" | sed s/\=\=.*// | awk 'system("pip show " $1)' | grep -E '^(Name:|Requires:)' | sed s/Name:/\\\nName:/ - tetapi tampaknya pipdeptree sekarang merupakan solusi yang lebih baik.
Mark Chackerian

14

Seperti yang baru-baru ini saya katakan di utas hn , saya akan merekomendasikan yang berikut:

Punya requirements.txtfile komentar dengan dependensi utama Anda:

## this is needed for whatever reason
package1

Install dependensi Anda: pip install -r requirements.txt. Sekarang Anda mendapatkan daftar lengkap dependensi Anda dengan 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

Ini memungkinkan Anda untuk menjaga struktur file Anda dengan komentar, memisahkan dependensi Anda dari dependensi dependensi Anda. Dengan cara ini Anda akan memiliki waktu yang jauh lebih baik di hari Anda perlu menghapus salah satunya :)

Perhatikan yang berikut ini:

  • Anda dapat memiliki requirements.rawkontrol versi bersih dengan untuk membangun kembali penuh Anda requirements.txt.
  • Waspadalah terhadap url git yang digantikan oleh nama telur dalam proses.
  • Ketergantungan dependensi Anda masih diurutkan berdasarkan abjad sehingga Anda tidak secara langsung mengetahui paket mana yang diperlukan tetapi pada saat ini Anda tidak benar-benar membutuhkannya.
  • Gunakan pip install --no-install <package_name>untuk mendaftar persyaratan spesifik.
  • Gunakan virtualenv jika tidak.

1
Saya hanya tidak mengerti mengapa ini pip freeze -r requirements.txttidak banyak digunakan. Sangat berguna untuk menjaga dependensi dan sub dependensi.
Penkey Suresh

1
catatan minor: pip installtidak lagi mendukung --no-install.
ryan

7

Anda juga dapat menggunakan perintah satu baris yang menyalurkan paket-paket dalam persyaratan untuk menampilkan pip.

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

1
Secara umum Anda tidak bisa karena format requirement.txt lebih kompleks daripada <package_name>==<package_version>.
Piotr Dobrogost

3

Pertama-tama pip freezemenampilkan semua paket yang diinstal saat ini Python, belum tentu menggunakan PIP.

Paket Python kedua memang berisi informasi tentang paket dependen serta versi yang diperlukan . Anda dapat melihat dependensi pkg tertentu menggunakan metode yang dijelaskan di sini . Saat Anda memutakhirkan paket, skrip pemasang seperti PIP akan menangani pemutakhiran dependensi untuk Anda.

Untuk mengatasi pembaruan paket saya sarankan menggunakan file persyaratan PIP . Anda dapat menentukan paket dan versi apa yang Anda butuhkan, dan menginstalnya sekaligus menggunakan pip install.


3

Gunakan pipupgrade !

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

pipupgrade menampilkan grafik ketergantungan dan menyoroti setiap paket untuk kemungkinan pembaruan (berdasarkan versi semantik). Ini juga menampilkan ketergantungan anak yang saling bertentangan dengan cara yang cantik. pipupgradejuga memastikan untuk meningkatkan paket yang ada dalam beberapa lingkungan Python. Kompatibel dengan Python2.7 +, Python3.4 + dan pip9 +, pip10 +, pip18 +, pip19 +.

masukkan deskripsi gambar di sini


1

(solusi, bukan jawaban yang benar)

Punya masalah yang sama, dengan lxml tidak menginstal dan saya ingin tahu siapa yang butuh lxml. Bukan yang membutuhkan lxml . Berakhir melewati masalah dengan.

  1. mencatat di mana paket situs saya ditempatkan.

  2. pergi ke sana dan grep rekursif untuk impor (grep terakhir --invert-match berfungsi untuk menghapus file lxml sendiri dari pertimbangan).

Ya, bukan jawaban tentang bagaimana menggunakan pip untuk melakukannya, tetapi saya tidak berhasil dari saran di sini, untuk alasan apa pun.

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

1

Saya menulis skrip cepat untuk mengatasi masalah ini. Skrip berikut akan menampilkan paket induk (tergantung) untuk setiap paket yang diberikan. Dengan cara ini Anda dapat yakin bahwa aman untuk meningkatkan atau menginstal paket tertentu. Dapat digunakan sebagai berikut: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)))

Ini tidak lagi berfungsi karena get_installed_distributions()metode ini tidak lagi tersedia. github.com/pypa/pip/issues/5243
Phil Gyford
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.