Requirement.txt เทียบกับ setup.py


120

ฉันเริ่มทำงานกับ Python ฉันได้เพิ่มrequirements.txtและsetup.pyในโครงการของฉันแล้ว แต่ฉันยังคงสับสนเกี่ยวกับวัตถุประสงค์ของทั้งสองไฟล์ ฉันได้อ่านข้อมูลที่setup.pyออกแบบมาสำหรับสิ่งของที่แจกจ่ายต่อได้และrequirements.txtออกแบบมาสำหรับสิ่งที่แจกจ่ายต่อไม่ได้ แต่ฉันไม่แน่ใจว่านี่ถูกต้อง

ไฟล์ทั้งสองนี้มีจุดประสงค์เพื่อใช้งานอย่างไร?


1
คุณได้ค้นหาเว็บโดยใช้ชื่อเรื่องของคุณหรือไม่? บทความนี้ (Hit แรกเมื่อฉันค้นหา) เป็นบทความที่ดีที่สุดที่ฉันเคยอ่านในหัวข้อนี้
คริส

2
บทความนี้อาจเป็นประโยชน์: caremad.io/posts/2013/07/setup-vs-requirement (ขออภัยขี้เกียจเกินไปที่จะแยกข้อมูลสำคัญออกเป็นคำตอบที่เหมาะสม) อีกประการหนึ่งคือเครื่องมือบางอย่าง (เช่นการทดสอบ) อาจมีอคติต่อสิ่งใดสิ่งหนึ่ง แต่อย่าปล่อยให้มันรบกวนคุณหากคุณเพิ่งเริ่มทำงานกับ Python
drdaeman

คำตอบ:


92

requirements.txt:

สิ่งนี้ช่วยคุณในการตั้งค่าสภาพแวดล้อมการพัฒนาของคุณ

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

pip install -r requirements.txt

setup.py:

สิ่งนี้ช่วยให้คุณสร้างแพ็คเกจที่คุณสามารถแจกจ่ายต่อได้

setup.pyสคริปต์จะหมายถึงการติดตั้งแพคเกจในระบบของผู้ใช้ที่ไม่ได้เตรียมความพร้อมในการพัฒนาสภาพแวดล้อมที่เป็นpip install -r requirements.txtไม่ ดูคำตอบนี้สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับsetup.pyสำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ


การอ้างอิงของโปรเจ็กต์ของคุณแสดงอยู่ในทั้งสองไฟล์


2
ในกรณีใดบ้างที่ฉันจะมีเพียงหนึ่งในนั้น ฉันจะมีทั้งสองอย่าง
Martin Thoma

31
เอิ่ม ... คุณแค่เขียนสคริปต์เพื่อความสนุกบนเครื่องของคุณ: ไม่ สคริปต์ได้รับการพัฒนาบนเครื่อง / vitualenvs หลายเครื่อง แต่ไม่แจกจ่ายซ้ำ: requirements.txt สคริปต์ได้รับการพัฒนาในเครื่องของคุณเท่านั้น แต่ควรแจกจ่ายใหม่: setup.py สคริปต์จะถูกแจกจ่ายและพัฒนาในหลายสภาพแวดล้อม: ทั้งสองอย่าง
AndreasT

คุณช่วยเพิ่มคำตอบนี้ได้ไหม
Martin Thoma

คุณเคยจริงๆมีsetup.pyโดยไม่requirements.txt? ขอให้เพื่อนที่ไม่เข้าใจสิ่งนี้โดยสิ้นเชิง
eric

61

คำตอบสั้น ๆrequirements.txtคือใช้สำหรับแสดงรายการข้อกำหนดของแพ็คเกจเท่านั้น setup.pyในทางกลับกันก็เหมือนกับสคริปต์การติดตั้ง หากคุณไม่ได้วางแผนที่จะติดตั้งรหัส python โดยทั่วไปคุณจะต้องใช้เพียงrequirements.txtหากคุณไม่ได้วางแผนในการติดตั้งรหัสหลามโดยทั่วไปแล้วคุณจะต้องการเพียง

