request.txt vs setup.py


110

Tôi đã bắt đầu làm việc với Python. Tôi đã thêm requirements.txtsetup.pyvào dự án của mình. Nhưng, tôi vẫn còn nhầm lẫn về mục đích của cả hai tệp. Tôi đã đọc nó setup.pyđược thiết kế cho những thứ có thể phân phối lại và nó requirements.txtđược thiết kế cho những thứ không thể phân phối lại. Nhưng tôi không chắc điều này là chính xác.

Hai tệp đó thực sự được sử dụng như thế nào?


1
Bạn đã tìm kiếm trên web bằng tiêu đề chính xác của mình chưa? Bài báo này ( bài viết đầu tiên khi tôi tìm kiếm) là bài báo hay nhất mà tôi đã đọc về chủ đề này.
Chris

2
Bài viết này có thể hữu ích: caremad.io/posts/2013/07/setup-vs-requirement (xin lỗi, quá lười để trích xuất những điều cần thiết thành một câu trả lời thích hợp). Một điều nữa là, một số công cụ (ví dụ: thử nghiệm) có thể có thành kiến ​​với cái này hay cái khác - nhưng đừng để nó làm phiền bạn nếu bạn mới bắt đầu làm việc trên Python.
drdaeman

Câu trả lời:


83

request.txt

Điều này giúp bạn thiết lập môi trường phát triển của mình. Các chương trình như thế này pipcó thể được sử dụng để cài đặt tất cả các gói được liệt kê trong tệp trong một lần cài đặt. Sau đó, bạn có thể bắt đầu phát triển tập lệnh python của mình. Đặc biệt hữu ích nếu bạn định nhờ người khác đóng góp vào sự phát triển hoặc sử dụng môi trường ảo. Đây là cách bạn sử dụng nó:

pip install -r requirements.txt

setup.py

Điều này cho phép bạn tạo các gói mà bạn có thể phân phối lại. Tập lệnh này nhằm cài đặt gói của bạn trên hệ thống của người dùng cuối, không phải để chuẩn bị môi trường phát triển pip install -r requirements.txt. Xem câu trả lời này để biết thêm chi tiết trên setup.py.

Các phần phụ thuộc của dự án của bạn được liệt kê trong cả hai tệp.


2
Trong trường hợp nào tôi sẽ chỉ có một trong số họ? Trong đó tôi sẽ có cả hai?
Martin Thoma

27
Erm ... bạn chỉ viết kịch bản cho vui trên máy cục bộ của bạn: Không. Script được phát triển trên nhiều máy / vitualenvs nhưng không được phân phối lại: tests.txt. Tập lệnh chỉ được phát triển trên máy của bạn nhưng phải được phân phối lại: setup.py. Script sẽ được phân phối lại và phát triển trong nhiều môi trường: Cả hai.
AndreasT

Bạn có thể thêm điều này vào câu trả lời?
Martin Thoma

58

Câu trả lời ngắn gọn là chỉ requirements.txtdành cho các yêu cầu về gói danh sách. setup.pymặt khác giống một tập lệnh cài đặt hơn. Nếu bạn không có kế hoạch cài đặt mã python, thông thường bạn sẽ chỉ cần requirements.txt.

Tệp setup.pymô tả, ngoài các phụ thuộc gói, tập hợp các tệp và mô-đun nên được đóng gói (hoặc được biên dịch, trong trường hợp mô-đun gốc (tức là được viết bằng C)) và siêu dữ liệu để thêm vào danh sách gói python ( ví dụ: tên gói, phiên bản gói, mô tả gói, tác giả, ...).

Vì cả hai tệp đều liệt kê các phụ thuộc, điều này có thể dẫn đến một chút trùng lặp. Đọc bên dưới để biết chi tiết.

request.txt


Tệp này liệt kê các yêu cầu về gói python. Đây là một tệp văn bản thuần túy (tùy chọn với các nhận xét) liệt kê các gói phụ thuộc của dự án python của bạn (một gói trên mỗi dòng). Nó không mô tả cách mà gói python của bạn được cài đặt. Bạn thường sử dụng tệp yêu cầu với pip install -r requirements.txt.

Tên tệp của tệp văn bản là tùy ý, nhưng thường là requirements.txttheo quy ước. Khi khám phá kho mã nguồn của các gói python khác, bạn có thể gặp phải các tên khác, chẳng hạn như dev-dependencies.txthoặc dependencies-dev.txt. Chúng phục vụ cùng mục đích dependencies.txtnhưng thường liệt kê các phụ thuộc bổ sung mà các nhà phát triển gói cụ thể quan tâm, cụ thể là để kiểm tra mã nguồn (ví dụ: pytest, pylint, v.v.) trước khi phát hành. Người dùng của gói nói chung sẽ không cần toàn bộ tập hợp các phụ thuộc của nhà phát triển để chạy gói.

