การระบุความสัมพันธ์การพึ่งพาสำหรับแพ็คเกจงูใหญ่ที่ติดตั้งด้วย pip


151

เมื่อฉันแช่แข็ง pip ฉันเห็นแพ็คเกจ Python จำนวนมากที่ฉันไม่ได้ติดตั้งอย่างชัดเจนเช่น

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

มีวิธีที่ฉันจะระบุหรือไม่ว่าทำไม pip จึงติดตั้งแพ็คเกจที่ขึ้นกับสิ่งเหล่านี้? กล่าวอีกนัยหนึ่งฉันจะกำหนดแพ็คเกจหลักที่มีแพ็คเกจเหล่านี้เป็นการอ้างอิงได้อย่างไร

ตัวอย่างเช่นฉันอาจต้องการใช้ Twisted และฉันไม่ต้องการพึ่งพาแพ็คเกจจนกว่าฉันจะรู้เพิ่มเติมเกี่ยวกับการไม่ถอนการติดตั้งหรืออัพเกรดโดยไม่ตั้งใจ

คำตอบ:


180

คุณสามารถลองpipdeptreeซึ่งแสดงการพึ่งพาเป็นโครงสร้างแบบต้นไม้เช่น:

$ 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

เพื่อให้มันทำงาน:

pip install pipdeptree


แก้ไข:ตามที่บันทึกไว้โดย @Esteban ในความคิดเห็นคุณสามารถแสดงรายการต้นไม้ในทางกลับกันด้วย-rหรือสำหรับแพ็คเกจเดียวด้วย-p <package_name>เพื่อค้นหาสิ่งที่ติดตั้ง Werkzeug ที่คุณสามารถเรียกใช้:

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

6
ฉันเชื่อว่าจะตอบคำถามของ @mark อย่างครบถ้วนคุณจะต้องเรียกใช้: pipdeptree -r "แสดงแผนผังการพึ่งพาในแบบย้อนกลับนั่นคือการพึ่งพาย่อยจะแสดงอยู่ในรายการแพคเกจที่ต้องการภายใต้พวกเขา"
เอสเตบัน

คุณจะดูแผนผังย้อนกลับสำหรับแพ็คเกจ PyPi ทั้งหมดได้อย่างไรไม่ใช่เฉพาะแพ็คเกจที่ติดตั้งภายในเครื่อง
Tijme

2
pipdeptreeดีมาก. น่าเสียดายที่มันไม่ได้คำนึงถึงการพึ่งพาบัญชีสำหรับแพ็คเกจที่ติดตั้งโดย conda: เช่นใน conda env ที่matplotlibและnumpyติดตั้งโดยใช้ pip แต่scipyถูกติดตั้งโดยใช้ conda scipyแสดงใน pipdeptree ว่าไม่มีการพึ่งพาและไม่มีผู้ติดตาม (ยังpip show scipyไม่แสดง ความต้องการ)
djvg

@Dennis ฉันไม่ได้ลอง แต่อาจใช้กับ conda github.com/rvalieris/conda-tree
djsutho

1
ในการใช้สิ่งนี้ในสภาพแวดล้อมเสมือนคุณต้องทำpython -m pipdeptreeอย่างอื่น (แม้เมื่อติดตั้งโปรแกรมปฏิบัติการลงใน virtualenv) ระบบจะแสดงรายการการขึ้นต่อกันของระบบเท่านั้น
Zim

81

pip showคำสั่งจะแสดงสิ่งที่แพคเกจที่จำเป็นสำหรับแพคเกจที่กำหนด (หมายเหตุที่แพคเกจที่กำหนดจะต้องติดตั้งแล้ว):

$ pip show specloud

Package: specloud
Version: 0.4.4
Requires:
nose
figleaf
pinocchio

pip show เป็นที่รู้จักใน pip รุ่น 1.4rc5


1
pip showถูกนำมาใช้ในรุ่น 1.4rc5 และมีอยู่ใน (ปัจจุบัน ณ การเขียน) 1.4.1
drevicko

10
สิ่งนี้ไม่ได้ตอบคำถามของฉันอย่างแน่นอนเพราะมันแสดงให้เห็นถึงเด็ก ๆ (การพึ่งพา) สำหรับแพ็คเกจเฉพาะแทนที่จะเป็นผู้ปกครอง แต่มันง่ายพอที่จะรวบรวมบางสิ่งเข้าด้วยกันเพื่อตรวจสอบการขึ้นต่อกันของแต่ละแพ็คเกจโดยใช้คำสั่งนี้ ตัวอย่างเช่นฉันสามารถกำหนดแพ็คเกจที่ติดตั้งซึ่งจำเป็นต้องใช้ PyYAML
Mark Chackerian

4
ตามความคิดเห็นก่อนหน้าของฉันคำสั่งเชลล์นี้จะทิ้งการอ้างอิงทั้งหมดสำหรับแต่ละแพ็คเกจที่ติดตั้งของฉัน: $ pip freeze | grep -v "\ -e" | sed s /\=\=.*// | awk 'ระบบ ("pip show" $ 1)'
Mark Chackerian

สคริปต์เวอร์ชันอัปเดตจากความคิดเห็นก่อนหน้าของฉันคือpip freeze | grep -v "\-e" | sed s/\=\=.*// | awk 'system("pip show " $1)' | grep -E '^(Name:|Requires:)' | sed s/Name:/\\\nName:/ - แต่ดูเหมือนว่า pipdeptree ตอนนี้เป็นทางออกที่ดีกว่า
Mark Chackerian

14

อย่างที่ฉันเพิ่งพูดในหัวข้อ hnฉันจะแนะนำต่อไปนี้:

