requirement.txt vs setup.py

112

Saya mulai bekerja dengan Python. Saya telah menambahkan requirements.txtdan setup.pyke proyek saya. Tapi, saya masih bingung dengan tujuan kedua file tersebut. Saya telah membaca yang setup.pydirancang untuk hal-hal yang dapat didistribusikan ulang dan yang requirements.txtdirancang untuk hal-hal yang tidak dapat didistribusikan ulang. Tapi saya tidak yakin ini akurat.

Bagaimana kedua file itu benar-benar dimaksudkan untuk digunakan?

lucy
sumber
1
Sudahkah Anda menelusuri web menggunakan judul persis Anda? Artikel ini (hit pertama ketika saya mencari) adalah yang terbaik yang pernah saya baca tentang subjek ini.
Chris
2
Artikel ini mungkin berguna: caremad.io/posts/2013/07/setup-vs-requirement (maaf, terlalu malas untuk mengekstrak hal-hal penting menjadi jawaban yang tepat). Hal lainnya adalah, beberapa alat (misalnya pengujian) mungkin memiliki bias terhadap satu atau lainnya - tetapi jangan biarkan hal itu mengganggu Anda jika Anda baru saja mulai mengerjakan Python.
drdaeman

Jawaban:

84

persyaratan.txt

Ini membantu Anda menyiapkan lingkungan pengembangan Anda. Program seperti pipini dapat digunakan untuk menginstal semua paket yang terdaftar di file dalam satu gerakan. Setelah itu Anda bisa mulai mengembangkan script python Anda. Sangat berguna jika Anda berencana meminta orang lain berkontribusi pada pengembangan atau menggunakan lingkungan virtual. Inilah cara Anda menggunakannya:

pip install -r requirements.txt

setup.py

Ini memungkinkan Anda membuat paket yang dapat didistribusikan ulang. Skrip ini dimaksudkan untuk menginstal paket Anda pada sistem pengguna akhir, bukan untuk mempersiapkan lingkungan pengembangan seperti pip install -r requirements.txthalnya. Lihat jawaban ini untuk detail lebih lanjut tentang setup.py.

Dependensi proyek Anda dicantumkan di kedua file.

AndreasT
sumber
2
Dalam kasus apa saya hanya memiliki satu dari mereka? Di manakah saya akan memiliki keduanya?
Martin Thoma
29
Erm ... Anda hanya membuat naskah untuk bersenang-senang di komputer lokal Anda: Tidak keduanya. Skrip dikembangkan di beberapa mesin / vitualenvs tetapi tidak didistribusikan ulang: Requirement.txt. Skrip dikembangkan hanya di mesin Anda tetapi harus didistribusikan ulang: setup.py. Script akan didistribusikan ulang dan dikembangkan di berbagai lingkungan: Keduanya.
AndreasT
Bisakah Anda menambahkan ini ke jawabannya?
Martin Thoma
58

Jawaban singkatnya requirements.txtadalah untuk mencantumkan persyaratan paket saja. setup.pydi sisi lain lebih seperti skrip instalasi. Jika Anda tidak berencana memasang kode python, biasanya Anda hanya perlu requirements.txt.

File tersebut setup.pymenjelaskan, selain dependensi paket, kumpulan file dan modul yang harus dikemas (atau dikompilasi, dalam kasus modul asli (yaitu, ditulis dalam C)), dan metadata untuk ditambahkan ke daftar paket python ( misalnya nama paket, versi paket, deskripsi paket, pembuat, ...).

Karena kedua file mencantumkan dependensi, ini dapat menyebabkan sedikit duplikasi. Baca detailnya di bawah.

persyaratan.txt


File ini mencantumkan persyaratan paket python. Ini adalah file teks biasa (opsional dengan komentar) yang mencantumkan dependensi paket proyek python Anda (satu per baris). Ini tidak menjelaskan cara paket python Anda diinstal. Anda biasanya akan menggunakan file persyaratan dengan pip install -r requirements.txt.

