12. Medii virtuale și pachete
*****************************


12.1. Introducere
=================

Aplicațiile Python folosesc adesea pachete și module care nu fac parte
din biblioteca standard. În diverse situații, o aplicație necesită o
versiune anumită a unei biblioteci, dat fiind că aplicația în cauză se
bazează pe faptul că o defecțiune de cod, din bibliotecă, a fost
corectată în versiunea respectivă sau, dimpotrivă, codul aplicației a
fost realizat cu elemente dintr-o versiune depășită a interfeței
bibliotecii în cauză.

De aceea, se poate întâmpla ca o singură instalare a sistemului Python
în calculatorul dumneavoastră să nu poată îndeplini în totalitate
cerințele tuturor aplicațiilor pe care intenționați să le folosiți.
Dacă, să zicem, aplicația A necesită versiunea 1.0 a modulului
*cutare* pe când aplicația B solicită prezența versiunii 2.0 a
respectivului modul, atunci cerințele intră în conflict una cu
cealaltă, deci, indiferent pe care dintre versiuni am instala-o, una
din aplicațiile A, B nu va putea funcționa.

Soluția unei asemenea probleme este să creăm un *mediu virtual*, adică
un *arbore* de directoare în care să se găsească o instalare (auto-
conținută) completă a sistemului Python corespunzând unei *versiuni*
precizate a Python-ului, instalare căreia să îi fie adăugate un număr
de pachete de interes particular.

Astfel, aplicații diferite vor putea fi rulate în medii virtuale
diferite. Ca o rezolvare a conflictului de cerințe din exemplul
anterior, aplicația A va putea dispune de propriul mediu virtual, în
care a fost instalată versiunea 1.0 a modulului respectiv, în timp ce
aplicația B va avea la dispoziție alt mediu virtual, cu versiunea 2.0
a aceluiași modul în funcțiune. Presupunând că, în urma unei
actualizări, aplicația B va avea nevoie de versiunea 3.0 a unei
biblioteci oarecare, instalarea ei nu va afecta în niciun fel mediul
aplicației A.


12.2. Crearea de medii virtuale
===============================

Modulul întrebuințat la crearea și administrarea *mediilor virtuale*
(de *execuție*, de *testare*, șamd.) se numește "venv". Acest "venv"
va instala acea versiune de Python pe care o folosim la rularea
comenzii de instalare în terminal (și pe care o putem evidenția cu
opțiunea "--version"). De exemplu, dacă executăm comanda cu
"python3.12", se va instala versiunea 3.12.

Pentru a crea un mediu virtual, decideți-vă asupra unui director în
care să îl plasați, apoi rulați modulul "venv" ca script, furnizându-i
calea de acces către directorul convenabil:

   python -m venv tutorialul_de_python_un_mediu_virtual

Execuția comenzii (de către interpretor) va crea directorul
"tutorialul_de_python_un_mediu_virtual", dacă acesta nu există deja,
apoi va crea și restul (sub)directoarelor sale, în care se vor găsi o
copie a interpretorului de Python și varii fișiere ajutătoare.

O alegere frecventă în privința directorului unui mediu virtual este
dată de ".venv". Un atare nume va face ca directorul să le fie
*ascuns* comenzilor interpretorului de comenzi (de la englezescul, ca
jargon informatic, *shell*) activ în terminalul din care lucrați și,
din acest motiv, să nu le fie obstacol acestora, respectiv el nu va
avea nevoie de explicații despre motivul pentru care există (atunci
când, la câteva luni de la ultima sa folosire, veți fi uitat că face
parte din sistemul de directoare). În plus, alegerea acestui nume va
elimina potențialele conflicte cu fișierele ".env", care conțin
definițiile unor variabile de mediu, cerute de diverse unelte
informatice.

De îndată ce ați creat un mediu virtual, îl puteți *activa*.

În Windows, rulați:

   tutorialul_de_python_un_mediu_virtual\Scripts\activate

În Unix sau MacOS, rulați:

   source tutorialul_de_python_un_mediu_virtual/bin/activate

(Acest script de activare a fost scris pentru interpretorul de comenzi
*bash*. Dacă îl folosiți ca interpretor fie pe **csh** fie pe
**fish**, atunci va trebui să utilizați scripturile corespunzătoare,
"activate.csh" ori "activate.fish".)

Activarea mediului virtual va schimba *promptul* interpretorului de
comenzi pe care îl întrebuințați în terminal pentru a vă informa ce
mediu virtual este în funcțiune, respectiv va modifica mediul pentru
ca rularea comenzii "python" să vă conducă chiar la versiunea
(special) instalată de Python cu care doriți să lucrați. De exemplu:

   $ source ~/envs/tutorialul_de_python_un_mediu_virtual/bin/activate
   (tutorialul_de_python_un_mediu_virtual) $ python
   Python 3.5.1 (default, May  6 2016, 10:59:36)
     ...
   >>> import sys
   >>> sys.path
   ['', '/usr/local/lib/python35.zip', ...,
   '~/envs/tutorialul_de_python_un_mediu_virtual/lib/python3.5/site-packages']
   >>>

