Apakah ada cara standar untuk mengaitkan string versi dengan paket python sedemikian rupa sehingga saya bisa melakukan hal berikut?
import foo
print foo.version
Saya akan membayangkan ada beberapa cara untuk mengambil data tanpa hardcoding tambahan, karena string minor / major sudah ditentukan di dalam setup.py
. Solusi alternatif yang saya temukan adalah memiliki import __version__
di saya foo/__init__.py
dan kemudian __version__.py
dihasilkan oleh setup.py
.
setup.py
sudah cukup. Lihat pertanyaan ini .Jawaban:
Bukan jawaban langsung untuk pertanyaan Anda, tetapi Anda sebaiknya mempertimbangkan untuk menamainya
__version__
, bukanversion
.Ini hampir merupakan standar kuasi. Banyak modul dalam pustaka standar yang digunakan
__version__
, dan ini juga digunakan dalam banyak modul pihak ke-3, jadi ini adalah standar-semu.Biasanya,
__version__
adalah string, tetapi kadang-kadang juga float atau tuple.Sunting: seperti yang disebutkan oleh S.Lott (Terima kasih!), PEP 8 mengatakannya secara eksplisit:
Anda juga harus memastikan bahwa nomor versi sesuai dengan format yang dijelaskan dalam PEP 440 ( PEP 386 versi sebelumnya dari standar ini).
sumber
__version_info__
khusus? (Yang "menciptakan" kata dua garis bawah Anda sendiri.) [Ketika James berkomentar, garis bawah tidak melakukan apa pun dalam komentar, sekarang mereka menunjukkan penekanan, sehingga James benar-benar__version_info__
juga menulis . --- ed.]Saya menggunakan satu
_version.py
file sebagai "tempat kanonis sekali" untuk menyimpan informasi versi:Ini menyediakan
__version__
atribut.Ini menyediakan versi metadata standar. Oleh karena itu akan terdeteksi oleh
pkg_resources
atau alat lain yang mengurai paket metadata (EGG-INFO dan / atau PKG-INFO, PEP 0345).Itu tidak mengimpor paket Anda (atau apa pun) ketika membangun paket Anda, yang dapat menyebabkan masalah dalam beberapa situasi. (Lihat komentar di bawah tentang masalah apa yang dapat menyebabkan ini.)
Hanya ada satu tempat nomor versi ditulis, jadi hanya ada satu tempat untuk mengubahnya ketika nomor versi berubah, dan ada sedikit peluang versi tidak konsisten.
Inilah cara kerjanya: "satu tempat kanonik" untuk menyimpan nomor versi adalah file .py, bernama "_version.py" yang ada dalam paket Python Anda, misalnya di
myniftyapp/_version.py
. File ini adalah modul Python, tetapi setup.py Anda tidak mengimpornya! (Itu akan mengalahkan fitur 3.) Sebaliknya setup.py Anda tahu bahwa isi file ini sangat sederhana, seperti:Dan setup.py Anda membuka file dan mem-parsingnya, dengan kode seperti:
Kemudian setup.py Anda meneruskan string itu sebagai nilai argumen "versi"
setup()
, sehingga fitur 2 memuaskan.Untuk memenuhi fitur 1, Anda dapat meminta paket Anda (pada saat run-time, bukan pada waktu setup!) Mengimpor file _version dari
myniftyapp/__init__.py
seperti ini:Berikut adalah contoh teknik ini yang telah saya gunakan selama bertahun-tahun.
Kode dalam contoh itu sedikit lebih rumit, tetapi contoh sederhana yang saya tulis dalam komentar ini harus merupakan implementasi yang lengkap.
Berikut ini contoh kode untuk mengimpor versi .
Jika Anda melihat ada yang salah dengan pendekatan ini, beri tahu saya.
sumber
setup.py
. Juga, jika mencoba melakukan kedalaman penuh-pertama dan melakukan semua deps sebelum melakukan ini, itu akan macet jika ada deps melingkar. Tetapi jika ia mencoba untuk membangun paket ini sebelum menginstal dependensi, maka jika Anda mengimpor paket Anda dari Andasetup.py
, ia tidak akan selalu dapat mengimpor depsnya, atau versi deps yang tepat.execfile("myniftyapp/_version.py")
dari dalam setup.py, daripada mencoba mengurai kode versi secara manual. Disarankan di stackoverflow.com/a/2073599/647002 - diskusi mungkin juga bermanfaat.Ditulis ulang 2017-05
Setelah lebih dari sepuluh tahun menulis kode Python dan mengelola berbagai paket saya sampai pada kesimpulan bahwa DIY mungkin bukan pendekatan terbaik.
Saya mulai menggunakan
pbr
paket untuk berurusan dengan versi dalam paket saya. Jika Anda menggunakan git sebagai SCM Anda, ini akan cocok dengan alur kerja Anda seperti sulap, menghemat minggu kerja Anda (Anda akan terkejut dengan betapa kompleksnya masalah ini).Sampai hari ini pbr berada di peringkat # 11 paket python yang paling sering digunakan dan mencapai level ini tidak termasuk trik kotor: hanya satu: memperbaiki masalah pengemasan umum dengan cara yang sangat sederhana.
pbr
dapat melakukan lebih banyak dari beban pemeliharaan paket, tidak terbatas pada versi tetapi tidak memaksa Anda untuk mengadopsi semua manfaatnya.Jadi untuk memberi Anda gambaran tentang bagaimana mengadopsi pbr dalam satu komit, lihatlah kemasan swiching untuk pbr
Mungkin Anda akan mengamati bahwa versi tersebut tidak disimpan sama sekali di repositori. PBR mendeteksi itu dari cabang dan tag Git.
Tidak perlu khawatir tentang apa yang terjadi ketika Anda tidak memiliki repositori git karena pbr melakukan "kompilasi" dan men-cache versi ketika Anda mengemas atau menginstal aplikasi, sehingga tidak ada ketergantungan runtime pada git.
Solusi lama
Inilah solusi terbaik yang pernah saya lihat sejauh ini dan itu juga menjelaskan mengapa:
Di dalam
yourpackage/version.py
:Di dalam
yourpackage/__init__.py
:Di dalam
setup.py
:Jika Anda tahu pendekatan lain yang tampaknya lebih baik beri tahu saya.
sumber
from .version import __version__
di setup.py juga?setup.py
sedang berjalan - coba, Anda akan mendapatkan kesalahan (atau setidaknya, saya lakukan :-))Per PEP 396 yang ditangguhkan (Nomor Versi Modul) , ada cara yang diusulkan untuk melakukan ini. Ini menjelaskan, dengan alasan, standar (diakui opsional) untuk mengikuti modul. Berikut cuplikan:
sumber
Meskipun ini mungkin terlalu terlambat, ada alternatif yang sedikit lebih sederhana dari jawaban sebelumnya:
(Dan itu akan cukup sederhana untuk mengkonversi bagian nomor versi yang ditambahkan secara otomatis ke string menggunakan
str()
.)Tentu saja, dari apa yang saya lihat, orang cenderung menggunakan sesuatu seperti versi yang disebutkan sebelumnya ketika menggunakan
__version_info__
, dan menyimpannya sebagai tuple int; namun, saya tidak mengerti maksudnya, karena saya ragu ada situasi di mana Anda akan melakukan operasi matematika seperti penambahan dan pengurangan pada bagian-bagian nomor versi untuk tujuan apa pun selain keingintahuan atau peningkatan otomatis (dan bahkan kemudian,int()
danstr()
dapat digunakan dengan cukup mudah). (Di sisi lain, ada kemungkinan kode orang lain mengharapkan tupel numerik daripada tupel string dan dengan demikian gagal.)Ini, tentu saja, pandangan saya sendiri, dan saya dengan senang hati ingin masukan dari orang lain tentang menggunakan tuple numerik.
Seperti yang diingatkan oleh shezi kepada saya, perbandingan string nomor (leksikal) tidak harus memiliki hasil yang sama dengan perbandingan numerik langsung; nol terkemuka akan diminta untuk menyediakan untuk itu. Jadi pada akhirnya, menyimpan
__version_info__
(atau apa pun namanya) sebagai tuple nilai integer akan memungkinkan perbandingan versi yang lebih efisien.sumber
__version_info__ = (1,2,3)
__version_info__ = (0, 1, 0) __version__ = '.'.join(map(str, __version_info__))
__version__ = '.'.join(__version_info__)
adalah apakah itu__version_info__ = ('1', '2', 'beta')
akan menjadi1.2.beta
, bukan1.2beta
atau1.2 beta
Banyak dari solusi ini di sini mengabaikan
git
tag versi yang masih berarti Anda harus melacak versi di banyak tempat (buruk). Saya mendekati ini dengan tujuan-tujuan berikut:git
repogit tag
/push
dansetup.py upload
langkah-langkah dengan satu perintah yang tidak membutuhkan input.Bagaimana itu bekerja:
Dari sebuah
make release
perintah, versi yang di-tag terakhir di git repo ditemukan dan ditambahkan. Tag didorong kembali keorigin
.The
Makefile
toko versi disrc/_version.py
mana ia akan dibaca olehsetup.py
dan juga termasuk dalam rilis. Jangan memeriksa_version.py
kontrol sumber!setup.py
perintah membaca string versi baru daripackage.__version__
.Detail:
Makefile
The
release
Target selalu increment ke-3 versi digit, tetapi Anda dapat menggunakannext_minor_ver
ataunext_major_ver
untuk kenaikan lain digit. Perintah-perintah bergantung padaversionbump.py
skrip yang diperiksa ke root dari repoversibump.py
Ini tidak mengangkat berat bagaimana memproses dan menambah nomor versi dari
git
.__init__.py
The
my_module/_version.py
file diimpor kemy_module/__init__.py
. Letakkan konfigurasi pemasangan statis di sini yang ingin Anda bagikan dengan modul Anda.setup.py
Langkah terakhir adalah membaca info versi dari
my_module
modul.Tentu saja, agar semua ini berfungsi, Anda harus memiliki setidaknya satu tag versi dalam repo Anda untuk memulai.
sumber
versionbump.py
saat kami memiliki paket bumpversion yang luar biasa untuk python._version.py
dilacak dengan kontrol versi?Saya menggunakan file JSON di dir paket. Ini sesuai dengan persyaratan Zooko.
Di dalam
pkg_dir/pkg_info.json
:Di dalam
setup.py
:Di dalam
pkg_dir/__init__.py
:Saya juga memasukkan informasi lain
pkg_info.json
, seperti penulis. Saya suka menggunakan JSON karena saya dapat mengotomatisasi manajemen metadata.sumber
Juga perlu dicatat adalah bahwa juga
__version__
semi-std. dalam python begitu juga__version_info__
yang merupakan tuple, dalam kasus-kasus sederhana Anda bisa melakukan sesuatu seperti:... dan Anda bisa mendapatkan
__version__
string dari file, atau apa pun.sumber
__version_info__
?__version_info__ = (1, 2, 3)
dan__version__ = '.'.join(map(str, __version_info__))
).__version__ = '.'.join(str(i) for i in __version_info__)
- sedikit lebih panjang tetapi lebih pythonic.i
tidak memiliki makna,version_num
agak panjang dan membingungkan ...). Saya bahkan menganggap keberadaanmap()
dalam Python sebagai petunjuk kuat bahwa itu harus digunakan di sini, karena apa yang perlu kita lakukan di sini adalah kasus penggunaan khasmap()
(gunakan dengan fungsi yang ada) —Aku tidak melihat banyak kegunaan lain yang masuk akal.Sepertinya tidak ada cara standar untuk menanamkan string versi dalam paket python. Sebagian besar paket yang saya lihat menggunakan beberapa varian dari solusi Anda, yaitu eitner
Cantumkan versi
setup.py
dan telahsetup.py
menghasilkan modul (mis.version.py
) Yang hanya berisi info versi, yang diimpor oleh paket Anda, atauSebaliknya: menaruh info versi dalam paket Anda sendiri, dan impor yang mengatur versi di
setup.py
sumber
panah menanganinya dengan cara yang menarik.
Sekarang (sejak 2e5031b )
Dalam
arrow/__init__.py
:Dalam
setup.py
:Sebelum
Dalam
arrow/__init__.py
:Dalam
setup.py
:sumber
file_text
?pip install -e .
di cabang pengembangan atau sesuatu saat pengujian. setup.py benar-benar tidak harus bergantung pada impor paket itu dalam proses pemasangan untuk menentukan parameter untuk penyebaran. Astaga.Saya juga melihat gaya lain:
sumber
.VERSION
bukan berarti Anda tidak harus menerapkan__version__
.django
dalam proyek?Menggunakan
setuptools
danpbr
Tidak ada cara standar untuk mengelola versi, tetapi cara standar untuk mengelola paket Anda adalah
setuptools
.Solusi terbaik yang saya temukan secara keseluruhan untuk mengelola versi adalah menggunakan
setuptools
denganpbr
ekstensi. Ini sekarang cara standar saya mengelola versi.Menyiapkan proyek Anda untuk pengemasan penuh mungkin berlebihan untuk proyek-proyek sederhana, tetapi jika Anda perlu mengelola versi, Anda mungkin berada pada level yang tepat untuk hanya mengatur semuanya. Melakukan hal itu juga membuat paket Anda dapat dirilis di PyPi sehingga semua orang dapat mengunduh dan menggunakannya dengan Pip.
PBR memindahkan sebagian besar metadata dari
setup.py
alat dan kesetup.cfg
file yang kemudian digunakan sebagai sumber untuk sebagian besar metadata, yang dapat menyertakan versi. Ini memungkinkan metadata untuk dikemas menjadi yang dapat dieksekusi menggunakan sesuatu sepertipyinstaller
jika diperlukan (jika demikian, Anda mungkin akan memerlukan info ini ), dan memisahkan metadata dari skrip pengaturan / pengaturan paket lainnya. Anda dapat langsung memperbarui string versisetup.cfg
secara manual, dan itu akan ditarik ke dalam*.egg-info
folder saat membangun rilis paket Anda. Skrip Anda kemudian dapat mengakses versi dari metadata menggunakan berbagai metode (proses ini diuraikan dalam bagian di bawah).Saat menggunakan Git untuk VCS / SCM, pengaturan ini bahkan lebih baik, karena akan menarik banyak metadata dari Git sehingga repo Anda dapat menjadi sumber kebenaran utama Anda untuk beberapa metadata, termasuk versi, penulis, changelogs, dll. Untuk versi khusus, itu akan membuat string versi untuk komit saat ini berdasarkan pada tag git di repo.
setup.py
dansetup.cfg
file dengan metadata.Karena PBR akan menarik versi, penulis, changelog, dan info lainnya langsung dari repo git Anda, sehingga beberapa metadata di
setup.cfg
dapat ditinggalkan dan dibuat secara otomatis setiap kali distribusi dibuat untuk paket Anda (menggunakansetup.py
)Versi aktual saat ini
setuptools
akan menarik info terbaru secara real-time menggunakansetup.py
:Ini akan menarik versi terbaru dari
setup.cfg
file, atau dari repo git, berdasarkan komit terbaru yang dibuat dan tag yang ada di repo. Perintah ini tidak memperbarui versi dalam distribusi.Memperbarui versi
Ketika Anda membuat distribusi dengan
setup.py
(misalnyapy setup.py sdist
, misalnya), maka semua info saat ini akan diekstraksi dan disimpan dalam distribusi. Ini pada dasarnya menjalankansetup.py --version
perintah dan kemudian menyimpan info versi itu kepackage.egg-info
folder dalam satu set file yang menyimpan metadata distribusi.Mengakses versi dari skrip
Anda bisa mengakses metadata dari build saat ini di dalam skrip Python dalam paket itu sendiri. Untuk versi, misalnya, ada beberapa cara untuk melakukan ini yang saya temukan sejauh ini:
Anda dapat memasukkan salah satu dari ini secara langsung
__init__.py
ke dalam paket Anda untuk mengekstrak info versi sebagai berikut, mirip dengan beberapa jawaban lain:sumber
Setelah beberapa jam mencoba menemukan solusi andal yang paling sederhana, berikut adalah bagian-bagiannya:
buat file version.py DI DALAM folder "/ mypackage" paket Anda:
di setup.py:
di folder utama init .py:
The
exec()
Fungsi menjalankan luar naskah impor apapun, karena setup.py dijalankan sebelum modul dapat diimpor. Anda masih hanya perlu mengelola nomor versi dalam satu file di satu tempat, tetapi sayangnya itu tidak ada di setup.py. (itulah sisi buruknya, tetapi tidak memiliki bug impor adalah sisi baiknya)sumber
Banyak pekerjaan menuju versi seragam dan mendukung konvensi telah selesai sejak pertanyaan ini pertama kali diajukan . Opsi Palatable sekarang dirinci dalam Panduan Pengguna Kemasan Python . Juga patut dicatat adalah bahwa skema nomor versi relatif ketat dalam Python per PEP 440 , dan menjaga hal-hal yang waras sangat penting jika paket Anda akan dirilis ke Toko Keju .
Berikut uraian singkat opsi versi:
setup.py
( setuptools ) dan dapatkan versinya.__init__.py
serta kontrol sumber), misalnya bump2version , perubahan atau zest.releaser .__version__
variabel global dalam modul tertentu.setup.py
rilis, dan gunakan importlib.metadata untuk mengambilnya saat runtime. (Peringatan, ada versi pra-3.8 dan pasca-3.8.)__version__
dalamsample/__init__.py
dan impor sampel masuksetup.py
.Perhatikan bahwa (7) mungkin pendekatan yang paling modern (metadata build tidak tergantung pada kode, diterbitkan oleh otomatisasi). Juga PERHATIKAN bahwa jika pengaturan digunakan untuk rilis paket yang sederhana
python3 setup.py --version
akan melaporkan versi secara langsung.sumber
Untuk apa nilainya, jika Anda menggunakan distutils NumPy,
numpy.distutils.misc_util.Configuration
memilikimake_svn_version_py()
metode yang menyematkan nomor revisi dipackage.__svn_version__
dalam variabelversion
.sumber
version.py
file hanya dengan__version__ = <VERSION>
param di file. Dalamsetup.py
file impor__version__
param dan masukkan nilainya dalamsetup.py
file seperti ini:version=__version__
setup.py
file denganversion=<CURRENT_VERSION>
- CURRENT_VERSION adalah hardcoded.Karena kami tidak ingin secara manual mengubah versi dalam file setiap kali kami membuat tag baru (siap merilis versi paket baru), kami dapat menggunakan yang berikut ..
Saya sangat merekomendasikan paket bumpversion . Saya telah menggunakannya selama bertahun-tahun untuk menabrak versi.
mulai dengan menambahkan
version=<VERSION>
kesetup.py
file Anda jika Anda belum memilikinya.Anda harus menggunakan skrip pendek seperti ini setiap kali Anda membuat versi:
Kemudian tambahkan satu file per repo bernama
.bumpversion.cfg
::catatan:
__version__
parameter di bawahversion.py
file seperti yang disarankan di posting lain dan memperbarui file bumpversion seperti ini:[bumpversion:file:<RELATIVE_PATH_TO_VERSION_FILE>]
git commit
ataugit reset
semua yang ada dalam repo Anda, jika tidak, Anda akan mendapatkan kesalahan repo kotor.sumber
bumpversion
, tanpa itu tidak akan berfungsi. Gunakan versi terbaru.version.py
, atau melacaknya denganbumpversion
?__version__
param ke dalam file setup.py. Solusi saya digunakan dalam produksi dan ini adalah praktik umum. Catatan: hanya untuk menjadi jelas, menggunakan bumpversion sebagai bagian dari skrip adalah solusi terbaik, taruh di CI Anda dan itu akan menjadi operasi otomatis.Jika Anda menggunakan CVS (atau RCS) dan menginginkan solusi cepat, Anda dapat menggunakan:
(Tentu saja, nomor revisi akan diganti untuk Anda oleh CVS.)
Ini memberi Anda versi ramah-cetak dan info versi yang dapat Anda gunakan untuk memeriksa apakah modul yang Anda impor memiliki setidaknya versi yang diharapkan:
sumber
__version__
untuk disimpan ? Bagaimana seseorang menambah nomor versi dengan solusi ini?