Cum să scrieți, să împachetați și să distribuiți o bibliotecă în Python

Python este un limbaj de programare excelent, dar ambalajul este unul dintre punctele sale cele mai slabe. Este un fapt cunoscut în comunitate. Instalarea, importarea, utilizarea și crearea pachetelor s-au îmbunătățit foarte mult de-a lungul anilor, dar încă nu seamănă cu limbi mai noi, cum ar fi Go și Rust, care au învățat multe din luptele lui Python și alte limbi mature. 

În acest tutorial, veți afla tot ce trebuie să știți despre scrierea, ambalarea și distribuirea propriilor pachete. 

Cum se scrie o Bibliotecă Python

O bibliotecă Python este o colecție coerentă de module Python care este organizată ca un pachet Python. În general, aceasta înseamnă că toate modulele se află sub același director și că acest director se află pe calea de căutare Python. 

Să scriem rapid un mic pachet Python 3 și să ilustrăm toate aceste concepte.

Pachetul de patologie

Python 3 are un obiect excelent Path, ceea ce reprezintă o îmbunătățire imensă față de modulul aw.path al lui Python 2. Dar lipsește o capacitate crucială de a găsi calea scenariului curent. Acest lucru este foarte important atunci când doriți să găsiți fișierele de acces în raport cu scriptul curent. 

În multe cazuri, scriptul poate fi instalat în orice locație, astfel încât să nu puteți utiliza căi absolute, iar directorul de lucru poate fi setat la orice valoare, astfel încât să nu puteți utiliza o cale relativă. Dacă doriți să accesați un fișier dintr-un director sau un director părinte, trebuie să știți directorul curent al scriptului. 

Iată cum faceți acest lucru în Python:

importul pathlib script_dir = pathlib.Path (__ fișierul __) parent.resolve ()

