Sprawdź, czy pakiet Python jest zainstalowany


113

Jaki jest dobry sposób sprawdzenia, czy pakiet jest zainstalowany w skrypcie Pythona? Wiem, że to łatwe od tłumacza, ale muszę to zrobić w ramach scenariusza.

Myślę, że mógłbym sprawdzić, czy w systemie jest katalog utworzony podczas instalacji, ale czuję, że jest lepszy sposób. Próbuję się upewnić, że pakiet Skype4Py jest zainstalowany, a jeśli nie, zainstaluję go.

Moje pomysły na wykonanie czeku

  • sprawdź katalog w typowej ścieżce instalacji
  • spróbuj zaimportować pakiet, a jeśli wyjątek zostanie zgłoszony, zainstaluj pakiet

Napisanie skryptu w Pythonie w celu zautomatyzowania uruchamiania Skype'a i używanie tcpdump do zbierania danych pakietowych, aby móc przeanalizować, jak działa sieć podczas połączenia konferencyjnego.
Kevin

Odpowiedzi:


108

Jeśli masz na myśli skrypt w Pythonie, zrób coś takiego:

Python 3.3+ używa sys.modules i 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
Ostrzeżenie: właśnie dzisiaj miałem sytuację, w której ImportError został wyrzucony w samym module. Nie powinno się to zdarzać często, ale pamiętaj tylko, że ta kontrola nie jest wiarygodna we wszystkich przypadkach.
Koen Bok

7
To nie tylko sprawdza ; to również importuje; zobacz także stackoverflow.com/questions/14050281/…
Jorge Leitao

6
Tak. Generalnie tego chcesz. Możesz użyć modułu narzędzi importu, aby przeprowadzić bardziej wyrafinowaną kontrolę, ale w większości przypadków jedynym powodem, dla którego przejmujesz się instalacją modułu, jest chęć jego użycia.
Christopher

To się nie powiedzie, jeśli masz inny plik o tej samej nazwie co pakiet.
Sapphire_Brick

Jasne, ale to zupełnie inny problem. Jeśli masz dwa różne moduły lub pakiety o tej samej nazwie w ścieżce wyszukiwania, masz kłopoty.
Christopher

56

Zaktualizowana odpowiedź

Lepszym sposobem na to jest:

import subprocess
import sys

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

Wynik:

print(installed_packages)

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

Sprawdź, czy requestsjest zainstalowany:

if 'requests' in installed_packages:
    # Do something

Dlaczego w ten sposób? Czasami występują kolizje nazw aplikacji. Importowanie z przestrzeni nazw aplikacji nie daje pełnego obrazu tego, co jest zainstalowane w systemie.

Zwróć uwagę, że proponowane rozwiązanie działa:

  • Gdy używasz pip do instalacji z PyPI lub z innego alternatywnego źródła (takiego jak pip install http://some.site/package-name.ziplub dowolnego innego typu archiwum).
  • Podczas instalacji ręcznej za pomocą python setup.py install.
  • Podczas instalacji z repozytoriów systemowych, takich jak sudo apt install python-requests.

Przypadki, w których może to nie działać:

  • Podczas instalacji w trybie programistycznym, na przykład python setup.py develop.
  • Podczas instalacji w trybie programistycznym, na przykład pip install -e /path/to/package/source/.

Stara odpowiedź

Lepszym sposobem na to jest:

import pip
installed_packages = pip.get_installed_distributions()

Dla pip> = 10.x użyj:

from pip._internal.utils.misc import get_installed_distributions

Dlaczego w ten sposób? Czasami występują kolizje nazw aplikacji. Importowanie z przestrzeni nazw aplikacji nie daje pełnego obrazu tego, co jest zainstalowane w systemie.

W rezultacie otrzymasz listę pkg_resources.Distributionobiektów. Zobacz poniższy przykład:

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)",
]

Zrób ich listę:

flat_installed_packages = [package.project_name for package in installed_packages]

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

Sprawdź, czy requestsjest zainstalowany:

if 'requests' in flat_installed_packages:
    # Do something

2
Jak wspomniano w drugiej odpowiedzi, możliwe, że błąd nie zostanie wychwycony. Dlatego uważam, że powinna to być akceptowana odpowiedź.
Jorrick Sleijster

1
Ta metoda nie działa z pakietami takimi jak „json” (zwraca False, gdy import jsonrzeczywiście działa). W tym przypadku działa metoda ice.nicer.
mountrix

1
Musiałem jakoś użyć czeku if "u'requests'" in installed_packages:z Zaktualizowanej odpowiedzi, aby dla mnie zadziałał. Wyjście print()tworzy to na moim pythonie macOS:[..., u'pytz', u'requests', ...]
Buju

1
@ArturBarseghyan Jestem na Pythonie 2.7.10 (system macOS python) ... właściwie muszę użyć if "requests'"(zwróć uwagę na pojedynczy cudzysłów na końcu). w ogóle nie ma sensu.
Buju

1
To nie odpowiada na pytanie: „czy pakiet 'x' jest zainstalowany?”. Istnieje wiele sposobów instalacji pakietu bez użycia pip. Np. Możesz stworzyć i zainstalować pakiet ze źródła. Ta odpowiedź ich nie znajdzie. Odpowiedź z @ ice.nicer na temat find_spec()jest prawidłowa.
Arthur

43

Jak Pythona 3.3, można użyć find_spec () metody

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
Czysta i prosta, najlepsza odpowiedź tutaj. To wymaga więcej głosów pozytywnych.
David Parks

