ตรวจสอบเวอร์ชันโมดูล Python ที่รันไทม์


119

โมดูล Python ของบุคคลที่สามจำนวนมากมีแอตทริบิวต์ที่เก็บข้อมูลเวอร์ชันสำหรับโมดูล (โดยปกติจะมีลักษณะคล้ายmodule.VERSIONหรือmodule.__version__) แต่บางโมดูลไม่มี

ตัวอย่างเฉพาะของโมดูลดังกล่าว ได้แก่ libxslt และ libxml2

ฉันต้องการตรวจสอบว่าเวอร์ชันที่ถูกต้องของโมดูลเหล่านี้กำลังใช้งานอยู่ที่รันไทม์ มีวิธีทำไหม?

วิธีแก้ปัญหาที่เป็นไปได้คือการอ่านซอร์สที่รันไทม์แฮชแล้วเปรียบเทียบกับแฮชของเวอร์ชันที่รู้จัก แต่นั่นเป็นเรื่องที่น่ารังเกียจ

มีวิธีแก้ไขที่ดีกว่านี้หรือไม่?

คำตอบ:


8

ฉันจะอยู่ห่างจากการแฮช เวอร์ชันของ libxslt ที่ใช้อาจมีแพตช์บางประเภทที่ไม่ส่งผลต่อการใช้งานของคุณ

อีกทางเลือกหนึ่งฉันขอแนะนำว่าอย่าตรวจสอบเวลาทำงาน (ไม่รู้ว่าเป็นข้อกำหนดที่ยากหรือไม่) สำหรับสิ่งที่ python ฉันเขียนว่ามีการอ้างอิงภายนอก (ไลบรารีของบุคคลที่สาม) ฉันเขียนสคริปต์ที่ผู้ใช้สามารถเรียกใช้เพื่อตรวจสอบการติดตั้ง python เพื่อดูว่ามีการติดตั้งโมดูลเวอร์ชันที่เหมาะสมหรือไม่

สำหรับโมดูลที่ไม่มีแอตทริบิวต์ "เวอร์ชัน" ที่กำหนดไว้คุณสามารถตรวจสอบอินเทอร์เฟซที่มี (คลาสและวิธีการ) และดูว่าตรงกับอินเทอร์เฟซที่ต้องการหรือไม่ จากนั้นในโค้ดจริงที่คุณกำลังดำเนินการสมมติว่าโมดูลของบุคคลที่สามมีอินเทอร์เฟซที่คุณคาดหวัง


245

ใช้pkg_resources ทุกสิ่งที่ติดตั้งจาก PyPI อย่างน้อยควรมีหมายเลขเวอร์ชัน

>>> import pkg_resources
>>> pkg_resources.get_distribution("blogofile").version
'0.7.1'

8
โปรดทราบว่าชื่อแพ็กเกจต้องเป็นชื่อของรายการ PyPI บางอย่างเช่น "pkg_resources.get_distribution ('MySQLdb') เวอร์ชัน" จะไม่ทำงาน แต่ "pkg_resources.get_distribution ('mysql-python'). version" จะ
Rahul

1
หากคุณกำลังเรียกใช้โดยใช้ชื่อไฟล์แบบสัมบูรณ์pkg_resourcesอาจเลือกเวอร์ชันอื่นที่ใช้แชโดว์เวอร์ชันที่คุณใช้งานอยู่จริงเนื่องจากมีลำดับความสำคัญสูงกว่าPYTHONPATHหรือใกล้เคียงกัน
tripleee

4
เผื่อมีใครอยากรู้วิธีสร้าง__version__แอตทริบิวต์: stackoverflow.com/q/17583443/562769
Martin Thoma

pkg_resourcesลิงค์เป็น Error 404
gerrit

สำหรับการประมวลผลอัตโนมัติโปรดดูคำถามนี้
gerrit

6

แนวคิดบางประการ:

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

แพ็กเกจควรระบุเวอร์ชัน แนวคิดเหล่านี้เกินความจำเป็นโดยสิ้นเชิงสำหรับงานง่าย ๆ ในการตรวจสอบเวอร์ชันโดยปกติ (ประมาณ 99%)
Zelphir Kaltstahl

2

คุณสามารถใช้ได้

pip freeze

เพื่อดูแพ็คเกจที่ติดตั้งในรูปแบบข้อกำหนด


1

คุณสามารถใช้importlib_metadataไลบรารีสำหรับสิ่งนี้

หากคุณใช้ python < 3.8ก่อนอื่นให้ติดตั้งด้วย:

pip install importlib_metadata

เนื่องจาก python 3.8รวมอยู่ในไลบรารีมาตรฐานของ python

จากนั้นในการตรวจสอบเวอร์ชันของแพ็คเกจ (ในตัวอย่างนี้lxml) ให้รัน:

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

โปรดทราบว่าวิธีนี้ใช้ได้กับแพ็คเกจที่ติดตั้งจาก PyPI เท่านั้น นอกจากนี้คุณต้องส่งชื่อแพ็กเกจเป็นอาร์กิวเมนต์ให้กับversionเมธอดแทนที่จะเป็นชื่อโมดูลที่แพ็กเกจนี้มีให้ (แม้ว่าโดยปกติจะเหมือนกันก็ตาม)


0

ฉันพบว่ามันค่อนข้างไม่น่าเชื่อถือที่จะใช้เครื่องมือต่างๆที่มีอยู่ (รวมถึงเครื่องมือที่ดีที่สุดที่pkg_resourcesกล่าวถึงในคำตอบอื่น ๆ นี้ ) เนื่องจากส่วนใหญ่ไม่ครอบคลุมทุกกรณี ตัวอย่างเช่น

  • โมดูลในตัว
  • ไม่ได้ติดตั้งโมดูล แต่เพิ่งเพิ่มไปยังเส้นทาง python (โดย IDE ของคุณเป็นต้น)
  • มีโมดูลเดียวกันสองเวอร์ชัน (หนึ่งในพา ธ python แทนที่โมดูลที่ติดตั้ง)

เนื่องจากเราจำเป็นต้องมีวิธีที่เชื่อถือได้ที่จะได้รับรุ่นใด ๆแพคเกจโมดูลหรือ submodule ฉันสิ้นสุดที่เขียนGetVersion ใช้งานง่ายมาก:

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

ดูรายละเอียดในเอกสารประกอบ


0

สำหรับโมดูลที่ไม่มี__version__สิ่งต่อไปนี้น่าเกลียด แต่ใช้งานได้:

#!/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))

หรือ

#!/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))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.