Memeriksa versi modul Python saat runtime

119

Banyak modul Python pihak ketiga memiliki atribut yang menyimpan informasi versi untuk modul tersebut (biasanya seperti module.VERSIONatau module.__version__), namun beberapa tidak.

Contoh khusus dari modul tersebut adalah libxslt dan libxml2.

Saya perlu memeriksa bahwa versi yang benar dari modul-modul ini digunakan saat runtime. Apakah ada cara untuk melakukan ini?

Solusi potensial adalah membaca sumber pada waktu proses, melakukan hash, lalu membandingkannya dengan hash dari versi yang diketahui, tapi itu buruk.

Apakah ada solusi yang lebih baik?

Kasar
sumber

Jawaban:

8

Saya akan menjauh dari hashing. Versi libxslt yang digunakan mungkin berisi beberapa jenis tambalan yang tidak memengaruhi penggunaan Anda.

Sebagai alternatif, saya menyarankan agar Anda tidak memeriksa pada waktu proses (tidak tahu apakah itu persyaratan yang sulit atau tidak). Untuk barang-barang python yang saya tulis yang memiliki ketergantungan eksternal (perpustakaan pihak ke-3), saya menulis skrip yang dapat dijalankan pengguna untuk memeriksa pemasangan python mereka untuk melihat apakah versi yang sesuai dari modul diinstal.

Untuk modul yang tidak memiliki atribut 'versi' yang ditentukan, Anda dapat memeriksa antarmuka yang dikandungnya (kelas dan metode) dan melihat apakah cocok dengan antarmuka yang mereka harapkan. Kemudian dalam kode aktual yang sedang Anda kerjakan, asumsikan bahwa modul pihak ketiga memiliki antarmuka yang Anda harapkan.

Mark Roddy
sumber
245

Gunakan pkg_resources . Apa pun yang diinstal dari PyPI setidaknya harus memiliki nomor versi.

>>> import pkg_resources
>>> pkg_resources.get_distribution("blogofile").version
'0.7.1'
EnigmaCurry
sumber
8
Perhatikan juga bahwa, nama paket harus dari entri PyPI. Jadi sesuatu seperti "pkg_resources.get_distribution ('MySQLdb'). Version" tidak akan berfungsi tetapi "pkg_resources.get_distribution ('mysql-python'). Version" akan berfungsi.
Rahul
1
Jika Anda menjalankan dengan nama file absolut, pkg_resourcesmungkin mengambil versi berbeda yang membayangi yang sebenarnya Anda jalankan karena memiliki prioritas lebih tinggi pada Anda PYTHONPATHatau serupa.
tripleee
4
Jika ada yang ingin tahu cara membuat __version__atribut: stackoverflow.com/q/17583443/562769
Martin Thoma
pkg_resourcesTautan adalah Kesalahan 404
gerrit
Untuk pemrosesan otomatis, lihat pertanyaan ini
gerrit
6

Beberapa ide:

  1. Coba periksa fungsi yang ada atau tidak ada di versi yang Anda butuhkan.
  2. Jika tidak ada perbedaan fungsi, periksa argumen fungsi dan tanda tangan.
  3. Jika Anda tidak dapat mengetahuinya dari tanda tangan fungsi, siapkan beberapa panggilan rintisan pada waktu impor dan periksa perilakunya.
Richard Levasseur
sumber
Paket harus menentukan versinya. Ide-ide ini benar-benar berlebihan untuk tugas yang biasanya (diperkirakan 99% dari kasus) mudah untuk memeriksa versi.
Zelphir Kaltstahl
2

Kamu bisa memakai

pip freeze

untuk melihat paket yang diinstal dalam format persyaratan.

no
sumber
1

Anda dapat menggunakan importlib_metadataperpustakaan untuk ini.

Jika Anda menggunakan python < 3.8, instal dulu dengan:

pip install importlib_metadata

Sejak python 3.8itu termasuk dalam perpustakaan standar python.

Kemudian, untuk memeriksa versi paket (dalam contoh ini lxml) jalankan:

>>> from importlib_metadata import version
>>> version('lxml')
'4.3.1'

Ingatlah bahwa ini hanya berfungsi untuk paket yang diinstal dari PyPI. Selain itu, Anda harus meneruskan nama paket sebagai argumen ke versionmetode tersebut, bukan nama modul yang disediakan paket ini (meskipun biasanya sama).

Jakub Kukul
sumber
0

Saya merasa sangat tidak dapat diandalkan untuk menggunakan berbagai alat yang tersedia (termasuk yang terbaik yang pkg_resourcesdisebutkan oleh jawaban lain ini ), karena kebanyakan tidak mencakup semua kasus. Sebagai contoh

  • modul bawaan
  • modul tidak diinstal tetapi hanya ditambahkan ke jalur python (oleh IDE Anda misalnya)
  • dua versi dari modul yang sama tersedia (satu di jalur python menggantikan yang terpasang)

Karena kita membutuhkan cara yang dapat diandalkan untuk mendapatkan versi setiap paket, modul atau submodule, saya akhirnya menulis getversion . Cukup mudah digunakan:

from getversion import get_module_version
import foo
version, details = get_module_version(foo)

Lihat dokumentasi untuk detailnya.

smarie
sumber
0

Untuk modul yang tidak menyediakan __version__yang berikut ini jelek tetapi berfungsi:

#!/usr/bin/env python3.6
import sys
import os
import subprocess
import re

sp = subprocess.run(["pip3", "show", "numpy"], stdout=subprocess.PIPE)
ver = sp.stdout.decode('utf-8').strip().split('\n')[1]
res = re.search('^Version:\ (.*)$', ver)
print(res.group(1))

atau

#!/usr/bin/env python3.7
import sys
import os
import subprocess
import re

sp = subprocess.run(["pip3", "show", "numpy"], capture_output=True)
ver = sp.stdout.decode('utf-8').strip().split('\n')[1]
res = re.search('^Version:\ (.*)$', ver)
print(res.group(1))
phzx_munki
sumber