Hvordan skrive, pakke og distribuere et bibliotek i python

Python er et bra programmeringsspråk, men emballasje er et av de svakeste punktene. Det er et velkjent faktum i samfunnet. Installere, importere, bruke og lage pakker har forbedret seg mye gjennom årene, men det er fortsatt ikke på nivå med nyere språk som Go and Rust som lærte mye fra Pythons og andre modne språk. 

I denne opplæringen lærer du alt du trenger å vite om å skrive, pakke og distribuere dine egne pakker. 

Hvordan skrive et pythonbibliotek

Et Python-bibliotek er en sammenhengende samling av Python-moduler som er organisert som en Python-pakke. Generelt betyr det at alle modulene bor under samme katalog, og at denne katalogen er på Python-søkebanen. 

La oss skrive en liten Python 3-pakke og illustrere alle disse konseptene.

Patologisk pakke

Python 3 har et utmerket Path-objekt, noe som er en stor forbedring over Python 2's ubehagelige OS.path-modul. Men det mangler en viktig evne - å finne banen til det nåværende skriptet. Dette er svært viktig når du vil finne tilgangsfiler i forhold til gjeldende skript. 

I mange tilfeller kan man installere skriptet på alle steder, slik at du ikke kan bruke absolutte baner, og arbeidskatalogen kan settes til hvilken som helst verdi, slik at du ikke kan bruke en relativ bane. Hvis du vil ha tilgang til en fil i en underkatalog eller en overordnet katalog, må du kunne finne ut det gjeldende skriptkatalogen. 

Slik gjør du det i Python:

import pathlib script_dir = pathlib.Path (__ file __). parent.resolve ()