ไฟล์ setup.pyอธิบายนอกเหนือจากการขึ้นต่อกันของแพ็กเกจชุดของไฟล์และโมดูลที่ควรแพ็กเกจ (หรือคอมไพล์ในกรณีของโมดูลเนทีฟ (เช่นเขียนด้วย C)) และข้อมูลเมตาที่จะเพิ่มลงในรายการแพ็คเกจ python ( เช่นชื่อแพ็กเกจเวอร์ชันแพ็กเกจคำอธิบายแพ็คเกจผู้เขียน ... )

เนื่องจากไฟล์ทั้งสองแสดงรายการการอ้างอิงจึงอาจนำไปสู่การทำซ้ำเล็กน้อย อ่านรายละเอียดด้านล่าง

Requirement.txt


ไฟล์นี้แสดงข้อกำหนดแพคเกจ python เป็นไฟล์ข้อความธรรมดา (เป็นทางเลือกพร้อมกับความคิดเห็น) ที่แสดงรายการการอ้างอิงแพ็กเกจของโครงการ python ของคุณ (หนึ่งรายการต่อบรรทัด) มันไม่ได้อธิบายวิธีการที่แพคเกจหลามของคุณมีการติดตั้ง โดยทั่วไปคุณจะใช้ไฟล์ข้อกำหนดด้วยไฟล์pip install -r requirements.txt.

ชื่อไฟล์ของไฟล์ข้อความเป็นไปตามอำเภอใจ แต่มักจะเป็นไปrequirements.txtตามแบบแผน เมื่อสำรวจเก็บซอร์สโค้ดของแพคเกจหลามอื่น ๆ ที่คุณอาจจะสะดุดกับชื่ออื่น ๆ เช่นหรือdev-dependencies.txt dependencies-dev.txtสิ่งเหล่านี้มีจุดประสงค์เดียวกับdependencies.txtแต่โดยทั่วไปจะแสดงรายการอ้างอิงเพิ่มเติมที่น่าสนใจสำหรับนักพัฒนาของแพ็คเกจเฉพาะกล่าวคือสำหรับการทดสอบซอร์สโค้ด (เช่น pytest, pylint ฯลฯ ) ก่อนวางจำหน่าย โดยทั่วไปแล้วผู้ใช้แพ็กเกจจะไม่ต้องการการอ้างอิงของนักพัฒนาทั้งชุดเพื่อเรียกใช้แพ็กเกจ

หากมีrequirements-X.txtตัวแปรหลายตัวโดยปกติแล้วตัวแปรหนึ่งจะแสดงรายการการอ้างอิงรันไทม์และเวลาสร้างหรือทดสอบการอ้างอิงอื่น ๆ บางโปรเจ็กต์ยังจัดเรียงไฟล์ข้อกำหนดไว้ด้วยเช่นเมื่อไฟล์ข้อกำหนดหนึ่งไฟล์มีไฟล์อื่น ( ตัวอย่าง ) การทำเช่นนี้สามารถลดการทำซ้ำได้

setup.py


นี่คือสคริปต์ python ที่ใช้setuptoolsโมดูลเพื่อกำหนดแพ็คเกจ python (ชื่อไฟล์ที่รวมข้อมูลเมตาของแพ็กเกจและการติดตั้ง) มันจะrequirements.txtแสดงรายการการอ้างอิงรันไทม์ของแพ็คเกจด้วยเช่นกัน Setuptools เป็นวิธีการสร้างและติดตั้งแพคเกจ python โดยพฤตินัย แต่มีข้อบกพร่องซึ่งเมื่อเวลาผ่านไปได้ขยายการพัฒนา "meta-package manager" ใหม่เช่น pip ตัวอย่างข้อบกพร่องของ setuptools คือไม่สามารถติดตั้งแพ็กเกจเดียวกันหลายเวอร์ชันและไม่มีคำสั่งถอนการติดตั้ง