Nama file dari file teks tersebut sewenang-wenang, tetapi sering kali requirements.txtberdasarkan konvensi. Saat menjelajahi repositori kode sumber dari paket python lainnya, Anda mungkin tersandung pada nama lain, seperti dev-dependencies.txtatau dependencies-dev.txt. Mereka melayani tujuan yang sama dependencies.txttetapi umumnya mencantumkan dependensi tambahan yang menarik bagi pengembang paket tertentu, yaitu untuk menguji kode sumber (misalnya pytest, pylint, dll.) Sebelum rilis. Pengguna paket umumnya tidak memerlukan seluruh rangkaian dependensi developer untuk menjalankan paket.

Jika ada beberapa requirements-X.txtvarian, biasanya salah satu akan mencantumkan dependensi waktu proses, dan yang lainnya akan mencantumkan dependensi waktu proses, atau menguji dependensi. Beberapa proyek juga menurunkan file persyaratan mereka, yaitu ketika satu file persyaratan menyertakan file lain ( contoh ). Melakukannya dapat mengurangi pengulangan.

setup.py


Ini adalah skrip python yang menggunakan setuptoolsmodul untuk mendefinisikan paket python (nama, file yang disertakan, metadata paket, dan instalasi). Ini akan, seperti requirements.txt, juga mencantumkan dependensi runtime dari paket tersebut. Setuptools adalah cara de-facto untuk membangun dan menginstal paket python, tetapi ia memiliki kekurangan, yang seiring waktu telah menumbuhkan pengembangan "manajer paket meta" baru, seperti pip. Contoh kekurangan dari setuptools adalah ketidakmampuannya untuk menginstal beberapa versi dari paket yang sama, dan kurangnya perintah uninstall.

Ketika pengguna python melakukan pip install ./pkgdir_my_module(atau pip install my-module), pip akan berjalan setup.pydi direktori (atau modul) yang diberikan. Demikian pula, modul apa pun yang memiliki a setup.pydapat pipdiinstal, misalnya dengan menjalankan pip install .dari folder yang sama.

Apakah saya benar-benar membutuhkan keduanya?


Jawaban singkatnya adalah tidak, tapi senang memiliki keduanya. Keduanya mencapai tujuan yang berbeda, tetapi keduanya dapat digunakan untuk membuat daftar dependensi Anda.

Ada satu trik yang dapat Anda pertimbangkan untuk menghindari duplikasi daftar dependensi antara requirements.txtdan setup.py. Jika Anda telah menulis sepenuhnya berfungsi setup.pyuntuk paket Anda, dan dependensi Anda sebagian besar eksternal, Anda dapat mempertimbangkan untuk memiliki yang sederhana requirements.txthanya dengan yang berikut:

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

Ini -eadalah pip installopsi khusus yang menginstal paket yang diberikan dalam mode yang dapat diedit . Ketika pip -r requirements.txtdijalankan pada file ini, pip akan menginstal dependensi Anda melalui daftar di ./setup.py. Opsi yang dapat diedit akan menempatkan symlink di direktori pemasangan Anda (bukan telur atau salinan yang diarsipkan). Ini memungkinkan pengembang untuk mengedit kode dari repositori tanpa menginstal ulang.

Anda juga dapat memanfaatkan apa yang disebut "tambahan setuptools" ketika Anda memiliki kedua file dalam repositori paket Anda. Anda dapat mendefinisikan paket opsional di setup.py di bawah kategori khusus, dan menginstal paket itu hanya dari kategori itu dengan pip:

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

dan kemudian, di file persyaratan:

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

Ini akan menyimpan semua daftar ketergantungan Anda di dalam setup.py.

Catatan : Anda biasanya akan menjalankan pip dan setup.py dari kotak pasir, seperti yang dibuat dengan program ini virtualenv. Ini akan menghindari pemasangan paket python di luar konteks lingkungan pengembangan proyek Anda.