For å få tilgang til en fil som heter 'file.txt' i en 'data' underkatalog i det aktuelle skriptets katalog, kan du bruke følgende kode: print (åpen (str (script_dir / 'data / fil.txt'). lese ())

Med patologisk pakken har du en innebygd script_dir metode, og du bruker den slik:

fra patologi.Pat import script_dir print (åpne (str (script_dir () / 'data / file.txt'). les ()) 

Ja, det er en munnfull. Patologipakken er veldig enkel. Den kommer fra sin egen baneklasse fra stien og legger til en statisk script_dir () som alltid returnerer banen til kallet skriptet. 

Her er implementeringen:

import pathlib import inspisere klassebane (type (pathlib.Path ())): @staticmethod def script_dir (): print (inspect.stack () [1] .filnavn) p = pathlib.Path (inspect.stack () [1 ] .filnavn) returnere p.parent.resolve () 

På grunn av plattformsimplementeringen av pathlib.Path, du kan utlede direkte fra det og må stammer fra en bestemt underklasse (PosixPath eller WindowsPath). Skriptdir-oppløsningen bruker inspeksjonsmodulen til å finne den som ringer og deretter filnavnet.

Testing av patologisk pakke

Når du skriver noe som er mer enn et throwaway script, bør du teste det. Patologimodulen er ikke noe unntak. Her er testene ved hjelp av standard enhetstestrammen: 

import oss importere shutil fra unittest import TestCase fra pathology.path import Path class PathTest (TestCase): def test_script_dir (selv): forventet = os.path.abspath (os.path.dirname (__ file__)) actual = str (Path.script_dir ()) selv.assertEkvivalent (forventet, faktisk) def test_file_access (selv): script_dir = os.path.abspath (os.path.dirname (__ file__)) subdir = os.path.join (script_dir, 'test_data') hvis sti (subdir) .is_dir (): shutil.rmtree (subdir) os.makedirs (subdir) file_path = str (Sti (subdir) / 'file.txt') content = '123' åpen (file_path, 'w'). (innhold) test_path = Path.script_dir () / subdir / 'file.txt' actual = open (str (test_path)) .les () self.assertEqual (innhold, faktisk) 

Python-banen

Python-pakker må installeres et sted på Python-søkebanen som skal importeres av Python-moduler. Python-søkebanen er en liste over kataloger og er alltid tilgjengelig i sys.path. Her er min nåværende sysepath:

>>> 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 / Brukere / gigi.sayfan / miniconda3 / envs / pY3 / lib / python3.6 / site-pakker / setuptools-27.2.0-py3.6.egg 

Merk at den første tomme linjen i utgangen representerer gjeldende katalog, slik at du kan importere moduler fra den nåværende arbeidsboken, uansett hva den er. Du kan direkte legge til eller fjerne kataloger til / fra sys.path. 

Du kan også definere en PYTHONPATH miljøvariabel, og der noen andre måter å kontrollere den på. Standarden site-pakker er inkludert som standard, og dette er hvor pakker du installerer bruker via pip go. 

Slik pakker du et Python-bibliotek

Nå som vi har vår kode og tester, la oss pakke alt sammen til et riktig bibliotek. Python gir en enkel måte via oppsettmodulen. Du oppretter en fil som heter setup.py i pakkenes rotkatalog. Så, for å opprette en kildefordeling kjører du: python setup.py sdist

For å opprette en binær distribusjon kalt et hjul kjører du: python setup.py bdist_wheel

Her er setup.py-filen til patologipakken:

fra setuptools importoppsett, find_packages setup (navn = 'patologi', versjon = "0.1", url = "https://github.com/the-gigi/pathology", license = "MIT", forfatter = "Gigi Sayfan" , author_email = "[email protected]", description = "Legg til statisk script_dir () metode til sti", pakker = find_packages (ekskluder = ['tester']), long_description = open ('README.md'). les (), zip_safe = False)

Den inneholder mye metadata i tillegg til "pakker" -elementet som bruker find_packages () funksjon importert fra setuptools for å finne delpakker.

La oss bygge en kildefordeling:

$ python setup.py sdist kjører sdist kjører egg_info skaper patologi.egg-info skriving pathology.egg-info / PKG-INFO skriver dependency_links til pathology.egg-info / dependency_links.txt skriver toppnivå navn til pathology.egg-info / top_level.txt skriftlig manifestfil 'pathology.egg-info / SOURCES.txt' lesings manifestfil 'pathology.egg-info / SOURCES.txt' skriver manifestfil 'pathology.egg-info / SOURCES.txt' advarsel: sdist: standard fil ikke funnet: burde ha en av README, README.rst, README.txt løpekontroll lage patologi-0.1 lage patologi-0.1 / patologi lage patologi-0.1 / pathology.egg-info kopiere filer til patologi-0.1 ... kopiering setup.py -> patologi-0,1 kopiering patologi / __ init__.py -> patologi-0.1 / patologi kopiering patologi / path.py -> patologi-0.1 / patologi kopiering patologi.egg-info / PKG-INFO -> patologi-0.1 / patology.egg -info kopiering patologi.egg-info / SOURCES.txt -> patologi-0.1 / patology.egg-info kopiering patologi.egg-info / dependency_links.txt -> patologi -0.1 / patology.egg-info kopiering patologi.egg-info / ikke-zip-safe -> patologi-0.1 / patology.egg-info kopiering patologi.egg-info / top_level.txt -> patologi-0.1 / patology.egg -info Skrivepatologi-0.1 / setup.cfg create dist Opprette tararkiv fjerner 'patologi-0.1' (og alt under det)

Advarselen er fordi jeg brukte en ikke-standard README.md-fil. Det er trygt å ignorere. Resultatet er en tar-gzipped-fil under dist-katalogen:

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

Og her er en binær distribusjon:

$ python setup.py bdist_wheel kjører bdist_wheel kjører bygge kjører build_py opprett bygge bygge oppbygging / lib lage / lib / patologi kopiering patologi / __ init__.py -> bygge / lib / patologi kopiering patologi / path.py -> bygge / lib / patologi installerer for å bygge / bdist.macosx-10.7-x86_64 / hjul kjører installerer kjører install_lib skaper build / bdist.macosx-10.7-x86_64 lage build / bdist.macosx-10.7-x86_64 / hjuloppretting build / bdist.macosx-10.7-x86_64 / kopi / lib / patologi / __ init__.py -> build / bdist.macosx-10.7-x86_64 / hjul / patologi kopiering build / lib / pathology / path.py -> build / bdist.macosx-10.7-x86_64 / hjul / patologi kjører install_egg_info kjører egg_info skrive pathology.egg-info / PKG-INFO skrive dependency_links til pathology.egg-info / dependency_links.txt skrive toppnivå navn til pathology.egg-info / top_level.txt lese manifest fil 'patologi. egg-info / SOURCES.txt 'skriftlig manifest fil' pathology.egg-info / SOURCES.txt 'Kopierer pathology.egg-info til bui ld / bdist.macosx-10.7-x86_64 / hjul / patologi-0.1-py3.6.egg-info kjører install_scripts lage build / bdist.macosx-10.7-x86_64 / hjul / patologi-0.1.dist-info / WHEEL

Patologipakken inneholder bare rene Python-moduler, slik at en universell pakke kan bygges. Hvis pakken inneholder C-utvidelser, må du bygge et eget hjul for hver plattform:

$ ls -la dist totalt 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 patologi-0.1-py3-none-any .whl -rw-r - r-- 1 gigi.sayfan gigi.sayfan 1223 apr 18 21:20 patologi-0.1.tar.gz 

For en dypere dykk inn i emnet for å pakke Python-biblioteker, sjekk ut hvordan du skriver dine egne pythonpakker.

Slik distribuerer du en Python-pakke

Python har et sentralt pakkelager kalt PyPI (Python Packages Index). Når du installerer en Python-pakke med pip, laster den pakken fra PyPI (med mindre du angir et annet lagringssted). For å distribuere vår patologiske pakke må vi laste den opp til PyPI og gi noen ekstra metadata PyPI krever. Trinnene er:

  • Opprett en konto på PyPI (bare en gang).
  • Registrer din pakke.
  • Last opp pakken.

Opprett en konto

Du kan opprette en konto på PyPI-nettsiden. Deretter oppretter du en .pypirc fil i din hjemmekatalog:

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

For testformål kan du legge til en "pypitest" indeksserver til din .pypirc fil:

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

Registrer din pakke

Hvis dette er den første utgivelsen av pakken din, må du registrere den med PyPI. Bruk registerkommandoen til setup.py. Det vil spørre deg om passordet ditt. Vær oppmerksom på at jeg peker det til testregisteret her:

$ python setup.py register -r pypitest kjøreregistrering kjører egg_info skrive pathology.egg-info / PKG-INFO skrive dependency_links til pathology.egg-info / dependency_links.txt skrive toppnivå navn til pathology.egg-info / top_level.txt lesing manifest fil 'pathology.egg-info / SOURCES.txt' skriver manifest fil 'pathology.egg-info / SOURCES.txt' kjører sjekke Passord: Registrering av patologi til https://testpypi.python.org/pypi Serverrespons (200 ): OK

Last opp pakken

Nå som pakken er registrert, kan vi laste den opp. Jeg anbefaler å bruke twine, som er sikrere. Installer den som vanlig ved å bruke pip installasjon twine. Last opp pakken din med twine og oppgi passordet ditt (redigeres nedenfor):

$ twine opplasting -r pypitest -p  dist / * Uploading distribusjoner til https://testpypi.python.org/pypi Uploading pathology-0.1-py3-none-any.whl [=================== ============] 5679/5679 - 00:00:02 Laster opp patologi-0.1.tar.gz [================== =============] 4185/4185 - 00:00:01 

For en dypere dykk inn i emnet for å distribuere pakkene dine, se hvordan du deler dine Python-pakker.

Konklusjon

I denne opplæringen gikk vi gjennom den fullverdige prosessen med å skrive et Python-bibliotek, pakke det og distribuere det gjennom PyPI. På dette tidspunktet bør du ha alle verktøyene for å skrive og dele biblioteker med verden.

I tillegg, ikke nøl med å se hva vi har tilgjengelig for salg og for studier på markedet, og vær så snill å stille spørsmål og gi din verdifulle tilbakemelding ved å bruke feedet under.