เมื่อผู้ใช้ python ทำpip install ./pkgdir_my_module(หรือpip install my-module) pip จะทำงานsetup.pyในไดเร็กทอรี (หรือโมดูล) ที่กำหนด ในทำนองเดียวกันโมดูลใด ๆ ที่setup.pyสามารถpipติดตั้งได้เช่นโดยเรียกใช้pip install .จากโฟลเดอร์เดียวกัน

ฉันต้องการทั้งสองอย่างจริงๆหรือ


คำตอบสั้น ๆ คือไม่ แต่เป็นเรื่องดีที่มีทั้งสองอย่าง พวกเขาบรรลุวัตถุประสงค์ที่แตกต่างกัน แต่สามารถใช้ทั้งสองเพื่อแสดงรายการการอ้างอิงของคุณ

มีอยู่คนหนึ่งเคล็ดลับที่คุณอาจพิจารณาที่จะหลีกเลี่ยงการทำซ้ำรายชื่อของการพึ่งพาระหว่างเป็นและrequirements.txt setup.pyหากคุณได้เขียนsetup.pyแพคเกจที่ใช้งานได้อย่างสมบูรณ์แล้วและการอ้างอิงของคุณส่วนใหญ่เป็นภายนอกคุณสามารถพิจารณาง่ายๆrequirements.txtโดยมีเพียงสิ่งต่อไปนี้:

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

-eเป็นพิเศษpip installตัวเลือกที่ติดตั้งแพคเกจที่กำหนดในการแก้ไขโหมด เมื่อpip -r requirements.txtเรียกใช้ไฟล์นี้ pip จะติดตั้งการอ้างอิงของคุณผ่านทางรายการใน./setup.py. ตัวเลือกที่แก้ไขได้จะวาง symlink ในไดเร็กทอรีการติดตั้งของคุณ (แทนที่จะเป็น egg หรือสำเนาที่เก็บถาวร) ช่วยให้นักพัฒนาสามารถแก้ไขโค้ดจากที่เก็บได้โดยไม่ต้องติดตั้งใหม่

คุณยังสามารถใช้ประโยชน์จากสิ่งที่เรียกว่า "setuptools extras" เมื่อคุณมีทั้งสองไฟล์ในที่เก็บแพ็กเกจของคุณ คุณสามารถกำหนดแพ็คเกจเสริมใน setup.py ภายใต้หมวดหมู่ที่กำหนดเองและติดตั้งแพ็คเกจเหล่านั้นจากหมวดหมู่นั้นด้วย pip:

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

จากนั้นในไฟล์ข้อกำหนด:

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

สิ่งนี้จะเก็บรายการอ้างอิงทั้งหมดของคุณไว้ใน setup.py

หมายเหตุ : คุณตามปกติจะดำเนินการ pip และ setup.py จาก Sandbox virtualenvเช่นผู้ที่สร้างขึ้นด้วยโปรแกรม วิธีนี้จะหลีกเลี่ยงการติดตั้งแพ็คเกจ python นอกบริบทของสภาพแวดล้อมการพัฒนาโครงการของคุณ


7
และคุณยังสามารถมีเพียง.w / o ภายใน-e requirements.txtวิธีนี้เป็นเพียงการมอบหมายข้อกำหนดทั้งหมดให้setup.pyและคุณไม่จำเป็นต้องบังคับให้ใครเข้าสู่โหมดแก้ไขได้ ผู้ใช้ยังสามารถทำได้pip install -e .หากต้องการ
stason

1
เคล็ดลับที่น่าสนใจกับ "-e." ใน Requirement.txt แต่นั่นไม่ทำให้บรรลุวัตถุประสงค์ของข้อกำหนดที่เป็นข้อกำหนดของระบบที่แน่นอนหรือไม่? ทำไมถึงมีหนึ่งในนั้น?
Ben Ogorek

