ตรวจสอบว่ามีการติดตั้ง Python Package หรือไม่


113

วิธีใดที่ดีในการตรวจสอบว่ามีการติดตั้งแพ็คเกจในขณะที่อยู่ในสคริปต์ Python หรือไม่? ฉันรู้ว่ามันง่ายจากล่าม แต่ฉันต้องทำภายในสคริปต์

ฉันเดาว่าฉันสามารถตรวจสอบได้ว่ามีไดเรกทอรีในระบบที่สร้างขึ้นระหว่างการติดตั้งหรือไม่ แต่ฉันรู้สึกว่ามีวิธีที่ดีกว่านี้ ฉันพยายามตรวจสอบให้แน่ใจว่าได้ติดตั้งแพ็คเกจ Skype4Py แล้วและหากไม่ติดตั้งฉันจะติดตั้ง

ความคิดของฉันในการทำเช็คให้สำเร็จ

  • ตรวจสอบไดเร็กทอรีในพา ธ การติดตั้งทั่วไป
  • ลองนำเข้าแพ็กเกจและหากมีการโยนข้อยกเว้นให้ติดตั้งแพ็กเกจ

การเขียนสคริปต์ Python เพื่อเริ่มต้น Skype โดยอัตโนมัติและใช้ tcpdump เพื่อรวบรวมข้อมูลแพ็คเก็ตดังนั้นฉันจึงสามารถวิเคราะห์ว่าเครือข่ายทำงานอย่างไรเมื่อคุณมีการประชุมทางโทรศัพท์
Kevin

คำตอบ:


108

หากคุณหมายถึงสคริปต์ python ให้ทำสิ่งนี้:

Python 3.3+ ใช้ sys.modules และfind_spec :

import importlib.util
import sys

# For illustrative purposes.
name = 'itertools'

if name in sys.modules:
    print(f"{name!r} already in sys.modules")
elif (spec := importlib.util.find_spec(name)) is not None:
    # If you choose to perform the actual import ...
    module = importlib.util.module_from_spec(spec)
    sys.modules[name] = module
    spec.loader.exec_module(module)
    print(f"{name!r} has been imported")
else:
    print(f"can't find the {name!r} module")

Python 3:

try:
    import mymodule
except ImportError as e:
    pass  # module doesn't exist, deal with it.

Python 2:

try:
    import mymodule
except ImportError, e:
    pass  # module doesn't exist, deal with it.

6
คำเตือน: วันนี้ฉันเพิ่งมีสถานการณ์ที่ ImportError เกิดขึ้นภายในโมดูลเอง สิ่งนี้ไม่ควรเกิดขึ้นบ่อยนัก แต่โปรดทราบว่าการตรวจสอบนี้ไม่น่าเชื่อถือในทุกกรณี
Koen Bok

7
นี้ไม่เพียง แต่ตรวจสอบ ; มันยังนำเข้า; ดูstackoverflow.com/questions/14050281/…
Jorge Leitao

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

การดำเนินการนี้จะล้มเหลวหากคุณมีไฟล์อื่นที่มีชื่อเดียวกันกับแพ็กเกจ
Sapphire_Brick

แน่นอน แต่นั่นเป็นปัญหาที่แตกต่างไปจากเดิมอย่างสิ้นเชิง หากคุณมีโมดูลหรือแพ็กเกจที่แตกต่างกันสองโมดูลที่มีชื่อเดียวกันในเส้นทางการค้นหาคุณกำลังมีปัญหา
Christopher

56

คำตอบที่อัปเดต

วิธีที่ดีกว่านี้คือ:

import subprocess
import sys

reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'])
installed_packages = [r.decode().split('==')[0] for r in reqs.split()]

ผลลัพธ์:

print(installed_packages)

[
    "Django",
    "six",
    "requests",
]

ตรวจสอบว่าrequestsติดตั้งแล้ว:

if 'requests' in installed_packages:
    # Do something

ทำไมต้องเป็นแบบนี้? บางครั้งคุณมีการชนกันของชื่อแอป การนำเข้าจากเนมสเปซของแอปไม่ได้ให้ภาพรวมของสิ่งที่ติดตั้งในระบบ

