Python jest jednym z najpopularniejszych języków programowania. Jest to język interpretowalny. Wiąże się z tym konieczność zainstalowania interpretera tego języka na naszym systemie operacyjnym. Umiejętność zarządzania wieloma wersjami interpretera języka Python w systemie Linux (i nie tylko) jest niezbędna dla każdego administratora sieci oraz programisty. Linux, dzięki swojej elastyczności i otwartości, oferuje szereg metod na równoczesne utrzymywanie kilku wersji Pythona, co umożliwia efektywne zarządzanie zależnościami projektu i uniknięcie konfliktów. W tym artykule odpowiemy sobie na pytanie, w jaki sposób efektywnie zarządzać takim środowiskiem. 

Dlaczego wiele wersji Pythona się przydaje? 

Istnieje szereg wymagań, ale także zalet, związanych z tym, że na pojedynczym systemie operacyjnym możemy mieć zainstalowanych wiele wersji interpretera języka Python jednocześnie. Dzięki takiemu podejściu możemy bez przeszkód pracować nad starszymi projektami, które wymagają wcześniejszych wersji Pythona, jednocześnie eksplorując nowe możliwości oferowane przez najnowsze wersje języka. Jeszcze rok czy dwa lata temu było to niezwykle istotne, ponieważ wiele projektów wspierało jedynie język Python w wersji 2. Ta stara wersja od dłuższego czasu nie jest już rozwijana, a nawet wspierana przez producentów i wszystkie aktywne projekty chyba już zdążyły z migrować do Pythona w wersji 3. Kiedy Python 3 został wprowadzony po raz pierwszy w 2008 roku, stanowił znaczący krok naprzód w rozwoju języka. Jednak wprowadzone zmiany nie były w pełni kompatybilne wstecz z Pythonem 2, co stworzyło konieczność utrzymywania obu wersji w wielu środowiskach programistycznych. Python 3 wprowadził wiele zmian w składni, które nie są kompatybilne z Pythonem 2. Na przykład, print stał się funkcją (tj. print(„hello”) zamiast print „hello”). W Pythonie 2 ciągi znaków były domyślnie traktowane jako bajty, natomiast Python 3 traktuje ciągi znaków jako Unicode. Takich zmian było bardzo dużo, a te głębokie różnice składniowe i semantyczne spowodowały, że wiele istniejących projektów opartych na Pythonie 2 nie mogło być łatwo przeniesionych do nowej wersji bez znaczących modyfikacji. W rezultacie, przez wiele lat obie wersje Pythona były równolegle używane, aby umożliwić stopniowe przejście na nowszą wersję oraz utrzymanie starszych systemów. 

Tyle historii, a jak to wygląda teraz? Posiadając różne wersje Pythona, łatwiej jest testować, czy nasze aplikacje działają poprawnie w różnych środowiskach, co jest kluczowe w procesie ciągłej integracji i wdrażania (CI/CD). Jeżeli spojrzymy na wiele projektów które mają wdrożone automatyczne testy kodu to zauważymy, że w projektach tych testujemy jego zgodność z wieloma wersjami. Dzięki temu mamy pewność, że przygotowany przez nas kod będzie działał z dowolnie wybraną przez użytkownika wersją Pythona lub możemy wskazać, z którymi wersjami jest on kompatybilny. Warto też zauważyć, że różne wersje Pythona mogą zawierać różne optymalizacje, co pozwala na wybór najbardziej efektywnego interpretera dla konkretnego zadania. 

Nie ma jednak róży bez kolców. Różnorodność wersji Pythona może prowadzić do konfuzji i błędów w zarządzaniu zależnościami, jeśli nie zostaną odpowiednio zarządzane przez narzędzia takie jak pyenv lub virtualenv. Pamiętajmy też, że każda instalacja Pythona zajmuje miejsce na dysku, co przy dużej liczbie wersji może stać się problematyczne, szczególnie w środowiskach z ograniczoną przestrzenią dyskową. Ponadto błędne skonfigurowanie ścieżek i zmiennych środowiskowych może prowadzić do nieoczekiwanych konfliktów i błędów w działaniu systemu. 

Python z instalacji Linuxa 

Rzadko się zdarza abyśmy interpreter języka Python instalowali z kodu źródłowego. Zazwyczaj jego wersja bazowa pochodzi od twórców dystrybucji Linuxa, którą wybraliśmy. Oczywiście jesteśmy wtedy uzależnieni od tego, które wersje dostarcza nam wydawca naszej dystrybucji. Zazwyczaj jednak dysponujemy co najmniej kilkoma wersjami do wyboru. 