คุณสามารถมีข้อกำหนดของระบบที่แน่นอนใน setup.py มี "." ใน requirements.txt ทำให้ใช้ setup.py ในโฟลเดอร์ปัจจุบัน การใช้-e .ยังใช้ setup.py เพื่อค้นหาการอ้างอิง แต่เชื่อมโยงโฟลเดอร์ปัจจุบัน (ในตำแหน่งที่มี symlink) ในโฟลเดอร์ pip install แทนที่จะถ่ายสำเนา - -eโดยทั่วไปคุณจะใช้เฉพาะในกรณีที่คุณกำลังพัฒนาแพ็คเกจ ด้วย-eการเปลี่ยนแปลงไฟล์แพคเกจ python (* .py) ของคุณจะมีผลทันทีในสภาพแวดล้อม pip ของคุณแทนที่จะต้องบังคับให้ติดตั้งแพ็กเกจใหม่หลังจากการเปลี่ยนแปลงแต่ละครั้ง
init_js

@init_js เป็น "โฟลเดอร์ปัจจุบัน" ที่สัมพันธ์กับไฟล์ข้อกำหนดหรือ CWD ที่เรียกว่า pip? เช่นถ้าคุณcd foo && pip install -r ./bar/requirements.txtจะค้นหา setup.py ในfoo/barหรือfoo? ถ้าอย่างหลังมีวิธีบรรลุอดีตหรือไม่?
Dan M.

pip -r REQไม่สนใจไดเร็กทอรีที่ REQ อยู่ คุณสามารถให้อาหารได้จาก FIFO pip install -r <(echo "mylib1"; echo "mylib2";)แม้ว่าคุณต้องการ: การ<(CMD)แทนที่คำสั่ง bash อยู่ที่ไหนไม่ใช่การเปลี่ยนเส้นทาง stdin
init_js

14

เพื่อความสมบูรณ์นี่คือวิธีที่ฉันเห็นใน3 4 มุมที่แตกต่างกัน

  1. วัตถุประสงค์ในการออกแบบของพวกเขาแตกต่างกัน

นี่คือคำอธิบายที่ชัดเจนที่อ้างจากเอกสารอย่างเป็นทางการ (เน้นของฉัน):

ขณะ install_requires (ใน setup.py) กำหนดอ้างอิงสำหรับโครงการเดียวไฟล์ที่ต้องการมักจะใช้ในการกำหนดความต้องการสำหรับสภาพแวดล้อมที่สมบูรณ์หลาม

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