มีความคิดเห็นrequirements.txtไฟล์ที่มีการอ้างอิงหลักของคุณ:

## this is needed for whatever reason
package1

pip install -r requirements.txtติดตั้งการอ้างอิงของคุณ: ตอนนี้คุณจะได้รับรายชื่อทั้งหมดของการอ้างอิงของคุณด้วย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

สิ่งนี้ช่วยให้คุณสามารถเก็บโครงสร้างไฟล์ของคุณด้วยความคิดเห็นแยกการพึ่งพาของคุณออกจากการขึ้นต่อกันของการพึ่งพาของคุณ วิธีนี้คุณจะมีเวลามากขึ้นในวันที่คุณต้องลบหนึ่งในนั้น :)

หมายเหตุดังต่อไปนี้:

  • คุณสามารถมีการทำความสะอาดที่มีการควบคุมรุ่นที่จะสร้างเต็มของคุณrequirements.rawrequirements.txt
  • ระวัง URL git ที่ถูกแทนที่ด้วยชื่อไข่ในกระบวนการ
  • การอ้างอิงของการพึ่งพาของคุณยังคงเรียงลำดับตามตัวอักษรดังนั้นคุณจึงไม่ทราบโดยตรงว่าต้องการใช้แพคเกจใด แต่ ณ จุดนี้คุณไม่จำเป็นต้องใช้จริงๆ
  • ใช้pip install --no-install <package_name>เพื่อแสดงรายการข้อกำหนดเฉพาะ
  • ใช้virtualenvถ้าคุณทำไม่ได้

1
ฉันแค่ไม่เข้าใจว่าทำไมpip freeze -r requirements.txtไม่ใช้กันอย่างแพร่หลาย มีประโยชน์มากสำหรับการบำรุงรักษาการอ้างอิงและการอ้างอิงย่อย
Penkey Suresh

1
โน้ตเล็ก ๆ น้อย ๆ : ไม่สนับสนุนแล้วpip install --no-install
ryan

7

คุณอาจใช้คำสั่งหนึ่งบรรทัดซึ่งไพพ์แพ็กเกจที่ต้องการเพื่อแสดง pip

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

1
โดยทั่วไปคุณไม่สามารถเป็นรูปแบบของ requirements.txt <package_name>==<package_version>มีความซับซ้อนมากกว่า
Piotr Dobrogost

3

ก่อนอื่นpip freezeจะแสดงแพ็คเกจที่ติดตั้งในปัจจุบันทั้งหมด Python ไม่จำเป็นต้องใช้ PIP

ประการที่สองแพคเกจหลามทำมีข้อมูลเกี่ยวกับแพคเกจขึ้นเช่นเดียวกับรุ่นที่ต้องการ คุณสามารถดูการอ้างอิงของ pkg โดยเฉพาะอย่างยิ่งการใช้วิธีการที่อธิบายไว้ที่นี่ เมื่อคุณอัปเกรดแพ็คเกจสคริปต์ติดตั้งเช่น PIP จะจัดการการอัปเดตการอ้างอิงสำหรับคุณ

เพื่อแก้ปัญหาการอัปเดตของแพคเกจผมขอแนะนำให้ใช้ไฟล์ข้อกำหนด PIP คุณสามารถกำหนดแพ็คเกจและเวอร์ชันที่คุณต้องการและติดตั้งพร้อมกันโดยใช้ pip install


3

ใช้pipupgrade !

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

pipupgradeแสดงกราฟการพึ่งพาและเน้นแต่ละแพ็คเกจสำหรับการอัพเดตที่เป็นไปได้ นอกจากนี้ยังแสดงการพึ่งพาของเด็กที่ขัดแย้งกันในวิธีที่ค่อนข้างดี pipupgradeยังช่วยให้แน่ใจว่าจะอัพเกรดแพ็คเกจที่มีอยู่ในสภาพแวดล้อม Python หลาย ๆ เข้ากันได้กับ Python2.7 +, Python3.4 + และ pip9 +, pip10 +, pip18 +, pip19 +

ป้อนคำอธิบายรูปภาพที่นี่


1

(วิธีแก้ปัญหาไม่ใช่คำตอบที่แท้จริง)

มีปัญหาเดียวกันกับ lxml ไม่ได้ติดตั้งและฉันต้องการที่จะรู้ว่าใครต้องการ lxml ไม่จำเป็นที่ lxml จบลงด้วยการข้ามปัญหาโดย

  1. สังเกตที่วางแพคเกจเว็บไซต์ของฉัน

  2. ไปที่นั่นและเรียกใช้ grep ซ้ำสำหรับการนำเข้า (grep's --invert-match สุดท้ายทำหน้าที่ลบไฟล์ของ lxml เองจากการพิจารณา)

ใช่ไม่ใช่คำตอบเกี่ยวกับวิธีการใช้ pip เพื่อทำ แต่ฉันไม่ประสบความสำเร็จจากคำแนะนำที่นี่ไม่ว่าด้วยเหตุผลใด

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

1

ฉันเขียนสคริปต์สั้น ๆ เพื่อแก้ปัญหานี้ สคริปต์ต่อไปนี้จะแสดงแพคเกจหลัก (ขึ้นอยู่กับ) สำหรับแพ็คเกจที่กำหนด วิธีนี้คุณสามารถมั่นใจได้ว่าจะปลอดภัยในการอัพเกรดหรือติดตั้งแพ็คเกจใด ๆ มันสามารถใช้ดังนี้: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)))

วิธีนี้ใช้ไม่ได้อีกต่อไปเนื่องจากget_installed_distributions()วิธีนี้ไม่สามารถใช้งานได้อีกต่อไป github.com/pypa/pip/issues/5243
Phil Gyford
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.