W różnych dystrybucjach Linuksa sposób dostarczania i zarządzania różnymi wersjami interpretera Python może się znacząco różnić, co jest odzwierciedleniem filozofii oraz celów poszczególnych dystrybucji. Przykładowo, dystrybucje takie jak Ubuntu i Debian dostarczają w swoich repozytoriach oficjalne pakiety dla kilku wersji Pythona, które użytkownicy mogą zainstalować jednocześnie. Dzieje się tak, ponieważ te systemy używają systemu zarządzania pakietami, jak dpkg, który pozwala na instalację wielu wersji tego samego oprogramowania bez konfliktów, o ile pakiety są odpowiednio skonfigurowane. Z kolei w dystrybucjach takich jak Fedora czy openSUSE, zazwyczaj dostępna jest najnowsza stabilna wersja Pythona, ale użytkownicy mogą również zainstalować starsze wersje poprzez dedykowane repozytoria lub pakiety. To pozwala na łatwe przełączanie między wersjami lub uruchamianie różnych aplikacji wymagających określonych wersji interpretera. 

Dystrybucje Linuxa często korzystają także z narzędzi takich jak alternatives system, które umożliwiają zarządzanie wieloma wersjami tego samego programu przez ustawianie domyślnych ścieżek i priorytetów dla wykonywalnych plików. Dzięki temu użytkownicy mogą wybierać, która wersja Pythona ma być używana jako domyślna w danym momencie, nie zakłócając przy tym pracy innych wersji. 

W Ubuntu, Debianie czy Fedorze pakiety związane z Pythonem zwykle zaczynają się od przedrostka python dla Pythona 2 i python3 dla Pythona 3, co ułatwia identyfikację, które pakiety są przeznaczone dla której wersji Pythona. Dla przykładu: 

  • python2.7 – pakiet dla Pythona 2.7 
  • python3.11 – pakiet dla Pythona 3.11 

Oprócz samego interpretera znajdziemy też pakiety z bibliotekami czy frameworkami. Rozpoznamy je poprzez dodanie do nazwy interpretera nazwy samej biblioteki, na przykład python3-numpy. Oprócz tego, w systemach Debian i Ubuntu często stosuje się meta-pakiety, które pozwalają na instalację grupy pakietów powiązanych z określoną wersją Pythona. Na przykład python3-dev to meta-pakiet, który instaluje wszystkie narzędzia i biblioteki potrzebne do kompilacji modułów Pythona 3. 

Zmiana domyślnej wersji Pythona 

W systemach Ubuntu, Debian oraz Fedora istnieją narzędzia i metody, które umożliwiają wybranie domyślnej wersji interpretera Python. W Ubuntu i Debianie można skorzystać z narzędzia update-alternatives, które zarządza różnymi wersjami programów, w tym interpreterem Python. Aby zarządzać wersjami Pythona, najpierw musimy je dodać do systemu alternatyw. 

sudo update-alternatives –install /usr/bin/python python /usr/bin/python3.11 1 

sudo update-alternatives –install /usr/bin/python python /usr/bin/python3.9 2 

Następnie możemy wybrać domyślną wersję interpretera wydając polecenie sudo update-alternatives –config python. Wyświetli ono listę dostępnych wersji Pythona i pozwoli wybrać domyślną poprzez wpisanie odpowiedniego numeru. 

W Fedorze zarządzanie wersjami Pythona jest nieco inne, ze względu na wykorzystywanie nowocześniejszego podejścia. Fedora korzysta z systemu modułów, który pozwala na instalację różnych wersji oprogramowania. Możemy zainstalować specyficzną wersję Pythona, korzystając z DNF. 

sudo dnf module install python3.9 

W Fedorze zamiast update-alternatives używane mogą być skrypty powłoki do ustawiania zmiennych środowiskowych lub symbolicznych dowiązań (symbolic links). Możesz na przykład stworzyć dowiązanie wskazujące na preferowaną wersję Pythona: 

sudo ln -sf /usr/bin/python3.9 /usr/bin/python 

Te metody pozwalają na elastyczne zarządzanie różnymi wersjami Pythona na różnych dystrybucjach Linuxa, co jest szczególnie przydatne w środowiskach deweloperskich i produkcyjnych, gdzie różne projekty mogą wymagać różnych wersji interpretera. Pamiętajmy jednak, aby sprawdzić czy mamy w wybranej przez nas domyślnej wersji interpretera zainstalowane globalnie wszystkie niezbędne biblioteki do działania naszych skryptów. 

Środowiska wirtualne 

Majstrowanie przy zainstalowanych z pakietów bibliotekach oraz wersjach języka Python może na nas sprowadzić problemy. Pamiętajmy, że wszystko to co jest dostępne globalnie jest dostępne dla wszystkich naszych użytkowników. Zatem zmieniając wersję interpretera możemy pozbawić użytkownika korzystania ze stworzonego przez niego skryptu. Dodatkowo miejmy na uwadze, że użytkownicy sami nie są w stanie doinstalować niezbędnych do działania ich skryptu bibliotek globalnie, bez uprawnień administratora. Nie wszystkie biblioteki są dostarczane także przez twórców samych dystrybucji Linuksa zawartych w przygotowanych przez nich pakietach. Wiele z nich instalujemy z repozytorium PyPi. 

