Python er et fantastisk programmeringsspråk og mye mer. En av sine svakeste poeng er emballasje. Dette er et velkjent faktum i samfunnet. Installere, importere, bruke og lage pakker har forbedret seg gjennom årene, men det er fortsatt ikke på nivå med nyere språk som Go and Rust som kan lære mye av kampene i Python og andre mer modne språk.
I denne opplæringen lærer du alt du trenger å vite for å bygge og dele dine egne pakker. For generell bakgrunn på Python-pakker, vennligst les Slik bruker du Python-pakker.
Emballasje av et prosjekt er prosessen der du tar et forhåpentligvis sammenhengende sett med Python-moduler og muligens andre filer og legger dem i en struktur som kan brukes lett. Det er forskjellige ting du må vurdere, for eksempel avhengigheter på andre pakker, intern struktur (delpakker), versjonering, målgruppe og form av pakke (kilde og / eller binær).
La oss starte med et raskt eksempel. Conman-pakken er en pakke for å administrere konfigurasjonen. Den støtter flere filformater samt distribuert konfigurasjon ved hjelp av etcd.
En pakkes innhold lagres vanligvis i en enkelt katalog (selv om det er vanlig å dele delpakker i flere kataloger) og noen ganger, som i dette tilfellet, i sitt eget git-repository.
Roten katalog inneholder forskjellige konfigurasjonsfiler (setup.py
er obligatorisk og den viktigste), og pakken koden selv er vanligvis i en underkatalog hvor navnet er pakkenes navn og ideelt sett en testerkatalog. Slik ser det ut som "conman":
> tre. ├── LISENS ├── MANIFEST.in ├── README.md ├── conman │ ├── __init__.py │ ├── __pycache__ │ ├── conman_base.py │ ├── conman_etcd.py │ └── conman_file.py ├── requirements.txt ├── setup.cfg ├── setup.py ├── test-krav.txt ├── tester │ ├── __pycache__ │ ├── conman_etcd_test.py │ ├── conman_file_test .py │ └─ - etcd_test_util.py └── tox.ini
La oss ta en rask titt på setup.py
fil. Den importerer to funksjoner fra setuptools-pakken: setup ()
og find_packages ()
. Så kaller det setup ()
funksjon og bruk find_packages ()
for en av parametrene.
fra setuptools importoppsett, find_packages setup (navn = 'conman', version = "0.3", url = "https://github.com/the-gigi/conman", lisens = "MIT", forfatter = "Gigi Sayfan" , author_email = "[email protected]", description = "Administrer konfigurasjonsfiler", pakker = find_packages (ekskluder = ['tester']), long_description = open ('README.md'). = False, setup_requires = ['nose> = 1.0'], test_suite = "nose.collector")
Dette er ganske normalt. Mens setup.py
filen er en vanlig Python-fil, og du kan gjøre hva du vil ha i den, den primære jobben den skal ringe til setup ()
Fungerer med de riktige parametrene fordi det vil bli påkalt av ulike verktøy på en standard måte når du installerer pakken. Jeg går over detaljene i neste avsnitt.
I tillegg til setup.py
, Det er noen andre valgfrie konfigurasjonsfiler som kan dukke opp her og tjene forskjellige formål.
De setup ()
funksjonen tar et stort antall navngitte argumenter for å kontrollere mange aspekter av pakkeinstallasjon, samt å kjøre forskjellige kommandoer. Mange argumenter angir metadata som brukes til å søke og filtrere når du laster opp pakken din til et lager.
find_packages ()
hjelper herDe Lang beskrivelse
er satt her til innholdet i README.md
fil, som er en god praksis å ha en eneste sannhetskilde.
Setup.py-filen serverer også et kommandolinjegrensesnitt for å kjøre forskjellige kommandoer. For eksempel, for å kjøre enhetstester, kan du skrive: python setup.py test
kjører test kjører egg_info skriver conman.egg-info / PKG-INFO skriver toppnivå navn til conman.egg-info / top_level.txt skriver dependency_links til conman.egg-info / dependency_links.txt lese manifest fil 'conman.egg-info /SOURCES.txt 'lesings manifestmal' MANIFEST.in 'skriver manifest fil' conman.egg-info / SOURCES.txt 'kjører build_ext test_add_bad_key (conman_etcd_test.ConManEtcdTest) ... ok test_add_good_key (conman_etcd_test.ConManEtcdTest) ... ok test_dictionary_access (conman_etcd_test.ConManEtcdTest ) ... ok test_initialization (conman_etcd_test.ConManEtcdTest) ... ok test_refresh (conman_etcd_test.ConManEtcdTest) ... ok test_add_config_file_from_env_var (conman_file_test.ConmanFileTest) ... ok test_add_config_file_simple_guess_file_type (conman_file_test.ConmanFileTest) ... ok test_add_config_file_simple_unknown_wrong_file_type (conman_file_test.ConmanFileTest) ... ok test_add_config_file_simple_with_file_type (conman_file_test.ConmanFileTest) ... ok test_add_config_file_simple_w rong_file_type (conman_file_test.ConmanFileTest) ... ok test_add_config_file_with_base_dir (conman_file_test.ConmanFileTest) ... ok test_dictionary_access (conman_file_test.ConmanFileTest) ... ok test_guess_file_type (conman_file_test.ConmanFileTest) ... ok test_init_no_files (conman_file_test.ConmanFileTest) ... ok test_init_some_bad_files (conman_file_test.ConmanFileTest) ... ok test_init_some_good_files ( conman_file_test.ConmanFileTest) ... ok -------------------------------------------- -------------------------- Ran 16 tester i 0.160s OK
Setup.cfg er en ini-formatfil som kan inneholde valgverdier for kommandoer du sender til setup.py
. Her inneholder setup.cfg noen alternativer for nosetests
(vår testløper):
[nosetests] verbose = 1 nocapture = 1
Denne filen inneholder filer som ikke er en del av den interne pakken katalogen, men du vil fortsatt inkludere. De er vanligvis de readme
fil, lisensfilen og lignende. En viktig fil er requirements.txt
. Denne filen brukes av pip for å installere andre nødvendige pakker.
Her er conman s MANIFEST.in
fil:
inkludere LISENS inkluderer README.md inkluderer requirements.txt
Du kan angi avhengigheter både i install_requires
del av setup.py
og i en requirements.txt
fil. Pip vil installere automatisk avhengigheter fra install_requires
, men ikke fra requirements.txt
fil. For å installere disse kravene må du spesifisere det eksplisitt når du kjører pip: pip installasjon -r krav.txt
.
De install_requires
alternativet er utformet for å angi minimal og mer abstrakte krav på hovedversjonsnivå. Requirements.txt-filen er for mer konkrete krav, ofte ved å legge ned mindre versjoner.
Her er kravfilen til conman. Du kan se at alle versjoner er festet, noe som betyr at det kan bli negativt påvirket hvis en av disse pakkene oppgraderer og introduserer en endring som bryter conman.
PyYAML == 3,11 python-etcd == 0.4.3 urllib3 == 1,7 pyOpenSSL == 0,15,1 psutil == 4,0,0 seks == 1,7,3
Pinning gir deg forutsigbarhet og trygghet. Dette er spesielt viktig hvis mange mennesker installerer pakken din på forskjellige tidspunkter. Uten pinning vil hver person få en annen blanding av avhengighetsversjoner basert på når de installerte den. Ulempen med å klemme er at hvis du ikke følger utviklingen av avhengighet, kan du bli sittende fast på en gammel, dårlig utførlig og til og med sårbar versjon av noen avhengighet.
Jeg skrev opprinnelig conman i 2014 og betalte ikke mye oppmerksomhet til det. Nå, for denne opplæringen oppgraderte jeg alt, og det var noen store forbedringer over hele linjen for nesten hver avhengighet.
Du kan opprette en kildefordeling eller en binær distribusjon. Jeg skal dekke begge deler.
Du lager en kildefordeling med kommandoen: python setup.py sdist
. Her er utgangen for conman:
> python setup.py sdist kjører sdist kjører egg_info skriver conman.egg-info / PKG-INFO skriver toppnivå navn til conman.egg-info / top_level.txt skriver dependency_links til conman.egg-info / dependency_links.txt lese manifest fil 'conman.egg-info / SOURCES.txt' lesings manifestmal 'MANIFEST.in' skriver manifestfil 'conman.egg-info / SOURCES.txt' advarsel: sdist: standardfil ikke funnet: skal ha en av README, README. rst, README.txt løpekontroll skapelse conman-0.3 opprette conman-0.3 / conman opprette conman-0.3 / conman.egg-info å lage vanskelige koblinger i conman-0.3 ... hard linking LISENS -> conman-0.3 hard linking MANIFEST.in -> conman-0.3 hard linking README.md -> conman-0.3 hardlinking requirements.txt -> conman-0.3 hard linking setup.cfg -> conman-0.3 hard linking setup.py -> conman-0.3 hard linking conman / __ init__.py -> conman-0.3 / conman hard linking conman / conman_base.py -> conman-0.3 / conman hard linking conman / conman_etcd.py -> conman-0.3 / conman hard linking conman / conman_fil e.py -> conman-0.3 / conman hard linking conman.egg-info / PKG-INFO -> conman-0.3 / conman.egg-info hard linking conman.egg-info / SOURCES.txt -> conman-0.3 / conman .egg-info hardt linking conman.egg-info / dependency_links.txt -> conman-0.3 / conman.egg-info hardt linking conman.egg-info / ikke-zip-safe -> conman-0.3 / conman.egg-info hardt linking conman.egg-info / top_level.txt -> conman-0.3 / conman.egg-info kopiering setup.cfg -> conman-0.3 Skriving conman-0.3 / setup.cfg creating dist Oppretter tar arkiv fjerner 'conman-0.3' (og alt under det)
Som du ser, fikk jeg en advarsel om manglende en README-fil med et av standardprefixene fordi jeg liker Markdown, så jeg har i stedet en "README.md". Annet enn det var alle pakkekildefilene inkludert og tilleggsfiler. Deretter ble det laget en haug med metadata i conman.egg-info
katalogen. Endelig heter et komprimert tjærearkiv conman-0.3.tar.gz
er opprettet og satt inn i en dist
sub-katalogen.
Installering av denne pakken krever et byggesteg (selv om det er ren Python). Du kan installere den ved hjelp av pip normalt, bare ved å sende stien til pakken. For eksempel:
pip installere dist / conman-0.3.tar.gz Prosessering ./dist/conman-0.3.tar.gz Installere samlepakker: conman Kjør setup.py installer for conman ... ferdig Installert conman-0.3
Conman har blitt installert i nettstedspakker og kan importeres som enhver annen pakke:
import conman conman .__ file__ '/Users/gigi/.virtualenvs/conman/lib/python2.7/site-packages/conman/__init__.pyc'
Hjul er en relativt ny måte å pakke Python kode og eventuelt C utvidelser. De erstatter eggformatet. Det finnes flere typer hjul: rene Python hjul, plattform hjul og universelle hjul. De rene Python-hjulene er pakker som conman som ikke har noen C-utvidelseskode.
Platformhjulene har C-forlengelseskode. Universalhjulene er rene Python-hjul som er kompatible med både Python 2 og Python 3 med samme kodebase (de krever ikke engang 2to3). Hvis du har en ren Python-pakke, og du vil at pakken din skal støtte både Python 2 og Python 3 (blir mer og viktigere), kan du bygge en enkelt universell bygg i stedet for ett hjul for Python 2 og ett hjul for Python 3.
Hvis pakken din har C-utvidelseskode, må du bygge et plattformshjul for hver plattform. Den store fordelen med hjul spesielt for pakker med C-utvidelser er at det ikke er nødvendig å ha kompilator og støttende biblioteker tilgjengelig på målmaskinen. Hjulet inneholder allerede en innebygd pakke. Så du vet at det ikke vil mislykkes i å bygge, og det er mye raskere å installere fordi det er bokstavelig talt bare en kopi. Folk som bruker vitenskapelige biblioteker som Numpy og Pandas, kan virkelig sette pris på dette, fordi installering av slike pakker pleide å ta lang tid og kan ha mislyktes hvis noen bibliotek manglet eller kompilatoren ikke var konfigurert riktig.
Kommandoen til å bygge rene eller plattform hjul er: python setup.py bdist_wheel
.
Setuptools-motoren som gir setup ()
funksjon - vil oppdage automatisk hvis det er behov for et rent eller platthjul.
kjører bdist_wheel kjører bygge kjører build_py skape bygge skape build / lib lage bygge / lib / conman kopiering conman / __ init__.py -> bygge / lib / conman kopiering conman / conman_base.py -> build / lib / conman kopiering conman / conman_etcd.py -> bygge / lib / conman kopiering conman / conman_file.py -> bygge / lib / conman installere for å bygge / bdist.macosx-10.9-x86_64 / hjulet kjører installerer kjører install_lib lage build / bdist.macosx-10.9-x86_64 lage build / bdist.macosx-10.9-x86_64 / hjulopprett bygg / bdist.macosx-10.9-x86_64 / hjul / conman kopiering build / lib / conman / __ init__.py -> build / bdist.macosx-10.9-x86_64 / hjul / conman kopiering bygge /lib/conman/conman_base.py -> build / bdist.macosx-10.9-x86_64 / hjul / conman kopiering build / lib / conman / conman_etcd.py -> build / bdist.macosx-10.9-x86_64 / hjul / conman kopiering bygge /lib/conman/conman_file.py -> build / bdist.macosx-10.9-x86_64 / hjul / conman kjører install_egg_info kjører egg_info skaper conman.egg-info skriving conman.egg-info / PKG-INFO skriver toppnivå navn es til conman.egg-info / top_level.txt skriver dependency_links til conman.egg-info / dependency_links.txt skriftlig manifestfil 'conman.egg-info / SOURCES.txt' lesings manifestfil 'conman.egg-info / SOURCES.txt 'read manifest template' MANIFEST.in 'skriftlig manifest fil' conman.egg-info / SOURCES.txt 'Kopierer conman.egg-info for å bygge / bdist.macosx-10.9-x86_64 / wheel / conman-0.3-py2.7. egg-info kjører install_scripts lage build / bdist.macosx-10.9-x86_64 / hjul / conman-0.3.dist-info / WHEEL
Kontrollerer dist
katalog, kan du se at et rent pythonhjul ble opprettet:
ls -la dist dist / total 32 -rw-r - r-- 1 gigi-stab 5.5K Feb 29 07:57 conman-0.3-py2-none-any.whl -rw-r - r-- 1 gigi-stab 4.4K Feb 28 23:33 conman-0.3.tar.gz
Navnet "conman-0.3-py2-none-any.whl" har flere komponenter: pakkenavn, pakkeversjon, Python-versjon, plattformversjon og til slutt "whl" -utvidelsen.
For å bygge universelle pakker, legger du bare til --universell
, som i python setup.py bdist_wheel --universal
.
Det resulterende hjulet kalles "conman-0.3-py2.py3-none-any.whl".
Legg merke til at det er ditt ansvar å sikre at koden din egentlig virker under både Python 2 og Python 3 hvis du oppretter en universell pakke.
Å skrive egne Python-pakker krever at du håndterer mange verktøy, angir mye metadata, og tenker nøye på dine avhengigheter og målgruppe. Men belønningen er stor.
Hvis du skriver nyttig kode og pakker det riktig, vil folk kunne installere det enkelt og dra nytte av det.