Pentru a *dezactiva* un mediu virtual, tastați:

   deactivate

în (linia de comandă din) terminal.


12.3. Administrarea pachetelor cu pip
=====================================

Putem instala, actualiza și elimina pachete cu ajutorul unui program
intitulat **pip**. În mod prestabilit, "pip" instalează pachete
preluate din Python Package Index (adică, *PyPI*; Catalogul pachetelor
Python). Pentru a putea răsfoi catalogul, este suficient să îi
vizitați pagina *web*.

"pip" are un număr de sub-comenzi (cu sintaxa *pip
nume_de_subcomandă*): "install", "uninstall", "freeze", șamd.
(Consultați ghidul Instalarea modulelor Python pentru o documentație
amănunțită referitoare la "pip".)

Puteți instala cea mai recentă versiune a unui pachet (precum *novas*)
specificându-i numele în comanda:

   (tutorialul_de_python_un_mediu_virtual) $ python -m pip install novas
   Collecting novas
     Downloading novas-3.1.1.3.tar.gz (136kB)
   Installing collected packages: novas
     Running setup.py install for novas
   Successfully installed novas-3.1.1.3

De asemeni, puteți instala o anumită versiune a unui pachet
(*requests*) introducându-i numele (în comandă), urmat de un "==" și
de numărul versiunii dorite:

   (tutorialul_de_python_un_mediu_virtual) $ python -m pip install requests==2.6.0
   Collecting requests==2.6.0
     Using cached requests-2.6.0-py2.py3-none-any.whl
   Installing collected packages: requests
   Successfully installed requests-2.6.0

În caz că re-executați comanda, "pip" vă va informa că versiunea
solicitată este deja instalată, după care nu va mai face nimic.
Desigur, pentru a instala altă versiune (a aceluiași pachet), va fi
nevoie să îi introduceți numărul (de versiune) sau veți putea rula
comanda "python -m pip install --upgrade" pentru a *actualiza*
pachetul, punându-i în uz cea mai recentă versiune:

   (tutorialul_de_python_un_mediu_virtual) $ python -m pip install --upgrade requests
   Collecting requests
   Installing collected packages: requests
     Found existing installation: requests 2.6.0
       Uninstalling requests-2.6.0:
         Successfully uninstalled requests-2.6.0
   Successfully installed requests-2.7.0

"python -m pip uninstall" urmat de unul ori de mai multe nume de
pachete va elimina, în urma execuției, pachetele respective din mediul
virtual.

"python -m pip show" va afișa informații despre un pachet precizat:

   (tutorialul_de_python_un_mediu_virtual) $ python -m pip show requests
   ---
   Metadata-Version: 2.0
   Name: requests
   Version: 2.7.0
   Summary: Python HTTP for Humans.
   Home-page: http://python-requests.org
   Author: Kenneth Reitz
   Author-email: me@kennethreitz.com
   License: Apache 2.0
   Location: /Users/akuchling/envs/tutorialul_de_python_un_mediu_virtual/lib/python3.4/site-packages
   Requires:

"python -m pip list" va afișa toate pachetele instalate în mediul
virtual:

   (tutorialul_de_python_un_mediu_virtual) $ python -m pip list
   novas (3.1.1.3)
   numpy (1.9.2)
   pip (7.0.3)
   requests (2.7.0)
   setuptools (16.0)

"python -m pip freeze" va produce o listă asemănătoare celei de
deasupra, cu excepția faptului că formatul acestei liste este identic
celui solicitat de comanda "python -m pip install". O convenție
populară ne spune că lista produsă de *freeze* trebuie să fie salvată
într-un fișier text cu nume sugestiv, precum "cerințe.txt":

   (tutorialul_de_python_un_mediu_virtual) $ python -m pip freeze > cerințe.txt
   (tutorialul_de_python_un_mediu_virtual) $ cat cerințe.txt
   novas==3.1.1.3
   numpy==1.9.2
   requests==2.7.0

În această situație, fișierul "cerințe.txt" va putea fi *comis* către
(baza de date a platformei de ) controlul versiunii, respectiv livrat
(către beneficiari) ca parte a aplicației construite de dumneavoastră.
Drept urmare, utilizatorii acesteia vor putea să își instaleze
pachetele de care are nevoie aplicația folosind "install -r":

   (tutorialul_de_python_un_mediu_virtual) $ python -m pip install -r cerințe.txt
   Collecting novas==3.1.1.3 (from -r cerințe.txt (line 1))
     ...
   Collecting numpy==1.9.2 (from -r cerințe.txt (line 2))
     ...
   Collecting requests==2.7.0 (from -r cerințe.txt (line 3))
     ...
   Installing collected packages: novas, numpy, requests
     Running setup.py install for novas
   Successfully installed novas-3.1.1.3 numpy-1.9.2 requests-2.7.0

"pip" are numeroase alte opțiuni. Consultați ghidul Instalarea
modulelor Python pentru documentația elaborată a lui "pip". Dacă ați
construit deja un pachet Python și doriți să îl faceți disponibil în
catalogul PyPI, vă recomandăm să parcurgeți materialul Python
packaging user guide.