Nếu có nhiều requirements-X.txtbiến thể, thì thường một biến thể sẽ liệt kê các phụ thuộc thời gian chạy và các phụ thuộc thời gian xây dựng hoặc thử nghiệm khác. Một số dự án cũng phân tầng tệp yêu cầu của họ, tức là khi một tệp yêu cầu bao gồm tệp khác ( ví dụ ). Làm như vậy có thể giảm sự lặp lại.

setup.py


Đây là một tập lệnh python sử dụng setuptoolsmô-đun để xác định một gói python (tên, tệp bao gồm, siêu dữ liệu gói và cài đặt). Nó cũng sẽ requirements.txtliệt kê các phụ thuộc thời gian chạy của gói. Setuptools là cách thực tế để xây dựng và cài đặt các gói python, nhưng nó có những khuyết điểm, theo thời gian đã làm nảy sinh sự phát triển của các "trình quản lý gói meta" mới, như pip. Các thiếu sót ví dụ của setuptools là không có khả năng cài đặt nhiều phiên bản của cùng một gói và thiếu lệnh gỡ cài đặt.

Khi người dùng python thực hiện pip install ./pkgdir_my_module(hoặc pip install my-module), pip sẽ chạy setup.pytrong thư mục (hoặc mô-đun) đã cho. Tương tự, bất kỳ mô-đun nào có một setup.pyđều có thể được pipcài đặt, ví dụ bằng cách chạy pip install .từ cùng một thư mục.

Tôi có thực sự cần cả hai không?


Câu trả lời ngắn gọn là không, nhưng thật tuyệt khi có cả hai. Chúng đạt được các mục đích khác nhau, nhưng cả hai đều có thể được sử dụng để liệt kê các phụ thuộc của bạn.

Có một thủ thuật bạn có thể cân nhắc để tránh trùng lặp danh sách các phụ thuộc giữa requirements.txtsetup.py. Nếu bạn đã viết một setup.pygói hoạt động hoàn toàn cho gói của mình và các phần phụ thuộc của bạn chủ yếu là bên ngoài, bạn có thể xem xét việc có một đơn giản requirements.txtchỉ với những điều sau:

 # requirements.txt
 #
 # installs dependencies from ./setup.py, and the package itself,
 # in editable mode
 -e .

 # (the -e above is optional). you could also just install the package
 # normally with just the line below (after uncommenting)
 # .

Đây -elà một pip installtùy chọn đặc biệt cài đặt gói đã cho ở chế độ có thể chỉnh sửa . Khi pip -r requirements.txtđược chạy trên tệp này, pip sẽ cài đặt các phần phụ thuộc của bạn thông qua danh sách trong ./setup.py. Tùy chọn có thể chỉnh sửa sẽ đặt một liên kết biểu tượng trong thư mục cài đặt của bạn (thay vì một quả trứng hoặc bản sao lưu trữ). Nó cho phép các nhà phát triển chỉnh sửa mã tại chỗ từ kho mà không cần cài đặt lại.

Bạn cũng có thể tận dụng những gì được gọi là "phần bổ sung của setuptools" khi bạn có cả hai tệp trong kho lưu trữ gói của mình. Bạn có thể xác định các gói tùy chọn trong setup.py trong một danh mục tùy chỉnh và cài đặt các gói đó chỉ từ danh mục đó bằng pip:

# setup.py
from setuptools import setup
setup(
   name="FOO"
   ...
   extras_require = {
       'dev': ['pylint'],
       'build': ['requests']
   }
   ...
)

và sau đó, trong tệp yêu cầu:

# install packages in the [build] category, from setup.py
# (path/to/mypkg is the directory where setup.py is)
-e path/to/mypkg[build]

Điều này sẽ giữ tất cả danh sách phụ thuộc của bạn bên trong setup.py.

Lưu ý : Bạn thường thực thi pip và setup.py từ hộp cát, chẳng hạn như các hộp được tạo bằng chương trình virtualenv. Điều này sẽ tránh cài đặt các gói python bên ngoài ngữ cảnh của môi trường phát triển dự án của bạn.


7
và bạn cũng có thể có .w / o -ebên trong requirements.txt. Phương pháp này chỉ ủy thác tất cả các yêu cầu setup.pyvà bạn không cần buộc bất kỳ ai vào chế độ có thể chỉnh sửa. Người dùng vẫn có thể làm pip install -e .nếu họ muốn.
stason

1
Thủ thuật thú vị với "-e." trong request.txt, nhưng điều đó không đánh bại mục đích của request.txt là thông số kỹ thuật hệ thống chính xác? Tại sao thậm chí có một trong trường hợp đó?
Ben Ogorek

