Xác định mối quan hệ phụ thuộc cho các gói python được cài đặt với pip


151

Khi tôi đóng băng pip, tôi thấy một số lượng lớn các gói Python mà tôi không cài đặt rõ ràng, ví dụ:

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

Có cách nào để tôi xác định lý do tại sao pip cài đặt các gói phụ thuộc cụ thể này không? Nói cách khác, làm cách nào để xác định gói cha mẹ có các gói này là phụ thuộc?

Ví dụ: tôi có thể muốn sử dụng Twisted và tôi không muốn phụ thuộc vào gói cho đến khi tôi biết thêm về việc không vô tình gỡ cài đặt hoặc nâng cấp gói.

Câu trả lời:


180

Bạn có thể thử pipdeptree hiển thị các phụ thuộc dưới dạng cấu trúc cây, ví dụ:

$ 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

Để có được nó chạy:

pip install pipdeptree


EDIT: như được lưu ý bởi @Esteban trong các bình luận, bạn cũng có thể liệt kê cây ngược lại với -rhoặc cho một gói duy nhất -p <package_name>để tìm Werkzeug đã cài đặt mà bạn có thể chạy:

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

6
Tôi tin rằng sẽ trả lời đầy đủ câu hỏi của @mark mà bạn sẽ cần chạy: pipdeptree -r "Hiển thị cây phụ thuộc theo kiểu ngược lại. Phụ thuộc phụ được liệt kê với danh sách các gói cần chúng theo chúng."
Esteban

Làm thế nào bạn có thể xem cây đảo ngược cho tất cả các gói PyPi, không chỉ các gói được cài đặt cục bộ?
Tijme

2
pipdeptreetuyệt. Thật không may, nó dường như không tính đến các phụ thuộc cho các gói được cài đặt bởi conda: ví dụ: trong một conda env nơi matplotlibnumpyđược cài đặt bằng pip, nhưng scipyđược cài đặt bằng conda, scipyhiển thị trong pipdeptree là không có phụ thuộc và không có phụ thuộc (cũng pip show scipykhông hiển thị yêu cầu).
djvg

@Dennis Tôi chưa thử nhưng điều này có thể hoạt động cho conda github.com/rvalieris/conda-tree
djsutho

1
Để sử dụng điều này trong một môi trường ảo, bạn cần phải làm python -m pipdeptreekhác (ngay cả khi tệp thực thi được cài đặt vào virtualenv), nó chỉ liệt kê các phụ thuộc hệ thống.
Zim

81

Các pip showlệnh sẽ thể hiện những gì gói được yêu cầu cho gói nhất định (lưu ý rằng mức khoán quy định đã phải được cài đặt):

$ pip show specloud

Package: specloud
Version: 0.4.4
Requires:
nose
figleaf
pinocchio

pip show đã được giới thiệu trong phiên bản pip 1.4rc5


1
pip showđã được giới thiệu trong phiên bản 1.4rc5 và có mặt trong (hiện tại khi viết) 1.4.1
drevicko

10
Điều này không trả lời chính xác câu hỏi của tôi, bởi vì nó cho trẻ em (phụ thuộc) cho một gói cụ thể, thay vì cha mẹ. Nhưng thật dễ dàng để kết hợp một thứ gì đó lại với nhau để kiểm tra sự phụ thuộc của từng gói, sử dụng lệnh này. Vì vậy, ví dụ, tôi có thể xác định gói cài đặt nào cần PyYAML.
Mark Chackerian

4
Theo nhận xét trước đây của tôi, lệnh shell này loại bỏ tất cả các phụ thuộc cho từng gói đã cài đặt của tôi: $ pip đóng băng | grep -v "\ -e" | sed s /\=\=.*// | awk 'system ("pip show" $ 1)'
Mark Chackerian

Một phiên bản cập nhật của tập lệnh từ nhận xét trước đây của tôi là pip freeze | grep -v "\-e" | sed s/\=\=.*// | awk 'system("pip show " $1)' | grep -E '^(Name:|Requires:)' | sed s/Name:/\\\nName:/ - nhưng có vẻ như pipdeptree bây giờ là một giải pháp tốt hơn.
Mark Chackerian

14

Như tôi đã nói gần đây trên một chủ đề hn , tôi sẽ đề nghị như sau:

Có một requirements.txttệp nhận xét với các phụ thuộc chính của bạn:

## this is needed for whatever reason
package1