init_js
sumber
7
dan Anda juga dapat memiliki hanya .w / o -edalam requirements.txt. Metode ini hanya mendelegasikan semua persyaratan ke setup.pydan Anda tidak perlu memaksa siapa pun ke mode yang dapat diedit. Pengguna tetap bisa melakukannya pip install -e .jika mereka mau.
stason
1
Trik menarik dengan "-e." di Requirement.txt, tetapi bukankah itu mengalahkan tujuan dari Requirement.txt sebagai spesifikasi sistem yang tepat? Kenapa harus punya satu dalam kasus itu?
Ben Ogorek
Anda dapat memiliki persyaratan sistem yang tepat di dalam setup.py. Memiliki "." di requirement.txt membuatnya menggunakan setup.py di folder saat ini. Menggunakan -e .juga menggunakan setup.py untuk menemukan dependensi, tetapi menautkan folder saat ini (di tempat, dengan symlink) di folder instalasi pip, daripada mengambil salinannya - Anda -ebiasanya hanya akan menggunakan jika Anda mengembangkan paket. Dengan -e, perubahan pada file paket python Anda (* .py) akan segera berlaku di lingkungan pip Anda, daripada harus menginstal ulang paket secara paksa setelah setiap perubahan.
init_js
@init_js adalah "folder saat ini" yang berhubungan dengan file persyaratan atau CWD dari mana pip dipanggil? Yaitu jika Anda melakukannya cd foo && pip install -r ./bar/requirements.txtakan mencari setup.py di foo/baratau foo? Jika yang terakhir, apakah ada cara untuk mencapai yang pertama?
Dan M.
pip -r REQtidak peduli dengan direktori tempat REQ berada. Anda dapat makan dari fifo bahkan jika Anda ingin: pip install -r <(echo "mylib1"; echo "mylib2";). Di mana <(CMD)substitusi perintah bash, bukan pengalihan stdin.
init_js
12

Demi kelengkapan, berikut adalah cara saya melihatnya dalam 3 4 sudut berbeda.

  1. Tujuan desain mereka berbeda

Ini adalah deskripsi tepat yang dikutip dari dokumentasi resmi (penekanan saya):

Sedangkan install_requires (di setup.py) mendefinisikan dependensi untuk satu proyek , File Persyaratan sering digunakan untuk menentukan persyaratan untuk lingkungan Python yang lengkap .

Meskipun persyaratan install_requires minimal, file persyaratan sering kali berisi daftar lengkap versi yang disematkan untuk tujuan mencapai instalasi berulang dari lingkungan yang lengkap.