Bạn có thể có các yêu cầu hệ thống chính xác bên trong setup.py. Đang có "." trong request.txt làm cho nó sử dụng setup.py trong thư mục hiện tại. Việc sử dụng -e .cũng sử dụng setup.py để tìm các phần phụ thuộc, nhưng liên kết thư mục hiện tại (tại chỗ, với một liên kết tượng trưng) trong thư mục cài đặt pip, thay vì lấy một bản sao - bạn -ethường chỉ sử dụng nếu đang phát triển gói. Với -e, các thay đổi đối với tệp gói python (* .py) của bạn sẽ có hiệu lực ngay lập tức trong môi trường pip của bạn, thay vì phải buộc cài đặt lại gói sau mỗi lần thay đổi.
init_js

@init_js là "thư mục hiện tại" có liên quan đến tệp yêu cầu hay CWD mà từ đó gọi là pip? Tức là nếu bạn làm, cd foo && pip install -r ./bar/requirements.txtnó sẽ tìm kiếm setup.py trong foo/barhay foo? Nếu cái sau, có cách nào để đạt được cái trước không?
Dan M.

pip -r REQkhông quan tâm đến thư mục chứa REQ. Bạn có thể ăn nó từ một fifo ngay cả khi bạn muốn: pip install -r <(echo "mylib1"; echo "mylib2";). Đâu <(CMD)là thay thế lệnh bash, không phải chuyển hướng stdin.
init_js

12

Để đầy đủ, đây là cách tôi nhìn nhận nó ở 3 4 góc độ khác nhau.

  1. Mục đích thiết kế của chúng khác nhau

Đây là mô tả chính xác được trích dẫn từ tài liệu chính thức (tôi nhấn mạnh):

Trong khi install_requires (trong setup.py) xác định các phần phụ thuộc cho một dự án đơn lẻ , các Tệp Yêu cầu thường được sử dụng để xác định các yêu cầu cho một môi trường Python hoàn chỉnh .

Trong khi các yêu cầu install_requires là tối thiểu, các tệp yêu cầu thường chứa danh sách đầy đủ các phiên bản được ghim nhằm mục đích đạt được các bản cài đặt lặp lại của một môi trường hoàn chỉnh.