Cài đặt phụ thuộc của bạn : pip install -r requirements.txt. Bây giờ bạn có được danh sách đầy đủ các phụ thuộc của bạn với 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

Điều này cho phép bạn giữ cấu trúc tệp của mình với các nhận xét, tách biệt các phụ thuộc của bạn khỏi các phụ thuộc của các phụ thuộc. Bằng cách này, bạn sẽ có thời gian đẹp hơn nhiều vào ngày bạn cần xóa một trong số chúng :)

Lưu ý những điều dưới đây:

  • Bạn có thể dọn dẹp requirements.rawvới kiểm soát phiên bản để xây dựng lại toàn bộ requirements.txt.
  • Cảnh giác với các url git được thay thế bằng tên trứng trong quá trình.
  • Sự phụ thuộc của các phụ thuộc của bạn vẫn được sắp xếp theo thứ tự bảng chữ cái để bạn không trực tiếp biết gói nào được yêu cầu bởi gói nào nhưng tại thời điểm này bạn không thực sự cần nó.
  • Sử dụng pip install --no-install <package_name>để liệt kê các yêu cầu cụ thể.
  • Sử dụng virtualenv nếu bạn không.

1
Tôi chỉ không hiểu tại sao điều này pip freeze -r requirements.txtkhông được sử dụng rộng rãi. Rất hữu ích để duy trì các phụ thuộc và phụ thuộc phụ.
Penkey Suresh

1
lưu ý nhỏ: pip installkhông còn hỗ trợ --no-install.
ryan

7

Bạn cũng có thể sử dụng lệnh một dòng để dẫn các gói trong các yêu cầu tới pip hiển thị.

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

1
Nói chung, bạn không thể vì định dạng của tests.txt phức tạp hơn <package_name>==<package_version>.
Piotr Dobrogost

3

Trước hết pip freezehiển thị tất cả các gói Python hiện đang cài đặt, không nhất thiết phải sử dụng PIP.

Các gói Python thứ hai có chứa thông tin về các gói phụ thuộc cũng như các phiên bản bắt buộc . Bạn có thể thấy sự phụ thuộc của pkg cụ thể bằng các phương pháp được mô tả ở đây . Khi bạn nâng cấp gói, tập lệnh cài đặt như PIP sẽ xử lý việc nâng cấp các phụ thuộc cho bạn.

Để giải quyết việc cập nhật các gói tôi khuyên bạn nên sử dụng các tệp yêu cầu PIP . Bạn có thể xác định gói và phiên bản nào bạn cần và cài đặt chúng cùng một lúc bằng cách sử dụng cài đặt pip.


3

Sử dụng đường ống !

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

pipupTHER hiển thị biểu đồ phụ thuộc và tô sáng từng gói để cập nhật có thể (dựa trên phiên bản ngữ nghĩa). Nó cũng hiển thị các phụ thuộc trẻ em xung đột theo một cách khá. pipupgradecũng đảm bảo nâng cấp các gói có trong nhiều môi trường Python. Tương thích với Python2.7 +, Python3.4 + và pip9 +, pip10 +, pip18 +, pip19 +.

nhập mô tả hình ảnh ở đây


1

(cách giải quyết, không trả lời đúng)

Có cùng một vấn đề, với lxml không cài đặt và tôi muốn biết ai cần lxml. Không phải ai cần lxml . Đã kết thúc bỏ qua vấn đề bằng cách.

  1. lưu ý nơi các gói trang web của tôi đã được đặt.

  2. đến đó và grep đệ quy cho quá trình nhập (lần cuối cùng của grep's --invert-match phục vụ để loại bỏ các tệp riêng của lxml khỏi xem xét).

Vâng, không phải là một câu trả lời về cách sử dụng pip để làm điều đó, nhưng tôi đã không nhận được bất kỳ thành công nào từ các đề xuất ở đây, vì bất kỳ lý do gì.

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

1

Tôi đã viết một kịch bản nhanh chóng để giải quyết vấn đề này. Kịch bản sau đây sẽ hiển thị (các) gói cha (phụ thuộc) cho bất kỳ gói nào. Bằng cách này, bạn có thể chắc chắn rằng an toàn để nâng cấp hoặc cài đặt bất kỳ gói cụ thể nào. Nó có thể được sử dụng như sau: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)))

Điều này không còn hoạt động vì get_installed_distributions()phương pháp không còn nữa. github.com/pypa/pip/issues/5243
Phil Gyford
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.