Công cụ đóng gói trong Python là gì?

Tại buổi gặp mặt Python Frederick tuần trước, tôi đã nói chuyện về bao bì Python. Mục đích của tôi là đề cập đến cách thức hoạt động của bao bì và cách xây dựng một gói cơ bản. Trong suốt buổi nói chuyện, chúng tôi đã sử dụng một số công cụ mà tôi nghĩ là rất quan trọng để phát hành gói Python cho PyPI. Tôi sẽ mô tả những công cụ này và lý do tại sao tôi nghĩ chúng quan trọng

chất độc

tox là một công cụ tuyệt vời để kiểm tra bao bì. Với lệnh

$ twine upload dist/*
61, nhà phát triển có thể xây dựng gói, cài đặt gói đó vào môi trường ảo cho phiên bản Python cụ thể và chạy gói thông qua bộ thử nghiệm của nó

Phiên bản ngắn của running tox trông giống như

$ tox -e py36

Lệnh này sẽ chạy bộ thử nghiệm của gói đối với Python 3. 6. Tôi thích nó khi các lệnh thanh lịch. Để làm được điều đó, nhà phát triển phải cho tox biết cách chạy bộ thử nghiệm. Cấu hình này được thực hiện trong tệp

$ twine upload dist/*
62. Một tập tin tối thiểu có thể trông giống như

[tox]
envlist = py36

[testenv]
commands = python -m unittest discover \
    -s {envsitepackagesdir}/whirlygig

Trong ví dụ này, bạn sẽ thay đổi

$ twine upload dist/*
63 thành tên dự án của bạn. Đây là thông tin đủ để thông báo cho tox về cách chạy bộ thử nghiệm của bạn

Tôi thấy rằng việc sử dụng tox giúp tôi tránh được các lỗi đóng gói khó phát hiện (bạn có biết chúng tồn tại không?) và nói chung là tuyệt vời để thử nghiệm trên nhiều phiên bản Python

quanh co

sợi xe là một công cụ quan trọng trong bộ công cụ của nhà đóng gói vì một lý do. nó cho phép bạn tải lên PyPI qua HTTPS. Ngược lại,

$ twine upload dist/*
64 sử dụng HTTP không an toàn cho nhiều phiên bản Python

Mặc dù có vẻ ngớ ngẩn nhưng bạn cần một gói riêng để tải lên an toàn qua HTTPS. Tôi cho rằng có những lý do chính đáng cho yêu cầu đó mà tôi không biết

$ twine upload dist/*
65 tạo một thư mục
$ twine upload dist/*
66 với các gói để tải lên. (Biên tập. Ghi chú. Xin chào từ 2021. Cộng đồng Python đã ngừng sử dụng trực tiếp
$ twine upload dist/*
67. Thay vào đó, để xây dựng các gói của bạn, hãy sử dụng một công cụ như bản dựng). Bạn có thể thực hiện tải lên của mình với

$ twine upload dist/*

Tóm lược

Hệ sinh thái Python có tài liệu tuyệt vời về đóng gói tại Hướng dẫn sử dụng bao bì Python. Bài đăng này nhằm mục đích giới thiệu nhẹ nhàng về một vài công cụ rất có giá trị khi bạn muốn làm việc với các gói

(Vâng, tôi biết một "gói" về mặt kỹ thuật được gọi là "phân phối" trong biệt ngữ Python thích hợp, nhưng tôi đã sử dụng thuật ngữ này vì nó được chấp nhận rộng rãi hơn trong nhiều ngôn ngữ lập trình. )

Thư viện này cung cấp các tiện ích triển khai các thông số kỹ thuật về khả năng tương tác rõ ràng có một hành vi đúng (ví dụ:. PEP 440) hoặc hưởng lợi rất nhiều từ việc có một triển khai được chia sẻ duy nhất (ví dụ:. PEP 425)

Dự án đóng gói bao gồm những điều sau đây. xử lý phiên bản, chỉ định, đánh dấu, yêu cầu, thẻ, tiện ích

Lịch sử dự án

Vui lòng xem lại THAY ĐỔI. tệp đầu tiên hoặc tài liệu Nhật ký thay đổi cho các thay đổi gần đây và lịch sử dự án

Pipenv là một công cụ đóng gói dành cho Python giúp giải quyết một số vấn đề phổ biến liên quan đến quy trình làm việc điển hình bằng cách sử dụng

package_a
package_b
8,
package_a
package_b
9 và
package_c>=1.0,<=2.0
package_a
package_b
0 cũ

Ngoài việc giải quyết một số vấn đề phổ biến, nó hợp nhất và đơn giản hóa quy trình phát triển thành một công cụ dòng lệnh duy nhất

Hướng dẫn này sẽ giới thiệu những vấn đề mà Pipenv giải quyết và cách quản lý các phần phụ thuộc Python của bạn với Pipenv. Ngoài ra, nó sẽ đề cập đến cách Pipenv phù hợp với các phương pháp phân phối gói trước đây

Tiền thưởng miễn phí. Nhấp vào đây để truy cập lớp học 5 ngày miễn phí chỉ cho bạn cách tránh các sự cố quản lý phụ thuộc phổ biến với các công cụ như Pip, PyPI, Virtualenv và các tệp yêu cầu

Các vấn đề mà Pipenv giải quyết

Để hiểu được lợi ích của Pipenv, điều quan trọng là phải xem qua các phương pháp hiện tại để đóng gói và quản lý phụ thuộc trong Python

Hãy bắt đầu với một tình huống điển hình về việc xử lý các gói của bên thứ ba. Sau đó, chúng tôi sẽ xây dựng cách triển khai một ứng dụng Python hoàn chỉnh

Loại bỏ các quảng cáo

Quản lý phụ thuộc với package_c>=1.0,<=2.0 package_a package_b 0

Hãy tưởng tượng bạn đang làm việc trên một dự án Python sử dụng gói của bên thứ ba như

package_c>=1.0,<=2.0
package_a
package_b
2. Bạn sẽ cần chỉ định yêu cầu đó để các nhà phát triển và hệ thống tự động khác có thể chạy ứng dụng của bạn

Vì vậy, bạn quyết định đưa phần phụ thuộc

package_c>=1.0,<=2.0
package_a
package_b
2 vào tệp
package_c>=1.0,<=2.0
package_a
package_b
0

[tox]
envlist = py36

[testenv]
commands = python -m unittest discover \
    -s {envsitepackagesdir}/whirlygig
0

Tuyệt vời, mọi thứ hoạt động tốt tại địa phương và sau khi hack ứng dụng của bạn một lúc, bạn quyết định chuyển nó sang sản xuất. Đây là nơi mọi thứ trở nên hơi đáng sợ…

Tệp

package_c>=1.0,<=2.0
package_a
package_b
0 ở trên không chỉ định phiên bản
package_c>=1.0,<=2.0
package_a
package_b
2 nào sẽ sử dụng. Trong trường hợp này, theo mặc định,
package_c>=1.0,<=2.0
package_a
package_b
7 sẽ cài đặt phiên bản mới nhất. Điều này không sao trừ khi có những thay đổi về giao diện hoặc hành vi trong phiên bản mới nhất làm hỏng ứng dụng của chúng tôi

Vì lợi ích của ví dụ này, giả sử rằng một phiên bản mới của

package_c>=1.0,<=2.0
package_a
package_b
2 đã được phát hành. Tuy nhiên, nó không tương thích ngược với phiên bản bạn đã sử dụng trong quá trình phát triển

Bây giờ, giả sử bạn triển khai ứng dụng của mình vào sản xuất và thực hiện một

package_c>=1.0,<=2.0
package_a
package_b
7. Pip nhận phiên bản mới nhất, không tương thích ngược của
package_c>=1.0,<=2.0
package_a
package_b
2 và cứ như vậy, ứng dụng của bạn bị hỏng… trong quá trình sản xuất

“Nhưng này, nó hoạt động trên máy của tôi. ” —Bản thân tôi đã từng đến đó, và đó không phải là một cảm giác tuyệt vời

Tại thời điểm này, bạn biết rằng phiên bản

package_c>=1.0,<=2.0
package_a
package_b
2 mà bạn đã sử dụng trong quá trình phát triển hoạt động tốt. Vì vậy, để khắc phục mọi thứ, bạn hãy cố gắng cụ thể hơn một chút trong
package_c>=1.0,<=2.0
package_a
package_b
0 của mình. Bạn thêm một trình xác định phiên bản vào phần phụ thuộc
package_c>=1.0,<=2.0
package_a
package_b
2. Điều này còn được gọi là ghim một phụ thuộc

$ twine upload dist/*
0

Việc ghim phần phụ thuộc của

package_c>=1.0,<=2.0
package_a
package_b
2 vào một phiên bản cụ thể đảm bảo rằng một
package_c>=1.0,<=2.0
package_a
package_b
7 sẽ thiết lập đúng phiên bản của
package_c>=1.0,<=2.0
package_a
package_b
2 mà bạn đã sử dụng trong quá trình phát triển. Nhưng nó thực sự?

Hãy nhớ rằng bản thân

package_c>=1.0,<=2.0
package_a
package_b
2 cũng có các phần phụ thuộc (mà
package_a
package_b
8 tự động cài đặt). Tuy nhiên, bản thân
package_c>=1.0,<=2.0
package_a
package_b
2 không chỉ định các phiên bản chính xác cho các phần phụ thuộc của nó. Ví dụ: nó cho phép mọi phiên bản của
$ twine upload dist/*
70

Một lần nữa, vì lợi ích của ví dụ này, giả sử một phiên bản mới của

$ twine upload dist/*
71 đã được phát hành, nhưng nó gây ra lỗi chặn hiển thị cho ứng dụng của bạn

Khi bạn thực hiện

package_c>=1.0,<=2.0
package_a
package_b
7 trong quá trình sản xuất lần này, bạn sẽ nhận được
$ twine upload dist/*
73 vì bạn đã ghim yêu cầu đó. Tuy nhiên, thật không may, bạn sẽ nhận được phiên bản mới nhất, có lỗi của
$ twine upload dist/*
71. Một lần nữa, sản phẩm bị hỏng trong sản xuất

Vấn đề thực sự ở đây là bản dựng không mang tính quyết định. Ý tôi là, với cùng một đầu vào (tệp

package_c>=1.0,<=2.0
package_a
package_b
0), pip không phải lúc nào cũng tạo ra cùng một môi trường. Hiện tại, bạn không thể dễ dàng sao chép môi trường chính xác mà bạn có trên máy phát triển của mình trong sản xuất

Giải pháp điển hình cho vấn đề này là sử dụng

$ twine upload dist/*
76. Lệnh này cho phép bạn nhận các phiên bản chính xác cho tất cả thư viện bên thứ 3 hiện được cài đặt, bao gồm cả pip phụ thuộc được cài đặt tự động. Vì vậy, bạn có thể đóng băng mọi thứ trong quá trình phát triển để đảm bảo rằng bạn có cùng một môi trường trong quá trình sản xuất

Việc thực thi

$ twine upload dist/*
76 dẫn đến các phụ thuộc được ghim mà bạn có thể thêm vào một
package_c>=1.0,<=2.0
package_a
package_b
0

package_a
package_b
6

Với các phụ thuộc được ghim này, bạn có thể đảm bảo rằng các gói được cài đặt trong môi trường sản xuất của bạn khớp chính xác với các gói trong môi trường phát triển của bạn, vì vậy sản phẩm của bạn không bị hỏng bất ngờ. Thật không may, “giải pháp” này lại dẫn đến một loạt vấn đề mới

Bây giờ bạn đã chỉ định các phiên bản chính xác của mọi gói bên thứ ba, bạn chịu trách nhiệm cập nhật các phiên bản này, mặc dù chúng là phần phụ thuộc của

package_c>=1.0,<=2.0
package_a
package_b
2. Điều gì sẽ xảy ra nếu có một lỗ hổng bảo mật được phát hiện trong
package_a
package_b
80 và những người bảo trì gói đã ngay lập tức vá trong
package_a
package_b
81?

Trước tiên, bạn cần lưu ý rằng có vấn đề với phiên bản bạn có. Sau đó, bạn cần tải phiên bản mới trong môi trường sản xuất của mình trước khi ai đó khai thác lỗ hổng bảo mật. Vì vậy, bạn phải thay đổi thủ công

package_c>=1.0,<=2.0
package_a
package_b
0 của mình để chỉ định phiên bản mới
package_a
package_b
81. Như bạn có thể thấy trong tình huống này, trách nhiệm cập nhật các bản cập nhật cần thiết thuộc về bạn

Sự thật là bạn thực sự không quan tâm phiên bản nào của

$ twine upload dist/*
71 được cài đặt miễn là nó không phá mã của bạn. Trên thực tế, bạn có thể muốn phiên bản mới nhất đảm bảo rằng bạn sẽ nhận được các bản sửa lỗi, bản vá bảo mật, tính năng mới, tối ưu hóa hơn, v.v.

câu hỏi thực sự là. “Làm cách nào để bạn cho phép các bản dựng xác định cho dự án Python của mình mà không chịu trách nhiệm cập nhật các phiên bản của phần phụ thuộc?”

cảnh báo spoiler. Câu trả lời dễ dàng là sử dụng Pipenv

Loại bỏ các quảng cáo

Phát triển các dự án với các phụ thuộc khác nhau

Hãy chuyển hướng một chút để nói về một vấn đề phổ biến khác phát sinh khi bạn làm việc trên nhiều dự án. Hãy tưởng tượng rằng

package_a
package_b
87 cần
package_a
package_b
88, nhưng
package_a
package_b
89 cần
package_a
package_b
80

Theo mặc định, Python cố gắng lưu trữ tất cả các gói bên thứ ba của bạn ở một vị trí trên toàn hệ thống. Điều này có nghĩa là mỗi khi bạn muốn chuyển đổi giữa

package_a
package_b
87 và
package_a
package_b
89, bạn phải đảm bảo đã cài đặt đúng phiên bản của
package_a
package_b
83. Điều này làm cho việc chuyển đổi giữa các dự án trở nên khó khăn vì bạn phải gỡ cài đặt và cài đặt lại các gói để đáp ứng các yêu cầu cho từng dự án

Giải pháp tiêu chuẩn là sử dụng một môi trường ảo có bộ lưu trữ gói của bên thứ ba và có thể thực thi Python của riêng nó. Bằng cách đó,

package_a
package_b
87 và
package_a
package_b
89 được phân tách đầy đủ. Giờ đây, bạn có thể dễ dàng chuyển đổi giữa các dự án vì chúng không chia sẻ cùng một vị trí lưu trữ gói.
package_a
package_b
86 có thể có bất kỳ phiên bản nào của
package_a
package_b
83 mà nó cần trong môi trường của chính nó và
package_a
package_b
88 có thể có những gì nó cần hoàn toàn riêng biệt. Một công cụ rất phổ biến cho việc này là
package_a
package_b
9 (hoặc
package_c>=1.0,<=2.0
package_a
package_b
80 trong Python 3)

Pipenv được tích hợp tính năng quản lý môi trường ảo để bạn có một công cụ duy nhất để quản lý gói của mình

Độ phân giải phụ thuộc

Ý tôi là gì khi giải quyết sự phụ thuộc?

package_a
package_b

Giả sử

package_c>=1.0,<=2.0
package_a
package_b
82 có phụ thuộc phụ thuộc vào
package_c>=1.0,<=2.0
package_a
package_b
83 và
package_c>=1.0,<=2.0
package_a
package_b
82 yêu cầu một phiên bản cụ thể của gói này.
package_c>=1.0,<=2.0
package_a
package_b
85. Đổi lại,
package_c>=1.0,<=2.0
package_a
package_b
86 có cùng phụ thuộc nhưng cần
package_c>=1.0,<=2.0
package_a
package_b
87

Lý tưởng nhất là khi bạn cố gắng cài đặt

package_c>=1.0,<=2.0
package_a
package_b
82 và
package_c>=1.0,<=2.0
package_a
package_b
86, công cụ cài đặt sẽ xem xét các yêu cầu dành cho
package_c>=1.0,<=2.0
package_a
package_b
83 (là
$ twine upload dist/*
001 và
$ twine upload dist/*
002) và chọn một phiên bản đáp ứng các yêu cầu đó. Bạn hy vọng rằng công cụ sẽ giải quyết các phụ thuộc để cuối cùng chương trình của bạn hoạt động. Đây là những gì tôi có nghĩa là "độ phân giải phụ thuộc. ”

Thật không may, hiện tại bản thân pip không có độ phân giải phụ thuộc thực sự, nhưng có một vấn đề mở để hỗ trợ nó

Cách pip sẽ xử lý tình huống trên như sau

  1. Nó cài đặt

    package_c>=1.0,<=2.0
    package_a
    package_b
    
    82 và tìm phiên bản của
    package_c>=1.0,<=2.0
    package_a
    package_b
    
    83 đáp ứng yêu cầu đầu tiên (
    package_c>=1.0,<=2.0
    package_a
    package_b
    
    85)

  2. Pip sau đó cài đặt phiên bản mới nhất của

    package_c>=1.0,<=2.0
    package_a
    package_b
    
    83 để đáp ứng yêu cầu đó. Giả sử phiên bản mới nhất của
    package_c>=1.0,<=2.0
    package_a
    package_b
    
    83 là 3. 1

Đây là nơi rắc rối (có khả năng) bắt đầu

Nếu phiên bản của

package_c>=1.0,<=2.0
package_a
package_b
83 do pip chọn không phù hợp với các yêu cầu trong tương lai (chẳng hạn như
package_c>=1.0,<=2.0
package_a
package_b
86 cần
package_c>=1.0,<=2.0
package_a
package_b
87), quá trình cài đặt sẽ không thành công

“Giải pháp” cho vấn đề này là chỉ định phạm vi cần thiết cho phụ thuộc phụ (

package_c>=1.0,<=2.0
package_a
package_b
83) trong tệp
package_c>=1.0,<=2.0
package_a
package_b
0. Bằng cách đó, pip có thể giải quyết xung đột này và cài đặt gói đáp ứng các yêu cầu đó

package_c>=1.0,<=2.0
package_a
package_b

Tuy nhiên, cũng giống như trước đây, giờ đây bạn đang trực tiếp quan tâm đến bản thân với các yếu tố phụ thuộc (

package_c>=1.0,<=2.0
package_a
package_b
83). Vấn đề với điều này là nếu
package_c>=1.0,<=2.0
package_a
package_b
82 thay đổi yêu cầu của họ mà bạn không biết, thì các yêu cầu bạn đã chỉ định (
$ twine upload dist/*
015) có thể không còn được chấp nhận nữa và quá trình cài đặt có thể bị lỗi… lần nữa. Vấn đề thực sự là một lần nữa, bạn chịu trách nhiệm cập nhật các yêu cầu của phụ thuộc

Lý tưởng nhất là công cụ cài đặt của bạn đủ thông minh để cài đặt các gói đáp ứng tất cả các yêu cầu mà bạn không cần chỉ định rõ ràng các phiên bản phụ thuộc

Giới thiệu Pipenv

Bây giờ chúng tôi đã giải quyết các vấn đề, hãy xem cách Pipenv giải quyết chúng

Đầu tiên, hãy cài đặt nó

package_c>=1.0,<=2.0
package_a
package_b
6

Khi bạn đã hoàn thành việc đó, bạn có thể quên đi

package_a
package_b
8 một cách hiệu quả vì về cơ bản, Pipenv đóng vai trò thay thế. Nó cũng giới thiệu hai tệp mới,
$ twine upload dist/*
017 (có nghĩa là để thay thế
package_c>=1.0,<=2.0
package_a
package_b
0) và
$ twine upload dist/*
019 (cho phép các bản dựng xác định)

Pipenv sử dụng

package_a
package_b
8 và
package_a
package_b
9 hoàn toàn nhưng đơn giản hóa việc sử dụng chúng bằng một giao diện dòng lệnh duy nhất

Loại bỏ các quảng cáo

Ví dụ sử dụng

Hãy bắt đầu lại với việc tạo ứng dụng Python tuyệt vời của bạn. Đầu tiên, sinh ra một vỏ trong môi trường ảo để cô lập sự phát triển của ứng dụng này

$ twine upload dist/*
7

Điều này sẽ tạo ra một môi trường ảo nếu một môi trường chưa tồn tại. Pipenv tạo tất cả các môi trường ảo của bạn ở một vị trí mặc định. Nếu bạn muốn thay đổi hành vi mặc định của Pipenv, có một số

Bạn có thể buộc tạo môi trường Python 2 hoặc 3 bằng các đối số tương ứng là

$ twine upload dist/*
022 và
$ twine upload dist/*
023. Nếu không, Pipenv sẽ sử dụng bất kỳ thứ gì mặc định mà
package_a
package_b
9 tìm thấy

phụ lục. Nếu bạn yêu cầu phiên bản Python cụ thể hơn, bạn có thể cung cấp đối số

$ twine upload dist/*
025 với phiên bản bạn yêu cầu. Ví dụ.
$ twine upload dist/*
026

Bây giờ bạn có thể cài đặt gói bên thứ 3 mà bạn cần,

package_c>=1.0,<=2.0
package_a
package_b
2. Ồ, nhưng bạn biết rằng bạn cần phiên bản
$ twine upload dist/*
028 chứ không phải phiên bản mới nhất, vì vậy hãy tiếp tục và cụ thể

package_a
package_b
8

Bạn sẽ thấy một cái gì đó như sau trong thiết bị đầu cuối của mình

package_a
package_b
8

Bạn sẽ nhận thấy rằng có hai tệp được tạo, một tệp

$ twine upload dist/*
017 và tệp
$ twine upload dist/*
019. Chúng ta sẽ xem xét kỹ hơn những điều này trong giây lát. Hãy cài đặt một gói bên thứ 3 khác,
$ twine upload dist/*
031, để xử lý số liệu. Bạn không cần một phiên bản cụ thể, vì vậy đừng chỉ định một phiên bản

package_c>=1.0,<=2.0
package_a
package_b
8

Nếu bạn muốn cài đặt thứ gì đó trực tiếp từ hệ thống kiểm soát phiên bản (VCS), bạn có thể. Bạn chỉ định các vị trí tương tự như cách bạn làm như vậy với

package_a
package_b
8. Ví dụ: để cài đặt thư viện
$ twine upload dist/*
033 từ kiểm soát phiên bản, hãy làm như sau

$ twine upload dist/*
00

Lưu ý đối số

$ twine upload dist/*
034 ở trên để cài đặt có thể chỉnh sửa được. Hiện tại, để Pipenv thực hiện giải quyết phụ thuộc

Giả sử bạn cũng có một số bài kiểm tra đơn vị cho ứng dụng tuyệt vời này và bạn muốn sử dụng

$ twine upload dist/*
035 để chạy chúng. Bạn không cần
$ twine upload dist/*
035 trong quá trình sản xuất, vì vậy bạn có thể chỉ định rằng phần phụ thuộc này chỉ dành cho quá trình phát triển với đối số
$ twine upload dist/*
037

$ twine upload dist/*
01

Việc cung cấp đối số

$ twine upload dist/*
037 sẽ đặt phần phụ thuộc vào một vị trí đặc biệt của
$ twine upload dist/*
039 trong
$ twine upload dist/*
017. Các gói phát triển này chỉ được cài đặt nếu bạn chỉ định đối số
$ twine upload dist/*
037 với
$ twine upload dist/*
042

Các phần khác nhau tách biệt các phần phụ thuộc chỉ cần thiết để phát triển với phần phụ thuộc cần thiết để mã cơ sở thực sự hoạt động. Thông thường, điều này sẽ được thực hiện với các tệp yêu cầu bổ sung như

$ twine upload dist/*
043 hoặc
$ twine upload dist/*
044. Bây giờ, mọi thứ được hợp nhất trong một
$ twine upload dist/*
017 duy nhất dưới các phần khác nhau

Được rồi, giả sử bạn có mọi thứ hoạt động trong môi trường phát triển cục bộ của mình và bạn đã sẵn sàng đưa nó vào sản xuất. Để làm điều đó, bạn cần khóa môi trường của mình để có thể đảm bảo rằng bạn có môi trường tương tự trong quá trình sản xuất

$ twine upload dist/*
02

Thao tác này sẽ tạo/cập nhật

$ twine upload dist/*
019 của bạn mà bạn sẽ không bao giờ cần (và không bao giờ có ý định) chỉnh sửa theo cách thủ công. Bạn phải luôn sử dụng tệp được tạo

Bây giờ, sau khi bạn nhận được mã và

$ twine upload dist/*
019 trong môi trường sản xuất của mình, bạn nên cài đặt môi trường thành công cuối cùng được ghi lại

$ twine upload dist/*
03

Điều này yêu cầu Pipenv bỏ qua

$ twine upload dist/*
017 để cài đặt và sử dụng những gì có trong
$ twine upload dist/*
019. Với
$ twine upload dist/*
019 này, Pipenv sẽ tạo chính xác môi trường mà bạn đã có khi chạy
$ twine upload dist/*
051, phụ thuộc phụ và tất cả

Tệp khóa cho phép các bản dựng xác định bằng cách chụp nhanh tất cả các phiên bản của gói trong một môi trường (tương tự như kết quả của

$ twine upload dist/*
76)

Bây giờ, giả sử một nhà phát triển khác muốn thực hiện một số bổ sung cho mã của bạn. Trong tình huống này, họ sẽ lấy mã, bao gồm cả

$ twine upload dist/*
017 và sử dụng lệnh này

$ twine upload dist/*
04

Thao tác này sẽ cài đặt tất cả các phần phụ thuộc cần thiết cho quá trình phát triển, bao gồm cả phần phụ thuộc thông thường và phần phụ thuộc mà bạn đã chỉ định với đối số

$ twine upload dist/*
037 trong thời gian
$ twine upload dist/*
055

Khi một phiên bản chính xác không được chỉ định trong Pipfile, lệnh

$ twine upload dist/*
055 sẽ tạo cơ hội cho các phần phụ thuộc (và phần phụ thuộc) cập nhật phiên bản của chúng

Đây là một lưu ý quan trọng vì nó giải quyết một số vấn đề trước đây chúng ta đã thảo luận. Để chứng minh, giả sử một phiên bản mới của một trong các phần phụ thuộc của bạn có sẵn. Vì bạn không cần phiên bản cụ thể của phần phụ thuộc này nên bạn không chỉ định phiên bản chính xác trong

$ twine upload dist/*
017. Khi bạn
$ twine upload dist/*
042, phiên bản phụ thuộc mới sẽ được cài đặt trong môi trường phát triển của bạn

Bây giờ, bạn thực hiện các thay đổi của mình đối với mã và chạy một số thử nghiệm để xác minh mọi thứ vẫn hoạt động như mong đợi. (Bạn có các bài kiểm tra đơn vị phải không?) Bây giờ, giống như trước đây, bạn khóa môi trường của mình bằng

$ twine upload dist/*
051 và một bản cập nhật
$ twine upload dist/*
019 sẽ được tạo với phiên bản phụ thuộc mới. Giống như trước đây, bạn có thể tái tạo môi trường mới này trong sản xuất bằng tệp khóa

Như bạn có thể thấy từ kịch bản này, bạn không còn phải ép buộc các phiên bản chính xác mà bạn không thực sự cần để đảm bảo môi trường sản xuất và phát triển của bạn giống nhau. Bạn cũng không cần phải luôn cập nhật các phụ thuộc phụ mà bạn “không quan tâm. ” Quy trình công việc này với Pipenv, kết hợp với thử nghiệm xuất sắc của bạn, khắc phục các sự cố khi thực hiện thủ công tất cả hoạt động quản lý phụ thuộc của bạn

Loại bỏ các quảng cáo

Phương pháp tiếp cận giải quyết phụ thuộc của Pipenv

Pipenv sẽ cố gắng cài đặt các phụ thuộc phụ đáp ứng tất cả các yêu cầu từ các phụ thuộc cốt lõi của bạn. Tuy nhiên, nếu có các phụ thuộc xung đột (

package_c>=1.0,<=2.0
package_a
package_b
82 cần
package_c>=1.0,<=2.0
package_a
package_b
85, nhưng
package_c>=1.0,<=2.0
package_a
package_b
86 cần
$ twine upload dist/*
064), Pipenv sẽ không thể tạo tệp khóa và sẽ xuất ra lỗi như sau

$ twine upload dist/*
05

Như đã cảnh báo, bạn cũng có thể hiển thị biểu đồ phụ thuộc để hiểu các phụ thuộc cấp cao nhất của mình và các phụ thuộc phụ của chúng

$ twine upload dist/*
06

Lệnh này sẽ in ra một cấu trúc dạng cây hiển thị các phần phụ thuộc của bạn. Đây là một ví dụ

$ twine upload dist/*
07

Từ đầu ra của

$ twine upload dist/*
065, bạn có thể thấy các gói phụ thuộc cấp cao nhất mà chúng tôi đã cài đặt trước đó (
$ twine upload dist/*
066,
$ twine upload dist/*
031,
$ twine upload dist/*
035 và
$ twine upload dist/*
033) và bên dưới, bạn có thể thấy các gói mà chúng phụ thuộc vào

Ngoài ra, bạn có thể đảo ngược cây để hiển thị các thành phần phụ thuộc với cha yêu cầu nó

$ twine upload dist/*
08

Cây đảo ngược này có thể hữu ích hơn khi bạn đang cố gắng tìm ra các phụ thuộc phụ xung đột

Pipfile

Pipfile dự định thay thế

package_c>=1.0,<=2.0
package_a
package_b
0. Pipenv hiện là triển khai tham chiếu để sử dụng
$ twine upload dist/*
017. Có vẻ như rất có khả năng rằng. Ngoài ra, điều đáng chú ý là

Cú pháp của

$ twine upload dist/*
017 là TOML và tệp được chia thành các phần.
$ twine upload dist/*
039 cho các gói chỉ dành cho phát triển,
$ twine upload dist/*
075 cho các gói yêu cầu tối thiểu và
$ twine upload dist/*
076 cho các yêu cầu khác như phiên bản cụ thể của Python. Xem một tập tin ví dụ dưới đây

$ twine upload dist/*
09

Lý tưởng nhất là bạn không nên có bất kỳ phụ thuộc phụ nào trong

$ twine upload dist/*
017 của mình. Điều tôi muốn nói là bạn chỉ nên bao gồm các gói bạn thực sự nhập và sử dụng. Không cần giữ
$ twine upload dist/*
078 trong
$ twine upload dist/*
017 của bạn chỉ vì nó là phụ thuộc phụ của
$ twine upload dist/*
033. (Pipenv sẽ cài đặt tự động. )
$ twine upload dist/*
017 phải truyền đạt các phụ thuộc cấp cao nhất mà gói của bạn yêu cầu

Pipfile. Khóa

Tệp này cho phép các bản dựng xác định bằng cách chỉ định các yêu cầu chính xác để tái tạo một môi trường. Nó chứa các phiên bản chính xác cho các gói và hàm băm để hỗ trợ xác minh an toàn hơn, điều này cũng. Một tệp ví dụ có thể trông giống như sau. Lưu ý rằng cú pháp của tệp này là JSON và tôi đã loại trừ các phần của tệp bằng

$ twine upload dist/*
083

package_a
package_b
60

Lưu ý phiên bản chính xác được chỉ định cho mọi phụ thuộc. Ngay cả các phụ thuộc phụ như

$ twine upload dist/*
084 không có trong
$ twine upload dist/*
017 của chúng tôi cũng xuất hiện trong
$ twine upload dist/*
019 này. Các giá trị băm được sử dụng để đảm bảo bạn đang truy xuất gói giống như bạn đã làm trong quá trình phát triển

Cần lưu ý một lần nữa rằng bạn không bao giờ được thay đổi tệp này bằng tay. Nó có nghĩa là được tạo ra với

$ twine upload dist/*
051

Loại bỏ các quảng cáo

Các tính năng bổ sung của Pipenv

Mở gói của bên thứ ba trong trình chỉnh sửa mặc định của bạn bằng lệnh sau

package_a
package_b
61

Thao tác này sẽ mở gói

package_c>=1.0,<=2.0
package_a
package_b
2 trong trình chỉnh sửa mặc định hoặc bạn có thể chỉ định chương trình có biến môi trường
$ twine upload dist/*
089. Ví dụ mình dùng Sublime Text nên chỉ đặt
$ twine upload dist/*
090. Điều này làm cho việc tìm hiểu bên trong gói bạn đang sử dụng trở nên cực kỳ đơn giản


Bạn có thể chạy một lệnh trong môi trường ảo mà không cần khởi chạy shell

package_a
package_b
62


Kiểm tra các lỗ hổng bảo mật (và yêu cầu PEP 508) trong môi trường của bạn

package_a
package_b
63


Bây giờ, giả sử bạn không cần gói nữa. Bạn có thể gỡ cài đặt nó

package_a
package_b
64

Ngoài ra, giả sử bạn muốn xóa hoàn toàn tất cả các gói đã cài đặt khỏi môi trường ảo của mình

package_a
package_b
65

Bạn có thể thay thế

$ twine upload dist/*
091 bằng
$ twine upload dist/*
092 để xóa các gói dev


Pipenv hỗ trợ tự động tải các biến môi trường khi tệp

$ twine upload dist/*
093 tồn tại trong thư mục cấp cao nhất. Theo cách đó, khi bạn
$ twine upload dist/*
094 mở môi trường ảo, nó sẽ tải các biến môi trường của bạn từ tệp. Tệp
$ twine upload dist/*
093 chỉ chứa các cặp khóa-giá trị

package_a
package_b
66


Cuối cùng, đây là một số lệnh nhanh để tìm xem đồ đạc ở đâu. Cách tìm ra môi trường ảo của bạn ở đâu

package_a
package_b
67

Làm thế nào để tìm ra nơi dự án nhà của bạn là

package_a
package_b
68

Loại bỏ các quảng cáo

Phân phối gói

Bạn có thể hỏi tất cả điều này hoạt động như thế nào nếu bạn định phân phối mã của mình dưới dạng gói

Có, tôi cần phân phối mã của mình dưới dạng gói

Pipenv hoạt động như thế nào với các tệp

$ twine upload dist/*
096?

Có rất nhiều sắc thái cho câu hỏi đó. Đầu tiên, tệp

$ twine upload dist/*
096 là cần thiết khi bạn đang sử dụng
$ twine upload dist/*
098 làm hệ thống xây dựng/phân phối của mình. Đây đã là tiêu chuẩn thực tế trong một thời gian, nhưng những thay đổi gần đây đã khiến việc sử dụng
$ twine upload dist/*
098 trở thành tùy chọn

Điều này có nghĩa là các dự án như flit có thể sử dụng

package_a
package_b
600 mới để chỉ định một hệ thống xây dựng khác không yêu cầu
$ twine upload dist/*
096

Tất cả những gì đang được nói, trong tương lai gần

$ twine upload dist/*
098 và một
$ twine upload dist/*
096 đi kèm vẫn sẽ là lựa chọn mặc định của nhiều người

Đây là quy trình công việc được đề xuất khi bạn đang sử dụng

$ twine upload dist/*
096 như một cách để phân phối gói hàng của mình

  • $ twine upload dist/*
    
    096
  • Từ khóa
    package_a
    package_b
    
    606 nên bao gồm bất kỳ gói nào “cần tối thiểu để chạy chính xác. ”
  • $ twine upload dist/*
    
    017
  • Đại diện cho các yêu cầu cụ thể cho gói của bạn
  • Kéo các phụ thuộc tối thiểu bắt buộc từ
    $ twine upload dist/*
    
    096 bằng cách cài đặt gói của bạn bằng Pipenv
    • Sử dụng
      package_a
      package_b
      
      609
    • Điều đó sẽ dẫn đến một dòng trong
      $ twine upload dist/*
      
      017 của bạn trông giống như
      package_a
      package_b
      
      611
  • $ twine upload dist/*
    
    019
  • Thông tin chi tiết về môi trường có thể tái sản xuất được tạo từ
    $ twine upload dist/*
    
    051

Để làm rõ, hãy đặt các yêu cầu tối thiểu của bạn vào

$ twine upload dist/*
096 thay vì trực tiếp với
$ twine upload dist/*
042. Sau đó, sử dụng lệnh
package_a
package_b
609 để cài đặt gói của bạn dưới dạng có thể chỉnh sửa. Điều này nhận được tất cả các yêu cầu từ
$ twine upload dist/*
096 vào môi trường của bạn. Sau đó, bạn có thể sử dụng
$ twine upload dist/*
051 để có được môi trường có thể tái tạo

Tôi không cần phân phối mã của mình dưới dạng gói

Tuyệt quá. Nếu bạn đang phát triển một ứng dụng không nhằm mục đích phân phối hoặc cài đặt (trang web cá nhân, ứng dụng dành cho máy tính để bàn, trò chơi hoặc tương tự), bạn không thực sự cần một

$ twine upload dist/*
096

Trong tình huống này, bạn có thể sử dụng kết hợp

$ twine upload dist/*
017/
$ twine upload dist/*
019 để quản lý các thành phần phụ thuộc của mình với quy trình được mô tả trước đó nhằm triển khai một môi trường có thể tái sản xuất trong sản xuất

Tôi đã có một package_c>=1.0,<=2.0 package_a package_b 0. Làm cách nào để chuyển đổi sang $ twine upload dist/* 017?

Nếu bạn chạy

$ twine upload dist/*
042, nó sẽ tự động phát hiện
package_c>=1.0,<=2.0
package_a
package_b
0 và chuyển đổi nó thành
$ twine upload dist/*
017, xuất ra kết quả như sau

package_a
package_b
69

Lưu ý cảnh báo trên

Nếu bạn đã ghim các phiên bản chính xác trong tệp

package_c>=1.0,<=2.0
package_a
package_b
0 của mình, có thể bạn sẽ muốn thay đổi
$ twine upload dist/*
017 của mình để chỉ chỉ định các phiên bản chính xác mà bạn thực sự yêu cầu. Điều này sẽ cho phép bạn đạt được những lợi ích thực sự của việc chuyển đổi. Ví dụ: giả sử bạn có những thứ sau đây nhưng thực sự không cần phiên bản chính xác của
$ twine upload dist/*
031

package_a
package_b
0

Nếu bạn không có bất kỳ yêu cầu phiên bản cụ thể nào cho các phần phụ thuộc của mình, bạn có thể sử dụng ký tự đại diện

package_a
package_b
630 để cho Pipenv biết rằng bất kỳ phiên bản nào cũng có thể được cài đặt

package_a
package_b
1

Nếu bạn cảm thấy lo lắng về việc cho phép bất kỳ phiên bản nào với

package_a
package_b
630, thì cách an toàn nhất là chỉ định lớn hơn hoặc bằng phiên bản bạn đang sử dụng để bạn vẫn có thể tận dụng các phiên bản mới

package_a
package_b
2

Tất nhiên, luôn cập nhật các bản phát hành mới cũng có nghĩa là bạn chịu trách nhiệm đảm bảo mã của mình vẫn hoạt động như mong đợi khi các gói thay đổi. Điều này có nghĩa là một bộ thử nghiệm là cần thiết cho toàn bộ quy trình Pipenv này nếu bạn muốn đảm bảo các bản phát hành mã của mình hoạt động hiệu quả

Bạn cho phép các gói cập nhật, chạy thử nghiệm, đảm bảo tất cả chúng đều vượt qua, khóa môi trường của bạn và sau đó bạn có thể yên tâm khi biết rằng mình chưa giới thiệu các thay đổi vi phạm. Nếu mọi thứ bị hỏng do phụ thuộc, bạn có một số bài kiểm tra hồi quy để viết và có thể có thêm một số hạn chế đối với các phiên bản phụ thuộc

Ví dụ: nếu

package_a
package_b
632 được cài đặt sau khi chạy
$ twine upload dist/*
042 và nó phá vỡ mã của bạn, điều mà bạn hy vọng sẽ nhận thấy trong quá trình phát triển hoặc trong quá trình thử nghiệm của mình, thì bạn có một số tùy chọn

  1. Cập nhật mã của bạn để hoạt động với phiên bản phụ thuộc mới

    Nếu không thể tương thích ngược với các phiên bản phụ thuộc trước đó, thì bạn cũng cần phải tăng phiên bản được yêu cầu trong

    $ twine upload dist/*
    
    017 của mình

    package_a
    package_b
    
    3

  2. Hạn chế phiên bản phụ thuộc trong

    $ twine upload dist/*
    
    017 thành
    package_a
    package_b
    
    636 phiên bản vừa phá vỡ mã của bạn

    package_a
    package_b
    
    4

Tùy chọn 1 được ưu tiên hơn vì nó đảm bảo rằng mã của bạn đang sử dụng các phụ thuộc cập nhật nhất. Tuy nhiên, Tùy chọn 2 mất ít thời gian hơn và không yêu cầu thay đổi mã, chỉ hạn chế về phụ thuộc


Bạn cũng có thể cài đặt từ các tệp yêu cầu với cùng đối số

package_a
package_b
637 mà
package_a
package_b
8 mất

package_a
package_b
5

Nếu bạn có

$ twine upload dist/*
043 hoặc thứ gì đó tương tự, bạn cũng có thể thêm chúng vào
$ twine upload dist/*
017. Chỉ cần thêm đối số
$ twine upload dist/*
037 để nó được đưa vào đúng phần

package_a
package_b
6

Ngoài ra, bạn có thể thực hiện theo cách khác và tạo các tệp yêu cầu từ

$ twine upload dist/*
017

package_a
package_b
7

Loại bỏ các quảng cáo

Cái gì tiếp theo?

Đối với tôi, có vẻ như tiến trình tự nhiên cho hệ sinh thái Python sẽ là một hệ thống xây dựng sử dụng

$ twine upload dist/*
017 để cài đặt các phụ thuộc tối thiểu cần thiết khi truy xuất và xây dựng gói từ chỉ mục gói (như PyPI). Điều quan trọng cần lưu ý một lần nữa là đặc tả thiết kế Pipfile vẫn đang được phát triển và Pipenv chỉ là một triển khai tham khảo

Điều đó đang được nói, tôi có thể thấy một tương lai nơi phần

package_a
package_b
606 của
$ twine upload dist/*
096 không tồn tại và thay vào đó,
$ twine upload dist/*
017 được tham chiếu cho các yêu cầu tối thiểu. Hoặc
$ twine upload dist/*
096 đã biến mất hoàn toàn và bạn nhận được siêu dữ liệu cũng như thông tin khác theo một cách khác, vẫn sử dụng
$ twine upload dist/*
017 để nhận các phụ thuộc cần thiết

Pipenv có đáng để kiểm tra không?

Chắc chắn. Ngay cả khi đó chỉ là một cách để hợp nhất các công cụ bạn đã sử dụng (

package_a
package_b
8 &
package_a
package_b
9) vào một giao diện duy nhất. Tuy nhiên, nó còn hơn thế nữa. Với việc bổ sung
$ twine upload dist/*
017, bạn chỉ xác định các phụ thuộc mà bạn thực sự cần

Bạn không còn phải đau đầu trong việc tự mình quản lý các phiên bản của mọi thứ chỉ để đảm bảo rằng bạn có thể tái tạo môi trường phát triển của mình. Với

$ twine upload dist/*
019, bạn có thể yên tâm phát triển khi biết rằng bạn có thể tái tạo chính xác môi trường của mình ở bất cứ đâu

Ngoài tất cả những điều đó, có vẻ như định dạng

$ twine upload dist/*
017 sẽ được chấp nhận và hỗ trợ bởi các công cụ Python chính thức như
package_a
package_b
8, vì vậy sẽ rất có lợi nếu bạn đi trước cuộc chơi. Ồ, và đảm bảo rằng bạn cũng đang cập nhật tất cả mã của mình lên Python 3.

Tài liệu tham khảo, đọc thêm, thảo luận thú vị, v.v.

  • Tài liệu chính thức của Pipenv
  • Dự án
    $ twine upload dist/*
    
    017 chính thức
  • Vấn đề giải quyết
    package_a
    package_b
    
    606 liên quan đến
    $ twine upload dist/*
    
    017
  • Thảo luận thêm về
    $ twine upload dist/*
    
    096 so với
    $ twine upload dist/*
    
    017
  • Bài viết nói về PEP 518
  • Đăng trên bao bì Python

Tiền thưởng miễn phí. Nhấp vào đây để truy cập lớp học 5 ngày miễn phí chỉ cho bạn cách tránh các sự cố quản lý phụ thuộc phổ biến với các công cụ như Pip, PyPI, Virtualenv và các tệp yêu cầu

Đánh dấu là đã hoàn thành

Xem ngay Hướng dẫn này có một khóa học video liên quan do nhóm Real Python tạo. Xem nó cùng với hướng dẫn bằng văn bản để hiểu sâu hơn. Làm việc với Pipenv

🐍 Thủ thuật Python 💌

Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python

Công cụ đóng gói trong Python là gì?

Gửi cho tôi thủ thuật Python »

Giới thiệu về Alexander VanTol

Công cụ đóng gói trong Python là gì?
Công cụ đóng gói trong Python là gì?

Alexander là một Pythonista cuồng nhiệt, người dành thời gian cho nhiều dự án sáng tạo khác nhau liên quan đến lập trình, âm nhạc và viết sáng tạo

» Thông tin thêm về Alexander


Mỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là

Công cụ đóng gói trong Python là gì?

Aldren

Công cụ đóng gói trong Python là gì?

Đan

Công cụ đóng gói trong Python là gì?

Joanna

Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Bậc thầy Kỹ năng Python trong thế giới thực
Với quyền truy cập không giới hạn vào Python thực

Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia

Nâng cao kỹ năng Python của bạn »

Bạn nghĩ sao?

Đánh giá bài viết này

Tweet Chia sẻ Chia sẻ Email

Bài học số 1 hoặc điều yêu thích mà bạn đã học được là gì?

Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi

Ví dụ về gói trong Python là gì?

Một gói về cơ bản là một thư mục chứa các tệp Python và một tệp có tên __init__. py. Điều này có nghĩa là mọi thư mục bên trong đường dẫn Python chứa tệp có tên __init__. py, sẽ được Python coi là một gói

Làm cách nào để đóng gói một ứng dụng Python?

Sử dụng pip là cách thông thường nhất và được hỗ trợ tốt nhất để đóng gói ứng dụng Python để tái sử dụng . Chỉ cần lấy thư mục ứng dụng của bạn và trang bị cho nó một thiết lập. py, biến nó thành một gói có thể cài đặt pip.