Nhưng nó vẫn có thể không dễ hiểu, vì vậy trong phần tiếp theo, có 2 ví dụ thực tế để chứng minh 2 cách tiếp cận được cho là được sử dụng, khác nhau như thế nào.

  1. Do đó, cách sử dụng thực tế của họ (được cho là) ​​khác nhau

    • Nếu dự án của bạn foosẽ được phát hành dưới dạng một thư viện độc lập (có nghĩa là những người khác có thể sẽ làm như vậy import foo), thì bạn (và những người dùng phía dưới của bạn) sẽ muốn có một khai báo phụ thuộc linh hoạt, để thư viện của bạn sẽ không (và nó không phải ) hãy "kén chọn" về phiên bản chính xác của sự phụ thuộc của BẠN. Vì vậy, thông thường, setup.py của bạn sẽ chứa các dòng như sau:

      install_requires=[
          'A>=1,<2',
          'B>=2'
      ]
    • Nếu bạn chỉ muốn bằng cách nào đó "tài liệu" hoặc "ghim" môi trường hiện tại CHÍNH XÁC cho ứng dụng của bạn bar, nghĩa là, bạn hoặc người dùng của bạn muốn sử dụng ứng dụng của bạn barnhư hiện tại, tức là đang chạy python bar.py, bạn có thể muốn đóng băng môi trường của mình để nó sẽ luôn luôn cư xử giống nhau. Trong trường hợp đó, tệp yêu cầu của bạn sẽ giống như sau:

      A==1.2.3
      B==2.3.4
      # It could even contain some dependencies NOT strickly required by your library
      pylint==3.4.5
  2. Trong thực tế, tôi sử dụng cái nào?

    • Nếu bạn đang phát triển một ứng dụng barsẽ được sử dụng bởi python bar.py, ngay cả khi đó là "chỉ là tập lệnh cho vui", bạn vẫn được khuyến nghị sử dụng tệp tests.txt bởi vì, ai mà biết được, tuần tới (sắp tới là Giáng sinh) bạn sẽ nhận được một máy tính mới như một món quà, vì vậy bạn sẽ cần thiết lập lại môi trường chính xác của mình ở đó.

    • Nếu bạn đang phát triển một thư viện foosẽ được sử dụng bởi import foo, bạn phải chuẩn bị setup.py. Giai đoạn = Stage. Nhưng bạn vẫn có thể chọn cung cấp cùng lúc một tệp tin request.txt, có thể:

      (a) A==1.2.3theo kiểu (như đã giải thích trong # 2 ở trên);

      (b) hoặc chỉ chứa một đĩa đơn kỳ diệu .

      .

      gần bằng "cài đặt các yêu cầu dựa trên setup.py" trong khi không có sự trùng lặp. Cá nhân tôi coi cách tiếp cận cuối cùng này làm mờ dòng, thêm vào sự nhầm lẫn và KHÔNG thực sự làm tăng giá trị, nhưng nó vẫn là một thủ thuật bắt nguồn từ cách tiếp cận được đề cập bởi nhà bảo trì bao bì Python Donald trong bài đăng trên blog của mình .

  3. Giới hạn thấp hơn khác nhau.

    Ngay cả sau khi bạn đã tuân theo 3 tiêu chí trên và quyết định chính xác rằng thư viện của bạn hybrid-enginesẽ sử dụng a setup.pyđể khai báo sự phụ thuộc của nó engine>=1.2.0và ứng dụng mẫu của bạn reliable-carsẽ sử dụng requirements.txtđể khai báo sự phụ thuộc của nó engine>=1.2.3, mặc dù phiên bản mới nhất của engineđã là 1.4.0. Như bạn thấy, sự lựa chọn của bạn cho số giới hạn dưới của chúng vẫn khác nhau một cách tinh tế. Và đây là lý do tại sao.

    • hybrid-enginephụ thuộc vào engine>=1.2.0bởi vì, theo giả thuyết, khả năng "đốt trong" cần thiết được đưa vào lần đầu tiên engine 1.2.0và khả năng đó là cần thiết hybrid-engine, bất kể có thể có một số lỗi (nhỏ) bên trong phiên bản đó và đã được sửa trong các phiên bản 1.2.1 tiếp theo hay không , 1.2.2 và 1.2.3.

    • reliable-carphụ thuộc vào engine>=1.2.3bởi vì đó là phiên bản sớm nhất KHÔNG có vấn đề được biết đến, cho đến nay. Chắc chắn có những khả năng mới trong các phiên bản sau, chẳng hạn như "động cơ điện" được đưa vào engine 1.3.0và "lò phản ứng hạt nhân" được đưa vào engine 1.4.0, nhưng chúng không cần thiết cho dự án reliable-car.


"thư viện của bạn sẽ không (và nó không được) 'kén chọn' về phiên bản chính xác của các phần phụ thuộc CỦA BẠN." Bạn có thể nói rõ hơn về điểm này một chút không? Tôi đoán mã của bạn thường chỉ được kiểm tra với các phiên bản phụ thuộc cụ thể và cách tiếp cận này có thể hơi nguy hiểm. Tôi giả sử một thư viện nên hoạt động với nhiều phiên bản vì bạn không muốn cài đặt quá nhiều phiên bản phụ thuộc? Để tiết kiệm dung lượng ổ đĩa?
Taro Kiritani

@TaroKiritani Thực ra tôi đã liệt kê 2 trường hợp khác nhau song song, trường hợp thư viện và trường hợp ứng dụng. Có lẽ bạn đã không làm việc trên một thư viện trước đây? Là một thư viện, nó sẽ được sử dụng bởi các gói hạ lưu. Vì vậy, nếu bạn kén chọn sự phụ thuộc của BẠN A==1.2.3, và sau đó nếu gói hạ lưu của thư viện của bạn tình cờ phụ thuộc vào A==1.2.4, thì bây giờ sẽ không có cách nào để đáp ứng cả hai. Giải pháp để giảm thiểu xung đột này là thư viện của bạn xác định một phạm vi mà bạn biết sẽ hoạt động. Giả sử nhiều thư viện ngược dòng đã theo sau semver.org , A>=1,<2sẽ hoạt động.
RayLuo

Tôi không nhận ra rằng chỉ có thể cài đặt một phiên bản của gói trong một môi trường duy nhất. stackoverflow.com/a/6572017/5686692 Cảm ơn bạn đã làm rõ.
Taro Kiritani

1
@TaroKiritani, vâng, nếu không thì làm sao ứng dụng của bạn biết được phiên bản foonào import foocung cấp cho bạn? Những câu trả lời được chấp nhận hacky trong liên kết mà bạn cung cấp là một ví dụ hoàn hảo về lý do tại sao người bảo trì gói "không nên và không được kén chọn". :-) Bây giờ tôi có thể nhận được ủng hộ của bạn không?
RayLuo

1
Tôi cũng có thể bình luận về suy nghĩ mới đó nhưng sau đó phần bình luận này đã lạc đề và khó cho những người mới đến theo dõi. Tôi sẽ đề nghị bạn đặt một câu hỏi mới "Chúng ta sẽ sử dụng tox hoặc một cái gì đó để đảm bảo công trình thư viện của tôi trên các kết hợp khác nhau phụ thuộc", và sau đó mọi người có thể kêu vang trong.
RayLuo
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.