Zależności w Pythonie
Na co dzień w pracy używam JavaScriptu i PHP. W tych językach występują menedżery pakietów npm
(i nie tylko) i composer
, które umożliwiają łatwe zarządzanie zależnościami dla każdego projektu. Do tej pory w Pythonie pisałem dość proste skrypty i nie potrzebowałem żadnego menedżera pakietów. W ramach nadchodzących projektów postanowiłem sprawdzić jak wygląda sprawa z zarządzaniem zależnościami w Pythonie.
pip (Pip Installs Packages)
Pip jest standardowym menedżerem pakietów w Pythonie. Poniżej przedstawiam listę podstawowych komend.
pip install <package> # instalacja pakietu
pip install <package> --upgrade # aktualizacja pakietu
pip uninstall # odinstalowuje pakiety
pip list # wyświetla listę zainstalowanych pakietów
pip list --outdated # wyświetla listę nieaktualnych pakietów
pip show # wyświetla szczegóły na temat pakietu
pip freeze # wyświetla listę zainstalowanych pakietów w formacie plików requirements.txt
pip install -r requirements.txt # instaluje zależności z pliku requirements.txt
Tworząc projekt warto podać w pliku requirements.txt
listę zależności, które są wymagane by uruchomić projekt. Przykładowy plik requirements.txt
wygląda następująco:
matplotlib==1.3.1
numpy==1.12.0
scikit-learn==0.18.1
Widzimy, że lista zawiera nazwy pakietów i ich wersje oddzielone znakami ==
.
pipreqs
Co jeśli jednak mamy już jakiś projekt i potrzebujemy utworzyć listę zależności? Czy musimy się bawić w ich wyciąganie z listy otrzymanej za pomocą polecenia pip freeze
? Z pomocą przychodzi biblioteka pipreqs
.
Instalujemy ją:
pip install pipreqs
A potem wywołujemy, jako parametr podając katalog z projektem, w którym chcemy dostać listę zależności:
pipreqs project_directory/
virtualenv
Wszystko fajnie, ale goły pip
ma jedną poważną wadę - instaluje wszystkie pakiety w przestrzeni globalnej (to tak jakbyśmy użyli npm install -g <package>
. W przypadku, gdy mamy kilka projektów i te potrzebują do działania różnych wersji tej samej biblioteki mamy problem. Rozwiązaniem jest użycie biblioteki virtualenv
. Pozwala ona na tworzenie odizolowanych środowisk z Pythonem i zależnościami. Zobaczmy jak to działa.
Aby zainstalować virtualenv
wpisujemy w konsoli:
pip install virtualenv
Instalacja virtualenv w katalogu projektu:
virtualenv env # env to nazwa katalogu, w którym będzie środowisko
virtualenv -p python3 env # jak chcemy Pythona 3
Powstanie katalog env. Wylistujmy go:
$ ls env/
bin include lib local pip-selfcheck.json
Katalog env/bin/
zawiera to co nas najbardziej interesuje, czyli lokalną wersję Pythona i pip.
Ok, przetestujmy virtualenv
. Instalacja biblioteki w virtualenv
wygląda następująco:
env/bin/pip install requests
Sprawdźmy, czy rzeczywiście to środowisko jest odizolowane od głównego:
$ env/bin/pip list
appdirs (1.4.3)
packaging (16.8)
pip (9.0.1)
pyparsing (2.2.0)
requests (2.13.0)
setuptools (34.3.1)
six (1.10.0)
wheel (0.29.0)
Ułatwienie pracy z virtualenv
Co jeśli nie chcemy ciągle pisać env/bin/pip
i tym podobnych komend odnoszących się do naszego środowiska?
Najpierw dla celów testowych użyjemy komendy which
która wyświetla katalog, w którym jest przechowywany uruchamiany program:
which python
Wynikiem wywołania tego polecenia będzie najprawdopodobniej poniższa ścieżka (lub podobna):
/usr/bin/python
Ok, zmieniamy Pythona i resztę na tę z naszego utworzonego środowiska:
source env/bin/activate
Powyższa komenda uruchami w bieżącej instancji powłoki skrypt, który podmieni zmienne środowiskowe na te ze środowiska wirtualnego.
Wpisujemy w konsoli jeszcze raz which python
i otrzymujemy coś w rodzaju:
/home/Dawid/python_projects/virtualenv_test/env/bin/python
Teraz jak wpiszemy w konsoli python
to uruchomi się Python z naszego odizolowanego środowiska wirtualnego, a nie ten globalny.
Aby wyłączyć środowisko projektu wystarczy wpisać w konsoli deactivate
.
Podsumowanie
To tyle, nauczyliśmy się podstawowej obsługi pip
i virtualenv
. O tworzenieniu paczek i wysyłaniu ich do PyPI będzie może kiedy indziej. Przyznam się także, że bardzo się zdziwiłem tym, że pip
nie umożliwia separacji bibliotek dla każdego projektu i potrzebna jest do tego instalacja specjalnej paczki. Dziwne, mam inne doświadczenia jeśli chodzi o PHP i JS. Obstawiam, że to przez jakieś zaszłości historyczne.