Namun mungkin masih belum mudah untuk dipahami, sehingga pada bagian selanjutnya, terdapat 2 contoh faktual untuk menunjukkan bagaimana kedua pendekatan tersebut seharusnya digunakan secara berbeda.

  1. Oleh karena itu, penggunaan aktualnya (seharusnya) berbeda

    • Jika proyek Anda fooakan dirilis sebagai pustaka mandiri (artinya, orang lain mungkin akan melakukannya import foo), maka Anda (dan pengguna hilir Anda) ingin memiliki deklarasi ketergantungan yang fleksibel, sehingga pustaka Anda tidak akan (dan tidak boleh ) menjadi "pilih-pilih" tentang versi pasti dari dependensi ANDA yang seharusnya. Jadi, biasanya, setup.py Anda akan berisi baris seperti ini:

      install_requires=[
          'A>=1,<2',
          'B>=2'
      ]
    • Jika Anda hanya ingin entah bagaimana "mendokumentasikan" atau "menyematkan" lingkungan Anda saat ini PERSIS untuk aplikasi Anda bar, artinya, Anda atau pengguna Anda ingin menggunakan aplikasi Anda barapa adanya, yaitu berjalan python bar.py, Anda mungkin ingin membekukan lingkungan Anda sehingga akan selalu berperilaku sama. Jika demikian, file persyaratan Anda akan terlihat seperti ini:

      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. Sebenarnya, mana yang saya gunakan?

    • Jika Anda mengembangkan aplikasi baryang akan digunakan oleh python bar.py, meskipun itu "hanya skrip untuk bersenang-senang", Anda tetap disarankan untuk menggunakan persyaratan.txt karena, siapa tahu, minggu depan (yang kebetulan Natal) Anda akan menerima komputer baru sebagai hadiah, jadi Anda perlu mengatur lingkungan persis Anda di sana lagi.

    • Jika Anda mengembangkan pustaka fooyang akan digunakan oleh import foo, Anda harus menyiapkan a setup.py. Titik. Tetapi Anda tetap dapat memilih untuk memberikan persyaratan.txt pada saat yang sama, yang dapat:

      (a) bisa A==1.2.3bergaya (seperti dijelaskan di # 2 di atas);

      (b) atau hanya berisi single magis .

      .

      yang kira-kira sama dengan "menginstal persyaratan berdasarkan setup.py" sementara tanpa duplikasi. Secara pribadi saya menganggap pendekatan terakhir ini mengaburkan garis, menambah kebingungan dan TIDAK benar-benar menambah nilai, tetapi tetap saja ini adalah trik yang berasal dari pendekatan yang disebutkan oleh pengelola kemasan Python Donald dalam posting blognya .

  3. Batas bawah yang berbeda.

    Bahkan setelah Anda mengikuti 3 kriteria di atas dan memutuskan dengan benar bahwa library Anda hybrid-engineakan menggunakan a setup.pyuntuk mendeklarasikan dependensinya engine>=1.2.0, dan aplikasi sampel Anda reliable-carakan menggunakan requirements.txtuntuk mendeklarasikan dependensinya engine>=1.2.3, meskipun versi terbaru enginesudah di 1.4.0. Seperti yang Anda lihat, pilihan Anda untuk angka batas bawahnya masih sedikit berbeda. Dan inilah alasannya.

    • hybrid-enginebergantung pada engine>=1.2.0karena, secara hipotesis, kemampuan "pembakaran internal" yang dibutuhkan pertama kali diperkenalkan engine 1.2.0, dan kapabilitas itu adalah kebutuhan hybrid-engine, terlepas dari apakah mungkin ada beberapa bug (kecil) di dalam versi tersebut dan telah diperbaiki di versi 1.2.1 berikutnya , 1.2.2, dan 1.2.3.

    • reliable-cartergantung engine>=1.2.3karena itu adalah versi paling awal TANPA masalah yang diketahui, sejauh ini. Tentu ada kemampuan baru di versi yang lebih baru, katakanlah, "motor listrik" diperkenalkan engine 1.3.0, dan "reaktor nuklir" diperkenalkan engine 1.4.0, tetapi mereka tidak diperlukan untuk proyek reliable-car.

RayLuo
sumber
"perpustakaan Anda tidak akan (dan tidak boleh) 'pilih-pilih' tentang versi pasti dari dependensi ANDA yang seharusnya." Bisakah Anda menjelaskan hal ini sedikit? Saya kira kode Anda biasanya diuji hanya dengan versi dependensi tertentu, dan pendekatan ini bisa sedikit berbahaya. Saya berasumsi sebuah perpustakaan harus bekerja dengan berbagai versi karena Anda tidak ingin menginstal terlalu banyak versi dependensi? Untuk menghemat ruang disk?
Taro Kiritani
@TaroKiritani Sebenarnya saya membuat daftar 2 skenario berbeda secara berdampingan, kasus perpustakaan dan kasus aplikasi. Mungkin Anda tidak pernah bekerja di perpustakaan sebelumnya? Sebagai pustaka, diharapkan dapat dikonsumsi oleh paket hilir. Jadi, jika Anda pilih-pilih untuk menyematkan dependensi ANDA A==1.2.3, lalu jika paket downstream library Anda kebetulan bergantung A==1.2.4, sekarang tidak akan ada cara untuk memenuhi keduanya. Solusi untuk meminimalkan konflik ini adalah perpustakaan Anda menentukan rentang yang Anda tahu akan berfungsi. Dengan asumsi banyak pustaka upstream sudah mengikuti semver.org , A>=1,<2akan berhasil.
RayLuo
Saya tidak menyadari bahwa hanya satu versi paket yang dapat diinstal dalam satu lingkungan. stackoverflow.com/a/6572017/5686692 Terima kasih atas klarifikasinya.
Taro Kiritani
1
@TaroKiritani, ya, kalau tidak bagaimana aplikasi know Anda versi footidak import foomemberikan? Jawaban hacky yang diterima di link yang Anda berikan berfungsi sebagai contoh sempurna mengapa pengelola paket "tidak boleh dan tidak boleh pilih-pilih". :-) Sekarang bolehkah saya mendapatkan upvote Anda?
RayLuo
1
Saya juga dapat mengomentari pemikiran baru itu tetapi kemudian bagian komentar ini sudah keluar dari topik dan sulit untuk diikuti oleh pendatang baru. Saya akan menyarankan Anda untuk mengajukan pertanyaan baru "Haruskah kita menggunakan tox atau sesuatu untuk menjamin perpustakaan saya berfungsi pada berbagai kombinasi dependensi", dan kemudian orang-orang dapat ikut serta.
RayLuo