โปรดทราบว่าโซลูชันที่เสนอนั้นใช้ได้ผล:

  • เมื่อใช้ pip เพื่อติดตั้งจาก PyPI หรือจากแหล่งอื่น ๆ (เช่นpip install http://some.site/package-name.zipหรือประเภทไฟล์เก็บถาวรอื่น ๆ )
  • เมื่อติดตั้งด้วยตนเองโดยใช้ python setup.py install .
  • เมื่อติดตั้งจากที่เก็บระบบเช่น sudo apt install python-requests .

กรณีที่อาจเกิดขึ้น ไม่ได้ผล:

  • เมื่อติดตั้งในโหมดการพัฒนาเช่นpython setup.py develop.
  • เมื่อติดตั้งในโหมดการพัฒนาเช่น pip install -e /path/to/package/source/.

คำตอบเก่า

วิธีที่ดีกว่านี้คือ:

import pip
installed_packages = pip.get_installed_distributions()

สำหรับ pip> = 10.x ใช้:

from pip._internal.utils.misc import get_installed_distributions

ทำไมต้องเป็นแบบนี้? บางครั้งคุณมีการชนกันของชื่อแอป การนำเข้าจากเนมสเปซของแอปไม่ได้ให้ภาพรวมของสิ่งที่ติดตั้งในระบบ

เป็นผลให้คุณได้รับรายการpkg_resources.Distributionวัตถุ ดูตัวอย่างต่อไปนี้:

print installed_packages
[
    "Django 1.6.4 (/path-to-your-env/lib/python2.7/site-packages)",
    "six 1.6.1 (/path-to-your-env/lib/python2.7/site-packages)",
    "requests 2.5.0 (/path-to-your-env/lib/python2.7/site-packages)",
]

จัดทำรายการ:

flat_installed_packages = [package.project_name for package in installed_packages]

[
    "Django",
    "six",
    "requests",
]

ตรวจสอบว่าrequestsติดตั้งแล้ว:

if 'requests' in flat_installed_packages:
    # Do something

2
ดังที่กล่าวไว้ในคำตอบอื่น ๆ อาจเป็นไปได้ว่าข้อผิดพลาดจะไม่ถูกจับ ดังนั้นฉันคิดว่านี่ควรเป็นคำตอบที่ได้รับการยอมรับ
Jorrick Sleijster

1
วิธีนี้ใช้ไม่ได้กับแพ็กเกจเช่น 'json' (ส่งคืน False เมื่อใช้งานimport jsonได้จริง) วิธีการของ ice.nicer ใช้งานได้ในกรณีนี้
mountrix

1
ฉันต้องใช้เช็คif "u'requests'" in installed_packages:จากคำตอบที่อัปเดตเพื่อทำงานให้ฉัน ผลลัพธ์ของการprint()สร้างสิ่งนี้บนงูหลาม macOS ของฉัน:[..., u'pytz', u'requests', ...]
Buju

1
@ArturBarseghyan ฉันใช้ Python 2.7.10 (python ระบบ macOS) ... จริงๆแล้วฉันต้องใช้if "requests'"(สังเกตคำพูดเดียวในตอนท้าย) ไม่สมเหตุสมผลเลย
Buju

1
สิ่งนี้ไม่ตอบคำถาม: "ติดตั้งแพ็กเกจ 'x' หรือไม่" pipมีหลายวิธีในการติดตั้งแพคเกจโดยไม่ต้องใช้เป็น เช่นคุณสามารถสร้างและติดตั้งแพ็คเกจจากแหล่งที่มา คำตอบนี้จะไม่พบสิ่งเหล่านั้น คำตอบจาก @ ice.nicer เกี่ยวกับfind_spec()ถูกต้อง
Arthur

43

ในฐานะที่เป็นของงูใหญ่ 3.3, คุณสามารถใช้find_spec ()วิธีการ

import importlib.util

# For illustrative purposes.
package_name = 'pandas'

spec = importlib.util.find_spec(package_name)
if spec is None:
    print(package_name +" is not installed")

4
สะอาดและเรียบง่ายคำตอบที่ดีที่สุดที่นี่ สิ่งนี้ต้องการการโหวตเพิ่มขึ้น
David Parks

5
ระวัง. หากชื่อแพ็กเกจมีขีดกลาง find_spec () จะไม่พบเว้นแต่คุณจะใช้จุด ตัวอย่าง: importlib.util.find_spec('google-cloud-logging')ไม่พบสิ่งใดในขณะที่importlib.util.find_spec('google.cloud.logging')พบ ชื่ออย่างเป็นทางการและชื่อที่ pip แสดงคือมีขีดกลางไม่ใช่จุด อาจเกิดความสับสนจึงควรใช้ด้วยความระมัดระวัง
dwich

27

หากต้องการเช็คจากเครื่องคุณสามารถเรียกใช้

pip3 show package_name

และหากไม่มีสิ่งใดถูกส่งกลับแสดงว่าไม่มีการติดตั้งแพ็คเกจ

หากคุณต้องการทำให้การตรวจสอบนี้เป็นไปโดยอัตโนมัติตัวอย่างเช่นคุณสามารถติดตั้งได้หากขาดหายไปคุณสามารถทำสิ่งต่อไปนี้ในสคริปต์ทุบตีของคุณ:

pip3 show package_name 1>/dev/null #pip for Python 2
if [ $? == 0 ]; then
   echo "Installed" #Replace with your actions
else
   echo "Not Installed" #Replace with your actions, 'pip3 install --upgrade package_name' ?
fi

ดูเหมือนว่าจะดี แต่จะส่งคืน "Not Installed" ให้ฉันเสมอ ทำไม?
Elliptica

คุณสามารถแชร์ผลลัพธ์ของ“ $ pip3—version” และ“ $ pip3 show package_name” โดยที่คุณแทนที่ package_name ด้วยแพ็คเกจที่ต้องการได้หรือไม่
Ognjen Vukovic

เคล็ดลับเชลล์: คุณสามารถใช้ifเพื่อทดสอบคำสั่งที่ประสบความสำเร็จได้โดยตรง:if pip3 show package_name 1>/dev/null; then ...
MestreLion

6

เป็นส่วนขยายของคำตอบนี้ :

สำหรับ Python 2. * pip show <package_name>จะทำงานเดียวกัน

ตัวอย่างเช่นpip show numpyจะส่งคืนสิ่งต่อไปนี้หรือเหมือนกัน:

Name: numpy
Version: 1.11.1
Summary: NumPy: array processing for numbers, strings, records, and objects.
Home-page: http://www.numpy.org
Author: NumPy Developers
Author-email: numpy-discussion@scipy.org
License: BSD
Location: /home/***/anaconda2/lib/python2.7/site-packages
Requires: 
Required-by: smop, pandas, tables, spectrum, seaborn, patsy, odo, numpy-stl, numba, nfft, netCDF4, MDAnalysis, matplotlib, h5py, GridDataFormats, dynd, datashape, Bottleneck, blaze, astropy

ไม่ใช่จากสคริปต์ แต่เหมาะสำหรับการตรวจสอบบรรทัดคำสั่ง ขอบคุณ
Jj Rivero

3

คุณสามารถใช้โมดูล pkg_resources จาก setuptools ตัวอย่างเช่น:

import pkg_resources

package_name = 'cool_package'
try:
    cool_package_dist_info = pkg_resources.get_distribution(package_name)
except pkg_resources.DistributionNotFound:
    print('{} not installed'.format(package_name))
else:
    print(cool_package_dist_info)

โปรดทราบว่ามีความแตกต่างระหว่างโมดูล python และแพ็คเกจ python แพ็กเกจสามารถมีหลายโมดูลและชื่อโมดูลอาจไม่ตรงกับชื่อแพ็กเกจ



1

ฉันต้องการเพิ่มความคิด / ข้อค้นพบของฉันในหัวข้อนี้ ฉันกำลังเขียนสคริปต์ที่ตรวจสอบข้อกำหนดทั้งหมดสำหรับโปรแกรมที่สร้างขึ้นเอง มีการตรวจสอบหลายโมดูลด้วย python เช่นกัน

มีปัญหาเล็กน้อยเกี่ยวกับไฟล์

try:
   import ..
except:
   ..

สารละลาย. ในกรณีของฉันหนึ่งในโมดูล python ที่เรียกว่าpython-nmapแต่คุณนำเข้าด้วยimport nmapและเมื่อคุณเห็นชื่อไม่ตรงกัน ดังนั้นการทดสอบด้วยวิธีแก้ปัญหาข้างต้นจึงให้ผลลัพธ์ที่เป็นเท็จและยังนำเข้าโมดูลเมื่อ hit แต่อาจไม่จำเป็นต้องใช้หน่วยความจำจำนวนมากสำหรับการทดสอบ / ตรวจสอบอย่างง่าย

ฉันยังพบว่า

import pip
installed_packages = pip.get_installed_distributions()

installed_packagesจะมีเฉพาะแพ็คเกจที่ติดตั้ง pipเท่านั้น ในระบบของฉันpip freezeส่งคืน40โมดูล python ในขณะที่installed_packagesมีเพียง1ฉันติดตั้งด้วยตนเอง (python-nmap)

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

วิธีแก้ปัญหาที่ได้ผลสำหรับฉัน ตามคำตอบนี้วิธีตรวจสอบว่ามีโมดูล python อยู่โดยไม่ต้องนำเข้าหรือไม่

from imp import find_module

def checkPythonmod(mod):
    try:
        op = find_module(mod)
        return True
    except ImportError:
        return False

หมายเหตุ: โซลูชันนี้ไม่สามารถค้นหาโมดูลตามชื่อได้python-nmapเช่นกันฉันต้องใช้nmapแทน (ใช้งานง่าย) แต่ในกรณีนี้โมดูลจะไม่ถูกโหลดลงในหน่วยความจำ แต่อย่างใด


0

หากคุณต้องการให้สคริปต์ของคุณติดตั้งแพ็กเกจที่ขาดหายไปและดำเนินการต่อคุณสามารถทำสิ่งนี้ได้ (ในตัวอย่างของโมดูล 'krbV' ในแพ็กเกจ 'python-krbV'):

import pip
import sys

for m, pkg in [('krbV', 'python-krbV')]:
    try:
        setattr(sys.modules[__name__], m, __import__(m))
    except ImportError:
        pip.main(['install', pkg])
        setattr(sys.modules[__name__], m, __import__(m))

0

วิธีที่รวดเร็วคือการใช้เครื่องมือบรรทัดคำสั่งpython เพียงพิมพ์import <your module name> คุณจะเห็นข้อผิดพลาดหากโมดูลหายไป

$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
>>> import sys
>>> import jocker
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named jocker
$

0

อืม ... สิ่งที่ใกล้เคียงที่สุดที่ฉันเห็นสำหรับคำตอบที่สะดวกคือการใช้บรรทัดคำสั่งเพื่อลองนำเข้า แต่ฉันชอบที่จะหลีกเลี่ยงสิ่งนั้นมากกว่า

แล้ว 'pip freeze | grep pkgname '? ฉันลองแล้วและได้ผลดี นอกจากนี้ยังแสดงเวอร์ชันที่มีและติดตั้งภายใต้การควบคุมเวอร์ชัน (ติดตั้ง) หรือแก้ไขได้ (พัฒนา)


0

คลาส myError (ข้อยกเว้น): ผ่าน # หรือลองทำบางอย่าง: นำเข้า mymodule ยกเว้น ImportError เป็น e: เพิ่ม myError ("เกิดข้อผิดพลาด")



0

ฉันต้องการแสดงความคิดเห็นกับ @ ice.nicer ตอบกลับ แต่ฉันทำไม่ได้ดังนั้น ... ข้อสังเกตของฉันคือแพ็คเกจที่มีขีดกลางจะถูกบันทึกด้วยขีดล่างไม่เพียง แต่มีจุดตามที่ระบุไว้ในความคิดเห็นของ @dwich

ตัวอย่างเช่นคุณทำpip3 install sphinx-rtd-themeแต่:

  • importlib.util.find_spec(sphinx_rtd_theme) ส่งคืนวัตถุ
  • importlib.util.find_spec(sphinx-rtd-theme) ส่งกลับไม่มี
  • importlib.util.find_spec(sphinx.rtd.theme) เพิ่ม ModuleNotFoundError

นอกจากนี้ชื่อบางชื่อยังเปลี่ยนไปโดยสิ้นเชิง ตัวอย่างเช่นคุณทำpip3 install pyyamlแต่ได้รับการบันทึกเป็นyaml

ฉันใช้ python3.8



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