Pentru a accesa un fișier numit 'file.txt' într-un subdirector 'data' din directorul scriptului curent, puteți folosi următorul cod: Print (deschis (str (script_dir / 'date / fisier.txt'). citește ())

Cu pachetul de patologie, aveți un built-in script_dir și îl utilizați astfel:

de la pathology.Path import script_dir print (deschide (str (script_dir () / 'data / file.txt'). 

Da, eo gură. Pachetul de patologie este foarte simplu. Ea își derivă propria clasă de cale din calea lui Pathlib și adaugă o statică script_dir () care întotdeauna întoarce calea scriptului de asteptare. 

Iată implementarea:

import pathlib import inspectați calea de clasă (tip (pathlib.Path ())): @staticmethod def script_dir (): print (inspect.stack () [1] .filename) p = pathlib.Path (inspect.stack ] .filename) return p.parent.resolve () 

Datorită implementării cross-platform a pathlib.Path, puteți obține direct din ea și trebuie să provină dintr-o anumită subclase (PosixPath sau WindowsPath). Rezoluția dir de script utilizează modulul de inspectare pentru a găsi apelantul și apoi atributul său de nume de fișier.

Testarea pachetului de patologie

Ori de câte ori scrieți ceva care este mai mult decât un script de aruncare, ar trebui să îl testați. Modulul de patologie nu este o excepție. Iată testele care utilizează cadrul de testare standard al unității: 

import os import shutil din unitatetest importCacheCath din patologie.path import Calea de cale PathTest (TestCase): def test_script_dir (auto): expected = os.path.abspath (os.path.dirname (__ file__)) actual = str (Path.script_dir (de exemplu, script_dir, 'test_data'), în cazul în care calea (path_dir) (subdir) .is_dir (): shutil.rmtree (subdir) os.makedirs (subdir) file_path = str (Path (subdir) / 'file.txt') content = '123' deschis (conținutul) test_path = Path.script_dir () / subdir / 'file.txt' actual = deschide (str (test_path)) read () self.assertEqual 

Calea Python

Pachetele Python trebuie instalate undeva pe calea de căutare Python pentru a fi importate de modulele Python. Calea de căutare Python este o listă de directoare și este întotdeauna disponibilă în sys.path. Aici este sys.path actual:

>>> print ('\ n'.join (sys.path)) /Users/gigi.sayfan/miniconda3/envs/py3/lib/python36.zip/Users/gigi.sayfan/miniconda3/envs/py3/lib/ python3.6 /Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/lib-dynload/Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/site-packages / Utilizatori / gigi.sayfan / miniconda3 / envs / py3 / lib / python3.6 / site-ul pachete / setuptools-27.2.0-py3.6.egg 

Rețineți că prima linie goală a ieșirii reprezintă directorul curent, astfel încât să puteți importa module din directorul de lucru curent, indiferent de ce este. Puteți adăuga sau elimina direct directoarele la / de la sys.path. 

De asemenea, puteți defini a PYTHONPATH variabila de mediu, și există câteva alte modalități de a controla. Standardul site-ul pachetelor este inclus în mod implicit, și aici se află pachetele pe care le instalați folosind pip pip. 

Cum să pachet o Bibliotecă Python

Acum, că avem codul și testele noastre, să le punem pe toate într-o bibliotecă adecvată. Python oferă o cale ușoară prin modulul de configurare. Creați un fișier numit setup.py în directorul rădăcină al pachetului. Apoi, pentru a crea o distribuție sursă, executați: python setup.py sdist

Pentru a crea o distribuție binară numită roată, rulați: python setup.py bdist_wheel

Aici este fișierul setup.py al pachetului de patologie:

de la setuptools import setup, find_packages setup (name = 'pathology', version = "0.1", author = "Gigi Sayfan" , author_email = "[email protected]", description = "Adauga metodă statică script_dir () la cale", packages = find_packages (exclude = ['tests']), long_description = open ('README.md'). read (), zip_safe = False)

Acesta include o mulțime de metadate în plus față de elementul "pachete" care utilizează find_packages () funcția importată din setuptools pentru a găsi subpachete.

Să construim o distribuție sursă:

$ python setup.py sdist rulează sdist rulează egg_info creând pathology.egg-info scriind pathology.egg-info / PKG-INFO scriind dependency_links la patologie.egg-info / dependency_links.txt scriind nume de nivel superior în patology.egg-info / top_level.txt scrierea fișierului manifest "patology.egg-info / SOURCES.txt" citirea fișierului manifest "patology.egg-info / SOURCES.txt" scrierea fișierului manifest "patology.egg-info / SOURCES.txt" avertisment: sdist: standard fișierul nu a fost găsit: ar trebui să aibă unul dintre README, README.rst, README.txt care rulează verificând crearea patologiei-0.1 crearea patologiei-0.1 / patologie creare patologie-0.1 / pathology.egg-info copierea fișierelor în patologie-0.1 ... copierea setup.py -> patologie-0.1 patologie / __ init__.py -> patologie-0.1 / patologie copiatoare patologie / path.py -> patologie-0.1 / patologie copiere pathology.egg-info / PKG-INFO -> patologie-0.1 / pathology.egg -info copierea patologiei.egg-info / SOURCES.txt -> patologie-0.1 / pathology.egg-info copying pathology.egg-info / dependency_links.txt -> patologie -0.1 / pathology.egg-info copiatoare patologie.egg-info / non-zip-safe -> patologie-0.1 / pathology.egg-info copying pathology.egg-info / top_level.txt -> patologie-0.1 / pathology.egg -info Scrierea patologiei-0.1 / setup.cfg creare dist Crearea arhivei tar care elimina 'patologie-0.1' (si totul sub ea)

Avertizarea se datorează faptului că am folosit un fișier README.md non-standard. Este în siguranță să ignori. Rezultatul este un fișier tar-gzipped sub directorul dist:

$ ls -la dist total 8 drwxr-xr-x 3 gigi.sayfan gigi.sayfan 102 18 aprilie 21:20. drwxr-xr-x 12 gigi.sayfan gigi.sayfan 408 Apr 18 21:20 ... -rw-r-r-- 1 gigi.sayfan gigi.sayfan 1223 18 apr. 21:20 patologie-0.1.tar.gz

Și aici este o distribuție binară:

$ python setup.py bdist_wheel rulează bdist_wheel rulează construire execută build_py construiește construiește crearea / lib crearea build / lib / patologie copierea patologiei / __ init__.py -> build / lib / patologie copierea patologiei / path.py -> build / lib / pathology instalarea pentru a construi / bdist.macosx-10.7-x86_64 / rolă execută instalarea rulează install_lib creare build / bdist.macosx-10.7-x86_64 / build bdist.macosx-10.7-x86_64 / router / patologie copiere build / lib / pathology / __ init__.py -> build / bdist.macosx-10.7-x86_64 / rularea / patologia care rulează install_egg_info rulează egg_info scrierea patologiei.egg-info / PKG-INFO scrierea dependency_links la patologie.egg-info / dependency_links.txt scrierea numelor de nivel superior în patology.egg-info / top_level.txt citirea fișierului manifest "patologie. egg-info / SOURCES.txt "scrierea fișierului manifest" pathology.egg-info / SOURCES.txt "Copierea patologiei.egg-info la bui ld / bdist.macosx-10.7-x86_64 / roată / patologie-0.1-py3.6.egg-info care rulează install_scripts creând build / bdist.macosx-10.7-x86_64 / wheel / pathology-0.1.dist-info / WHEEL

Pachetul de patologie conține numai module Python pure, astfel încât poate fi construit un pachet universal. Dacă pachetul include extensii C, va trebui să construiți o roată separată pentru fiecare platformă:

$ ls -la dist total 16 drwxr-xr-x 4 gigi.sayfan gigi.sayfan 136 Apr 18 21:24. drwxr-xr-x 13 gigi.sayfan gigi.sayfan 442 Apr 18 21: 24 ... -rw-r-r-- 1 gigi.sayfan gigi.sayfan 2695 Apr 18 21:24 patologie-0.1-py3-none-orice .whl -rw-r-r-- 1 gigi.sayfan gigi.sayfan 1223 18 apr. 21:20 patologie-0.1.tar.gz 

Pentru o scufundare mai profundă în tema de ambalare a bibliotecilor Python, consultați Cum să scrieți propriile pachete Python.

Cum să distribuiți un pachet Python

Python are un depozit central de pachete numit PyPI (Python Packages Index). Când instalați un pachet Python utilizând pip, acesta va descărca pachetul din PyPI (dacă nu specificați un depozit diferit). Pentru a distribui pachetul nostru de patologie, trebuie să îl încărcăm în PyPI și să oferim unele metadate suplimentare pe care PyPI le cere. Pașii sunt:

  • Creați un cont pe PyPI (o singură dată).
  • Înregistrați-vă pachetul.
  • Încărcați pachetul.

Creează un cont

Puteți crea un cont pe site-ul PyPI. Apoi creați o .pypirc fișier în directorul de acasă:

[distutils] index-servers = pypi [pypi] repository = https://pypi.python.org/pypi username = the_gigi 

În scopuri de testare, puteți adăuga un server de index "pypitest" la dvs. .pypirc fişier:

[distutils] index-servere = pypi pypitest [pypitest] repository = https://testpypi.python.org/pypi username = the_gigi [pypi] repository = https://pypi.python.org/pypi username = the_gigi

Înregistrați-vă pachetul

Dacă aceasta este prima versiune a pachetului, trebuie să îl înregistrați cu PyPI. Utilizați comanda de înregistrare a setup.py. Vă va cere parola. Rețineți că îl îndrept în depozitul de testare aici:

$ python setup.py registru -r pypitest registru de funcționare running egg_info writing pathology.egg-info / PKG-INFO scrierea dependency_links la patology.egg-info / dependency_links.txt scrierea numelor de nivel superior la pathology.egg-info / top_level.txt citirea fișierului manifestului "pathology.egg-info / SOURCES.txt" scrierea fișierului manifest "patology.egg-info / SOURCES.txt" verificarea parolei: înregistrarea patologiei la https://testpypi.python.org/pypi răspunsul serverului (200 ): O.K

Încărcați pachetul

Acum că pachetul este înregistrat, îl putem încărca. Vă recomandăm să utilizați sfoară, care este mai sigură. Instalați-l ca de obicei folosind introduceți sfoară. Apoi încărcați pachetul utilizând sfoară și introduceți parola (redată mai jos):

încărcați sfoară $ -r pypitest -p  dist / * Încărcarea distribuțiilor la https://testpypi.python.org/pypi Încărcarea patologiei-0.1-py3-none-any.whl [==================== ============] 5679/5679 - 00:00:02 Încărcarea patologiei-0.1.tar.gz [=================== =============] 4185/4185 - 00:00:01 

Pentru o scufundare mai profundă în subiectul distribuirii pachetelor, consultați modul de partajare a pachetelor Python.

Concluzie

În acest tutorial, am parcurs procesul de scriere a unei biblioteci Python, ambalarea acesteia și distribuirea acesteia prin PyPI. În acest moment, ar trebui să aveți toate instrumentele necesare pentru a scrie și a vă împărtăși bibliotecile cu lumea.

În plus, nu ezitați să vedeți ce avem disponibile pentru vânzare și pentru a studia pe piață și vă rugăm să întrebați orice întrebări și să oferiți feedback-ul dvs. valoros folosind feed-ul de mai jos.

Cod