แต่อาจยังเข้าใจได้ไม่ยากดังนั้นในหัวข้อถัดไปจึงมีตัวอย่างข้อเท็จจริง 2 ตัวอย่างเพื่อแสดงให้เห็นว่าควรใช้ 2 วิธีนี้แตกต่างกันอย่างไร

  1. การใช้งานที่แท้จริงของพวกเขาจึง (ควรจะ) แตกต่างกัน

    • หากโปรเจ็กต์ของคุณfooกำลังจะออกเป็นไลบรารีแบบสแตนด์อโลน (หมายถึงคนอื่น ๆ ก็น่าจะทำimport foo) คุณ (และผู้ใช้ปลายน้ำของคุณ) จะต้องมีการประกาศการพึ่งพาที่ยืดหยุ่นเพื่อที่ห้องสมุดของคุณจะไม่ (และต้องไม่ ) เป็น "จู้จี้จุกจิก" เกี่ยวกับเวอร์ชันที่แน่นอนของการอ้างอิงของคุณ ดังนั้นโดยทั่วไปแล้ว setup.py ของคุณจะมีบรรทัดดังนี้:

      install_requires=[
          'A>=1,<2',
          'B>=2'
      ]
      
    • หากคุณต้องการเพียงแค่ "เอกสาร" หรือ "ตรึง" สภาพแวดล้อมปัจจุบันที่แน่นอนของคุณสำหรับแอปพลิเคชันของคุณbarหมายความว่าคุณหรือผู้ใช้ของคุณต้องการใช้แอปพลิเคชันของคุณbarตามที่เป็นอยู่นั่นคือกำลังทำงานอยู่python bar.pyคุณอาจต้องการหยุดสภาพแวดล้อมของคุณเพื่อให้ มักจะทำตัวเหมือนเดิม ในกรณีนี้ไฟล์ข้อกำหนดของคุณจะมีลักษณะดังนี้:

      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. ในความเป็นจริงฉันจะใช้อันไหน?

    • หากคุณกำลังพัฒนาแอปพลิเคชันbarที่จะใช้งานpython bar.pyแม้ว่าจะเป็น "สคริปต์เพื่อความสนุก" แต่คุณยังคงแนะนำให้ใช้ requirements.txt เพราะใครจะรู้สัปดาห์หน้า (ซึ่งเป็นวันคริสต์มาส) คุณจะได้รับ คอมพิวเตอร์เครื่องใหม่เป็นของขวัญดังนั้นคุณจะต้องตั้งค่าสภาพแวดล้อมที่แน่นอนอีกครั้ง

    • หากคุณกำลังพัฒนาไลบรารีfooที่จะใช้โดยimport fooคุณต้องเตรียม setup.py ระยะเวลา แต่คุณอาจยังคงเลือกที่จะระบุ requirements.txt ในเวลาเดียวกันซึ่งสามารถ:

      (ก) อยู่ในA==1.2.3รูปแบบ (ตามที่อธิบายไว้ใน # 2 ด้านบน)

      (b) หรือมีเพียงเพลงมหัศจรรย์ .

      .
      

      ซึ่งจะเท่ากับ "ติดตั้งข้อกำหนดตาม setup.py" โดยประมาณในขณะที่ไม่มีการทำซ้ำ โดยส่วนตัวแล้วฉันคิดว่าวิธีสุดท้ายนี้ทำให้เส้นเบลอเพิ่มความสับสนและไม่ได้เพิ่มมูลค่า แต่กระนั้นก็เป็นกลอุบายที่ได้มาจากแนวทางที่กล่าวถึงโดยผู้ดูแลบรรจุภัณฑ์ Python Donald ในบล็อกโพสต์ของเขา

  3. ขอบเขตล่างที่แตกต่างกัน

    แม้ว่าคุณจะปฏิบัติตาม 3 เกณฑ์ข้างต้นและตัดสินใจถูกต้องแล้วว่าห้องสมุดของคุณhybrid-engineจะใช้ a setup.pyเพื่อประกาศการพึ่งพาengine>=1.2.0และแอปพลิเคชันตัวอย่างของคุณreliable-carจะใช้requirements.txtเพื่อประกาศการพึ่งพาengine>=1.2.3แม้ว่าเวอร์ชันล่าสุดengineจะอยู่ที่ 1.4.0 แล้วก็ตาม ดังที่คุณเห็นตัวเลือกของคุณสำหรับหมายเลขขอบเขตล่างของพวกเขายังคงแตกต่างกันเล็กน้อย และนี่คือเหตุผล

    • hybrid-engineขึ้นอยู่กับengine>=1.2.0ว่าในแง่สมมุติความสามารถ "การเผาไหม้ภายใน" ที่จำเป็นถูกนำมาใช้เป็นครั้งแรกengine 1.2.0และความสามารถนั้นเป็นสิ่งจำเป็นhybrid-engineโดยไม่คำนึงว่าอาจมีข้อบกพร่องบางอย่าง (เล็กน้อย) ในเวอร์ชันดังกล่าวหรือไม่และได้รับการแก้ไขในเวอร์ชันต่อ ๆ ไป 1.2.1 , 1.2.2 และ 1.2.3

    • reliable-carขึ้นอยู่กับengine>=1.2.3ว่าเป็นรุ่นแรกสุดโดยไม่มีปัญหาที่ทราบจนถึงตอนนี้ ตรวจสอบว่ามีความสามารถใหม่ในรุ่นต่อมาพูดว่า "มอเตอร์ไฟฟ้า" แนะนำในengine 1.3.0และ "เครื่องปฏิกรณ์นิวเคลียร์" นำมาใช้ในแต่พวกเขาไม่ได้เป็นสิ่งที่จำเป็นสำหรับโครงการengine 1.4.0reliable-car


"ห้องสมุดของคุณจะไม่ (และต้องไม่)" จู้จี้จุกจิก "เกี่ยวกับเวอร์ชันที่แน่นอนของการอ้างอิงของคุณ" คุณช่วยอธิบายเพิ่มเติมเกี่ยวกับประเด็นนี้สักหน่อยได้ไหม ฉันเดาว่าโดยทั่วไปโค้ดของคุณจะได้รับการทดสอบด้วยการอ้างอิงเฉพาะบางเวอร์ชันและวิธีนี้อาจเป็นอันตรายได้เล็กน้อย ฉันคิดว่าไลบรารีควรทำงานร่วมกับเวอร์ชันต่างๆได้เนื่องจากคุณไม่ต้องการติดตั้งการอ้างอิงหลายเวอร์ชันเกินไป? เพื่อประหยัดเนื้อที่ดิสก์?
Taro Kiritani

@TaroKiritani อันที่จริงฉันระบุ 2 สถานการณ์ที่แตกต่างกันแบบเคียงข้างกันเคสไลบรารีและเคสแอปพลิเคชัน บางทีคุณอาจไม่เคยทำงานกับห้องสมุดมาก่อน? ในฐานะห้องสมุดคาดว่าจะถูกใช้โดยแพ็คเกจดาวน์สตรีม ดังนั้นหากคุณจู้จี้จุกจิกที่จะปักหมุดการพึ่งพาของคุณA==1.2.3และหากแพ็กเกจดาวน์สตรีมของห้องสมุดของคุณขึ้นอยู่กับA==1.2.4ตอนนี้ก็จะไม่มีวิธีใดที่จะทำให้ทั้งสองพอใจ วิธีแก้ปัญหาเพื่อลดความขัดแย้งนี้คือไลบรารีของคุณกำหนดช่วงที่คุณรู้ว่าน่าจะใช้ได้ สมมติว่าไลบรารีต้นน้ำจำนวนมากติดตามsemver.orgแล้วA>=1,<2จะใช้งานได้
RayLuo

ฉันไม่ทราบว่าสามารถติดตั้งแพ็คเกจได้เพียงเวอร์ชันเดียวในสภาพแวดล้อมเดียว stackoverflow.com/a/6572017/5686692ขอบคุณสำหรับคำชี้แจง
Taro Kiritani

1
@TaroKiritani ใช่แล้วแอปของคุณจะรู้ได้อย่างไรว่ารุ่นfooใดimport fooให้คุณ คำตอบที่แฮกเกอร์ยอมรับในลิงก์นั้นถือเป็นตัวอย่างที่สมบูรณ์แบบว่าเหตุใดผู้ดูแลแพ็กเกจจึง "ไม่ควรและต้องไม่จู้จี้จุกจิก" :-) ตอนนี้ฉันขอโหวตเพิ่มได้ไหม
RayLuo

1
ฉันยังสามารถแสดงความคิดเห็นเกี่ยวกับความคิดใหม่นั้นได้ แต่ส่วนความคิดเห็นนี้ก็ไม่อยู่ในหัวข้อและยากสำหรับผู้มาใหม่ที่จะติดตาม ฉันขอแนะนำให้คุณถามคำถามใหม่ "เราจะใช้สารพิษหรืออะไรบางอย่างเพื่อรับประกันว่าห้องสมุดของฉันจะทำงานโดยใช้ชุดค่าผสมต่างๆของการอ้างอิง" จากนั้นผู้คนก็สามารถ
ส่งเสียงเข้ามาได้
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.