Python is een geweldige programmeertaal en nog veel meer. Een van de zwakste punten is verpakking. Dit is een bekend feit in de gemeenschap. Het installeren, importeren, gebruiken en maken van pakketten is in de loop der jaren verbeterd, maar het is nog steeds niet vergelijkbaar met nieuwere talen als Go en Rust die veel kunnen leren van de strijd van Python en andere meer volwassen talen.
In deze zelfstudie leert u alles wat u moet weten om uw eigen pakketten samen te stellen en te delen. Voor algemene achtergrondinformatie over Python-pakketten leest u Hoe Python-pakketten te gebruiken.
Het verpakken van een project is het proces waarmee je een hopelijk samenhangende set Python-modules en mogelijk andere bestanden neemt en deze in een structuur plaatst die gemakkelijk kan worden gebruikt. Er zijn verschillende dingen waar je rekening mee moet houden, zoals afhankelijkheden van andere pakketten, interne structuur (subpakketten), versiebeheer, doelgroep en vorm van pakket (bron en / of binair).
Laten we beginnen met een snel voorbeeld. Het conman-pakket is een pakket voor het beheren van de configuratie. Het ondersteunt verschillende bestandsformaten evenals gedistribueerde configuratie met etcd.
De inhoud van een pakket wordt meestal opgeslagen in een enkele map (hoewel het gebruikelijk is om subpakketten in meerdere mappen te splitsen) en soms, zoals in dit geval, in zijn eigen git-repository.
De hoofdmap bevat verschillende configuratiebestanden (setup.py
is verplicht en de belangrijkste) en de pakketcode zelf bevindt zich meestal in een submap waarvan de naam de naam van het pakket is en idealiter een testdirectory. Hier is hoe het eruit ziet voor "conman":
> boom. ├── LICENSE ├── MANIFEST.in ├── README.md ├── conman │ ├── __init__.py │ ├── __pycache__ │ ├── conman_base.py │ ├── conman_etcd.py │ └── conman_file.py ├── requirements.txt ├── setup.cfg ├── setup.py ├── test-demands.txt ├── tests │ ├── __pycache__ │ ├── conman_etcd_test.py │ ├── conman_file_test .py │ └── etcd_test_util.py └── tox.ini
Laten we even kijken naar de setup.py
het dossier. Het importeert twee functies uit het setuptools-pakket: opstelling()
en find_packages ()
. Dan roept het de opstelling()
functie en gebruik find_packages ()
voor een van de parameters.
van setuptools import setup, find_packages setup (naam = 'conman', version = "0.3", url = "https://github.com/the-gigi/conman", license = "MIT", author = "Gigi Sayfan" , author_email = "[email protected]", description = "Beheer configuratiebestanden", packages = find_packages (exclude = ['tests']), long_description = open ('README.md'). read (), zip_safe = False, setup_requires = ['nose> = 1.0'], test_suite = "nose.collector")
Dit is normaal. Terwijl de setup.py
bestand is een normaal Python-bestand en u kunt doen wat u maar wilt, de primaire taak ervan is het opstelling()
functie met de juiste parameters, omdat deze standaard door verschillende hulpmiddelen worden opgeroepen tijdens het installeren van uw pakket. Ik zal de details in de volgende sectie bespreken.
In aanvulling op setup.py
, er zijn een paar andere optionele configuratiebestanden die hier kunnen worden weergegeven en die verschillende doeleinden dienen.
De opstelling()
functie neemt een groot aantal benoemde argumenten om vele aspecten van de pakketinstallatie te besturen en verschillende opdrachten uit te voeren. Veel argumenten specificeren metadata die worden gebruikt voor zoeken en filteren bij het uploaden van uw pakket naar een repository.
find_packages ()
helpt hierDe lange beschrijving
wordt hier ingesteld op de inhoud van de README.md
bestand, wat een goede gewoonte is om een enkele bron van waarheid te hebben.
Het setup.py-bestand biedt ook een opdrachtregelinterface om verschillende opdrachten uit te voeren. Als u bijvoorbeeld de eenheidstests wilt uitvoeren, typt u: python setup.py test
draaitest running egg_info schrijven conman.egg-info / PKG-INFO schrijven van topniveau namen naar conman.egg-info / top_level.txt schrijven van dependency_links naar conman.egg-info / dependency_links.txt lezen van het manifestbestand 'conman.egg-info /SOURCES.txt 'leest manifestsjabloon' MANIFEST.in 'manifest-bestand schrijven' conman.egg-info / SOURCES.txt 'running 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 -------------------------------------------- -------------------------- 16 Ran 16-tests uitgevoerd in 0,160 OK
De setup.cfg is een ini-indeling die mogelijk standaardinstellingen bevat voor opdrachten waarnaar u overschakelt setup.py
. Hier bevat setup.cfg enkele opties voor nosetests
(onze testrunner):
[nosetests] verbose = 1 nocapture = 1
Dit bestand bevat bestanden die geen deel uitmaken van de interne pakketdirectory, maar u wilt deze wel opnemen. Dat zijn meestal de Leesmij
bestand, het licentiebestand en dergelijke. Een belangrijk bestand is het requirements.txt
. Dit bestand wordt door pip gebruikt om andere vereiste pakketten te installeren.
Hier is Conman's MANIFEST.in
het dossier:
inclusief LICENSE include README.md include requirements.txt
U kunt afhankelijkheden zowel in de install_requires
gedeelte van setup.py
en in een requirements.txt
het dossier. Pip zal automatisch de afhankelijkheden van installeren install_requires
, maar niet van de requirements.txt
het dossier. Als u deze vereisten wilt installeren, moet u dit expliciet opgeven bij het uitvoeren van pip: pip install -r requirements.txt
.
De install_requires
optie is ontworpen om minimale en meer abstracte vereisten op het hoofdversieniveau te specificeren. Het bestand requirements.txt is voor meer concrete vereisten, vaak met vastgezette, secundaire versies.
Hier is het vereistenbestand van Conman. U kunt zien dat alle versies zijn vastgezet, wat betekent dat het negatief kan worden beïnvloed als een van deze pakketten upgradet en een wijziging introduceert die conman overtreedt.
PyYAML == 3.11 python-etcd == 0.4.3 urllib3 == 1.7 pyOpenSSL == 0.15.1 psutil == 4.0.0 six == 1.7.3
Vastzetten geeft je voorspelbaarheid en gemoedsrust. Dit is vooral belangrijk als veel mensen uw pakket op verschillende tijdstippen installeren. Zonder pinning krijgt elke persoon een andere mix van afhankelijkheidsversies op basis van wanneer ze het hebben geïnstalleerd. Het nadeel van pinning is dat als je de ontwikkeling van afhankelijkheden niet bijhoudt, je vast komt te zitten aan een oude, slecht presterende en zelfs kwetsbare versie van een afhankelijkheid.
Ik schreef oorspronkelijk conman in 2014 en besteedde er niet veel aandacht aan. Nu heb ik voor deze tutorial alles geüpgraded en er waren over de hele linie enkele belangrijke verbeteringen voor bijna elke afhankelijkheid.
U kunt een brondistributie of een binaire distributie maken. Ik zal beide behandelen.
U maakt een bronverdeling met de opdracht: python setup.py sdist
. Hier is de uitvoer voor conman:
> python setup.py sdist draait sdist draait egg_info schrijven conman.egg-info / PKG-INFO schrijft top-level namen naar conman.egg-info / top_level.txt schrijven van dependency_links naar conman.egg-info / dependency_links.txt lezen manifestbestand 'conman.egg-info / SOURCES.txt' leesmanifest template 'MANIFEST.in' schrijven manifest bestand 'conman.egg-info / SOURCES.txt' waarschuwing: sdist: standaard bestand niet gevonden: moet een van README, README hebben. eerste, README.txt lopende controle creëren conman-0.3 aanmaken conman-0.3 / conman aanmaken conman-0.3 / conman.egg-info maken van harde koppelingen in conman-0.3 ... moeilijk koppelen LICENTIE -> conman-0.3 moeilijk koppelen MANIFEST.in -> conman-0.3 hard linken README.md -> conman-0.3 moeilijk linken requirements.txt -> conman-0.3 hard linken setup.cfg -> conman-0.3 hard linken setup.py -> conman-0.3 hard linken 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 hard linken conman.egg-info / dependency_links.txt -> conman-0.3 / conman.egg-info hard linken conman.egg-info / not-zip-safe -> conman-0.3 / conman.egg-info hard koppelen conman.egg-info / top_level.txt -> conman-0.3 / conman.egg-info kopiëren setup.cfg -> conman-0.3 Schrijven conman-0.3 / setup.cfg maken dist Maken van tar archief verwijderen 'conman-0.3' (en alles daaronder)
Zoals je ziet, kreeg ik een waarschuwing over het missen van een README-bestand met een van de standaardprefixen omdat ik Markdown leuk vind, dus in plaats daarvan heb ik een "README.md". Verder zijn alle bronbestanden van het pakket opgenomen en de aanvullende bestanden. Vervolgens is een heleboel metagegevens gemaakt in de conman.egg-info
directory. Eindelijk een gecomprimeerd tar-archief genaamd conman-0.3.tar.gz
is gemaakt en in een dist
sub-directory.
Voor het installeren van dit pakket is een bouwstap vereist (ook al is het pure Python). Je kunt het normaal via pip installeren, gewoon door het pad naar het pakket te voeren. Bijvoorbeeld:
pip install dist / conman-0.3.tar.gz Verwerking ./dist/conman-0.3.tar.gz Installatie van verzamelde pakketten: conman Setup.py uitvoeren voor conman installeren ... done Conman-0.3 succesvol geïnstalleerd
Conman is geïnstalleerd in sitepakketten en kan net als elk ander pakket worden geïmporteerd:
import conman conman .__ file__ '/Users/gigi/.virtualenvs/conman/lib/python2.7/site-packages/conman/__init__.pyc'
Wielen zijn een relatief nieuwe manier om Python-code en optioneel C-uitbreidingen te verpakken. Ze vervangen het eierformaat. Er zijn verschillende soorten wielen: pure Python-wielen, platformwielen en universele wielen. De pure Python-wielen zijn pakketten zoals conman die geen C-extensiecode hebben.
De platformwielen hebben wel een C-uitbreidingscode. De universele wielen zijn pure Python-wielen die compatibel zijn met zowel Python 2 als Python 3 met dezelfde codebasis (ze vereisen zelfs geen 2to3). Als je een puur Python-pakket hebt en je wilt dat je pakket zowel Python 2 als Python 3 ondersteunt (steeds belangrijker worden), dan kun je een enkele universele build maken in plaats van één wiel voor Python 2 en één wiel voor Python 3.
Als uw pakket een C-uitbreidingscode heeft, moet u voor elk platform een platformwiel bouwen. Het grote voordeel van wielen, met name voor pakketten met C-extensies, is dat er geen behoefte is aan compileerprogramma's en ondersteunende bibliotheken op de doelcomputer. Het wiel bevat al een gebouwd pakket. Dus je weet dat het niet zal mislukken om te bouwen en het is veel sneller te installeren omdat het letterlijk slechts een kopie is. Mensen die wetenschappelijke bibliotheken zoals Numpy en Panda's gebruiken, kunnen dit erg waarderen, omdat het installeren van dergelijke pakketten lang heeft geduurd en mogelijk mislukt is als een bibliotheek ontbrak of de compiler niet correct was geconfigureerd.
Het commando om pure of platformwielen te bouwen is: python setup.py bdist_wheel
.
Setuptools - de engine die de opstelling()
functie-detecteert automatisch of een puur of platformwiel nodig is.
hardlopen bdist_wheel hardlopen build hardlopen build_py maken build maken build / lib maken build / lib / conman kopiëren conman / __ init__.py -> build / lib / conman kopiëren conman / conman_base.py -> build / lib / conman kopiëren conman / conman_etcd.py -> build / lib / conman kopiëren conman / conman_file.py -> build / lib / conman installeren om te bouwen / bdist.macosx-10.9-x86_64 / wheel running install uitvoeren install_lib create build / bdist.macosx-10.9-x86_64 build maken / bdist.macosx-10.9-x86_64 / wheel creating build / bdist.macosx-10.9-x86_64 / wheel / conman copy build / lib / conman / __ init__.py -> build / bdist.macosx-10.9-x86_64 / wheel / conman copy build /lib/conman/conman_base.py -> build / bdist.macosx-10.9-x86_64 / wheel / conman copy build / lib / conman / conman_etcd.py -> build / bdist.macosx-10.9-x86_64 / wheel / conman copy build /lib/conman/conman_file.py -> build / bdist.macosx-10.9-x86_64 / wheel / conman running install_egg_info running egg_info creating conman.egg-info writing conman.egg-info / PKG-INFO schrijven top-level nam es to conman.egg-info / top_level.txt schrijven van dependency_links naar conman.egg-info / dependency_links.txt schrijven van manifestbestand 'conman.egg-info / SOURCES.txt' lezen manifestbestand 'conman.egg-info / SOURCES.txt 'manifest manifestsjabloon lezen' MANIFEST.in 'manifest-bestand schrijven' conman.egg-info / SOURCES.txt 'Conman.egg-info kopiëren om te bouwen / bdist.macosx-10.9-x86_64 / wheel / conman-0.3-py2.7. egg-info met install_scripts maken build / bdist.macosx-10.9-x86_64 / wheel / conman-0.3.dist-info / WHEEL
Controle van de dist
map, kunt u zien dat een puur Python-wiel is gemaakt:
ls -la dist dist / total 32 -rw-r - r-- 1 gigi personeel 5.5K 29 feb. 07:57 conman-0.3-py2-none-any.whl -rw-r - r-- 1 gigi personeel 4.4K 28 februari 23:33 conman-0.3.tar.gz
De naam "conman-0.3-py2-none-any.whl" heeft verschillende componenten: pakketnaam, pakketversie, Python-versie, platformversie en tenslotte de "whl" -extensie.
Om universele pakketten te bouwen, voeg je gewoon toe --universeel
, als in python setup.py bdist_wheel --universal
.
Het resulterende wiel wordt "conman-0.3-py2.py3-none-any.whl" genoemd.
Merk op dat het uw verantwoordelijkheid is om ervoor te zorgen dat uw code daadwerkelijk werkt onder zowel Python 2 als Python 3 als u een universeel pakket maakt.
Het schrijven van je eigen Python-pakketten vereist het omgaan met veel tools, het specificeren van veel metadata en het goed nadenken over je afhankelijkheden en doelgroep. Maar de beloning is geweldig.
Als u nuttige code schrijft en deze op de juiste manier verpakt, kunnen mensen deze gemakkelijk installeren en ervan profiteren.