5
Bądź ostrożny. Jeśli nazwa pakietu zawiera myślniki, funkcja find_spec () nie może jej znaleźć, chyba że użyjesz kropek. Przykład: importlib.util.find_spec('google-cloud-logging')nic nie znajduje, gdy importlib.util.find_spec('google.cloud.logging')zostanie znalezione. Oficjalna nazwa i nazwa, którą pokazuje pip, zawiera myślniki, a nie kropki. Może to być mylące, dlatego należy zachować ostrożność.
dwich

27

Jeśli chcesz mieć czek z terminala, możesz biec

pip3 show package_name

a jeśli nic nie zostanie zwrócone, pakiet nie zostanie zainstalowany.

Jeśli być może chcesz zautomatyzować to sprawdzenie, aby na przykład zainstalować go, jeśli go brakuje, możesz mieć następujące elementy w swoim skrypcie bash:

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

Wydaje się to świetne, ale zawsze zwraca „Niezainstalowane”. Czemu?
Elliptica

Czy możesz udostępnić dane wyjściowe „$ pip3 - wersja” i „$ pip3 show nazwa_pakietu”, w których zastępujesz nazwę_pakietu żądanym pakietem?
Ognjen Vukovic

Wskazówka dotycząca powłoki: możesz użyć ifdo bezpośredniego przetestowania udanego polecenia:if pip3 show package_name 1>/dev/null; then ...
MestreLion

6

Jako rozszerzenie tej odpowiedzi :

Dla Pythona 2. *, pip show <package_name>wykona to samo zadanie.

Na przykład pip show numpyzwróci następujące lub podobne:

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

Nie ze skryptu, ale świetnie nadaje się do sprawdzania wiersza poleceń. Dzięki
Jj Rivero

3

Możesz użyć modułu pkg_resources z setuptools. Na przykład:

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)

Zauważ, że istnieje różnica między modułem Pythona a pakietem Pythona. Pakiet może zawierać wiele modułów, a nazwy modułów mogą nie odpowiadać nazwie pakietu.



1

Chciałbym dodać swoje przemyślenia / ustalenia do tego tematu. Piszę skrypt, który sprawdza wszystkie wymagania programu na zamówienie. Istnieje również wiele testów z modułami Pythona.

Jest mały problem z

try:
   import ..
except:
   ..

rozwiązanie. W moim przypadku jeden z modułów Pythona wywołał python-nmap, ale importujesz go z import nmapi jak widzisz niezgodność nazw. Dlatego test z powyższym rozwiązaniem zwraca wynik Fałsz, a także importuje moduł po trafieniu, ale być może nie ma potrzeby używania dużej ilości pamięci do prostego testu / sprawdzenia.

Ja też to znalazłem

import pip
installed_packages = pip.get_installed_distributions()

installed_packagesbędzie mieć tylko te pakiety, które zostały zainstalowane za pomocą pip . W moim systemie pip freezewraca przez 40moduły Pythona, podczas gdy installed_packagesma tylko ten 1, który zainstalowałem ręcznie (python-nmap).

Kolejne rozwiązanie poniżej, o którym wiem, może nie mieć związku z pytaniem , ale myślę, że dobrą praktyką jest oddzielenie funkcji testowej od tej, która wykonuje instalację, może być przydatna dla niektórych.

Rozwiązanie, które zadziałało dla mnie. Opiera się na tej odpowiedzi Jak sprawdzić, czy moduł Pythona istnieje bez importowania go

from imp import find_module

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

UWAGA: to rozwiązanie nie może znaleźć modułu również po nazwie python-nmap, muszę go użyć nmap(łatwy w użyciu), ale w tym przypadku moduł nie zostanie w ogóle załadowany do pamięci.


0

Jeśli chcesz, aby Twój skrypt zainstalował brakujące pakiety i kontynuował, możesz zrobić coś takiego (na przykładzie modułu 'krbV' w pakiecie '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

Szybkim sposobem jest użycie narzędzia wiersza poleceń w języku Python . Po prostu wpisz. import <your module name> Jeśli brakuje modułu, pojawi się błąd.

$ 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

Hmmm ... najbliższa wygodnej odpowiedzi, jaką widziałem, to użycie wiersza poleceń do wypróbowania importu. Ale wolę nawet tego unikać.

Co powiesz na „zamrażanie pip” | grep pkgname '? Próbowałem i działa dobrze. Pokazuje również wersję, którą ma i czy jest zainstalowana pod kontrolą wersji (zainstaluj), czy może być edytowana (programuj).


0

class myError (wyjątek): pass #lub zrób coś spróbuj: zaimportuj mymodule z wyjątkiem ImportError as e: raise myError ("wystąpił błąd")


0

W typie terminala

pip show some_package_name

Przykład

pip show matplotlib

0

Chciałbym skomentować odpowiedź @ ice.nicer, ale nie mogę, więc ... Z moich obserwacji wynika, że ​​pakiety z myślnikami są zapisywane z podkreśleniami, a nie tylko kropkami, jak wskazuje komentarz @dwich

Na przykład tak pip3 install sphinx-rtd-theme, ale:

  • importlib.util.find_spec(sphinx_rtd_theme) zwraca Object
  • importlib.util.find_spec(sphinx-rtd-theme) zwraca None
  • importlib.util.find_spec(sphinx.rtd.theme) podnosi ModuleNotFoundError

Co więcej, niektóre imiona uległy całkowitej zmianie. Na przykład robisz, pip3 install pyyamlale jest zapisywany po prostu jakoyaml

Używam Pythona3.8


0
if pip3 list | grep -sE '^some_command\s+[0-9]' >/dev/null
  # installed ...
else
  # not installed ...
fi

-1

Wybierz opcję nr 2. Jeśli ImportErrorzostanie wyrzucony, pakiet nie jest zainstalowany (lub nie jest w sys.path).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.