Środowiska wirtualne pozwalają na tworzenie izolowanych przestrzeni dla różnych projektów, dzięki czemu każdy z nich może mieć własne, niezależne biblioteki i wersje interpretera, co jest szczególnie przydatne w rozbudowanych lub różnorodnych środowiskach deweloperskich. Każde środowisko wirtualne jest oddzielne i nie wpływa na inne projekty ani na globalne ustawienia systemu. Dzięki temu możemy uniknąć konfliktów zależności między projektami. Możemy specyfikować i zarządzać wersjami bibliotek, które są potrzebne dla danego projektu. To pozwala na łatwe przetestowanie nowych wersji bibliotek, bez ryzyka zaburzenia działania innych aplikacji. Środowiska wirtualne ułatwiają też zarządzanie zależnościami, szczególnie w dużych zespołach programistycznych, gdzie różni deweloperzy mogą pracować nad różnymi aspektami tego samego projektu. 

Dwa najpopularniejsze, i jednocześnie najprostsze w obsłudze, środowiska wirtualne w Python to venv oraz virtualenv. Oba z nich opierają się na tej samej ideologii i zasadzie działania, przy czym pierwsze z nich jest standardową częścią języka Python 3, drugi zaś pochodzi z Pythona 2. 

Utworzenie wirtualnego środowiska za pomocą venv jest dziecinnie proste. Na początek musimy globalnie zainstalować bibliotekę venv za pomocą managera pakietów. Na Ubuntu wydamy polecenie: 

sudo apt install python3.11-venv 

Następnie w wybranym folderze wydajemy dwa polecenia: 

python3 -m venv py311-venv 

source py311-venv/bin/activate 

Pierwsze z nich spowoduje utworzenie nowego środowiska wirtualnego w katalogu py311-venv. Zostanie on utworzone na bazie domyślnej wersji interpretera ustawionego dla naszego rynku systemu. Jeżeli chcemy wybrać inną wersję interpretera spośród zainstalowanych musimy wywołać moduł venv z poziomu wskazanego interpretera. Przykładowo, jeżeli oprócz wersji 3.11 mam zainstalowaną wersję 3.10, która nie jest domyślną, to aby utworzyć środowisko wirtualne w wersji 3.10 wydam polecenie: 

python3.10 -m venv py310-venv 

Drugie polecenie, activate, spowoduje aktywację wskazanego środowiska. O tym, że pracujemy w środowisku wirtualnym nie zaś korzystając z globalnej instalacji Pythona dowiemy się analizując prompt wiersza poleceń. Zostanie on uzupełnione o nazwę wirtualnego środowiska na samym początku, na przykład: 

(py310-venv) piotr@rpi-1:~/moj_projekt$ 

Aby deaktywować środowisko wydajemy polecenie deactivate. Wewnątrz wirtualnego środowiska pakietami zarządzamy za pomocą managera pip. 

Wirtualne środowisko venv jest proste i efektywne, dla mnie od wielu lat wystarczające. Warto jednak wspomnieć o innych bardziej rozbudowanych alternatywach. Conda to zarządzane, wieloplatformowe narzędzie, które służy do instalowania, uruchamiania i aktualizowania pakietów oraz ich zależności. Jest szczególnie popularne w społeczności naukowej, gdzie zarządzanie złożonymi zależnościami jest kluczowe. Pipenv łączy zarządzanie pakietami z pip i zarządzanie wirtualnymi środowiskami w jednym narzędziu. Automatyzuje proces tworzenia i zarządzania środowiskami wirtualnymi oraz dodaje Pipfile i Pipfile.lock do zarządzania zależnościami. Poetry zaś jest narzędziem służącym do zarządzania zależnościami i tworzeniem własnych pakietów z bibliotekami w Pythonie, które również obsługuje zarządzanie wirtualnymi środowiskami. Jest to nowoczesne narzędzie, które zapewnia deterministyczne budowanie projektów dzięki plikom pyproject.toml i poetry.lock

Zainteresował Cię ten artykuł i chcesz dowiedzieć się więcej o automatyzacji z wykorzystaniem języka Python lub innych narzędzi? Koniecznie sprawdź portal Szkoła DevNet (https://szkoladevnet.pl) prowadzony przez Piotra, a także z przygotowanymi przez niego szkoleniami on-line (https://showroute.pl/edu/) między innymi z automatyzacji z wykorzystaniem Python i Ansible.