Python projecten verpakken voor Debian / Raspbian met dh-virtualenv
Dit artikel is bedoeld om een aantal dingen uit te leggen aan ontwikkelaars die niet veel Python gebruiken, en anders misschien zouden worstelen met sommige concepten.
Ik beveel de lezing van het volgende artikel ten zeerste aan als een inleiding op de hier besproken concepten:
pypi.org
pypi.org is een officiële opslagplaats van software voor de programmeertaal Python. Het bevat bibliotheken die we in onze projecten willen gebruiken, maar die niet standaard met Python worden meegeleverd.
Het probleem
Ons doel is om een applicatie geschreven in Python (gericht op Python3) te verpakken als een .deb pakket voor Raspbian (wat, alles welbeschouwd, eigenlijk gelijk is aan Debian).
Onze applicatie is afhankelijk van verschillende Python bibliotheken.
Bijvoorbeeld, wij zouden graag de verzoeken bibliotheek. De requests bibliotheek zelf is afhankelijk van andere bibliotheken, b.v. chardet, urllib3, enz.
Het handmatig beheren van deze afhankelijkheden en het handmatig verzenden van de vereiste bibliotheekcode is van nature onpraktisch.
pip
Python heeft zijn eigen pakket/afhankelijkheidsbeheersysteem, genaamd pip
pip staat je toe python bibliotheken en toepassingen te installeren, zodat je eigen code deze bibliotheken kan gebruiken.
Hier zijn er twee problemen:
- willen we het pakket verzenden als een Debian pakketvoor eindgebruikers om gemakkelijk te installeren. We kunnen veilig aannemen dat op een aanzienlijk aantal doelsystemen de juiste python bibliotheken niet door de gebruiker zullen zijn geïnstalleerd
- als we proberen om deze bibliotheken te installeren voor het hele systeem namens de gebruikerkunnen we de compatibiliteit met sommige andere pakketten verbreken (bv. wegens API-wijzigingen tussen versies van de bibliotheken)
Daarom hebben we een oplossing nodig.
virtualenv
virtualenv zal ons toelaten om virtuele omgevingen voor Python te creëren.
In deze virtuele omgevingen hebben we:
- onze eigen Python interpreter
- kopieën van de vereiste standaardbibliotheken
- onze eigen pip
- onze eigen "systeembrede" bibliotheek
Praktisch gedeelte: Virtualenv uitproberen
Installeer virtualenv (als onderdeel van dh-virtualenv, waar we zo dadelijk op terugkomen) door te doen:
sudo apt install dh-virtualenv
Aangezien requests al systeembreed geïnstalleerd is op mijn testdoos, zullen we een ander pakket als voorbeeld gebruiken. randstr kunt u een willekeurige string genereren.
Controleer of randstr wordt in het hele systeem geïnstalleerd:
pip3 toon randstr
Dit zou niets moeten opleveren. Geeft aan dat dit pakket niet systeembreed is geïnstalleerd:
Nu zullen we een virtuele omgeving maken. De virtuele omgeving map hoeft NIET in uw code map te staan, maar het kan. Je moet het negeren in GIT.
Laten we zeggen dat we een directory /home/pi/tutorial hebben
Ga naar deze map, en maak een nieuwe omgevingsmap env:
cd /home/pi/tutorial
welke python3
virtualenv -p /usr/bin/python3 env
Opmerking: u moet de Python interpreter specificeren als u Python 3 wilt, omdat anders Python 2 zal worden gebruikt. Ik gebruik Python 3. (Ik draai virtualenv met interpreter /usr/bin/python2)
die python3 zal je vertellen waar de python3 binary zich bevindt, pas het pad voor virtualenv overeenkomstig aan.
de omgeving te activeren:
source env/bin/activate
(Dit commando pad gaat er van uit dat je in de tutorial directory bent gebleven). Merk ook op dat dit geen uitvoerbaar script is - je moet bron om het te gebruiken met je bash terminal.
Merk op, hoe (env) is voorgehangen voor je commando prompt:
Dit betekent dat de omgeving actief is. Nu kun je pip3 opnieuw uitvoeren, maar deze keer zal pip3 zijn werk doen op de virtuele omgeving:
pip3 toon randstr
pip3 verzoeken tonen
zou nog steeds niets moeten opleveren. De tweede regel zal ook niets laten zien - waaruit blijkt dat (als requests systeembreed is geïnstalleerd) we inderdaad in een virtuele omgeving zijn.
Installeer nu randstr:
pip3 installeer randstr
en controleer opnieuw, of het geïnstalleerd is:
pip3 toon randstr
Deze keer laat het zien dat randstr is geïnstalleerd. Het is geïnstalleerd in env/lib/python3.5/site-packages:
Terwijl de omgeving nog geactiveerd is, laten we een klein Python voorbeeldprogramma schrijven:
nano sample.py
plak de volgende code, die een willekeurige string genereert met de nieuwe bibliotheek die we net geïnstalleerd hebben:
uit randstr import randstr
print("hello world")
print(randstr())
en opslaan.
Voer de code uit met python3:
python3 sample.py
terwijl de omgeving nog actief is, zal dit werken:
Nu is het tijd om de omgeving af te sluiten, om te zien of de code nog zal lopen:
deactiveren
Je prompt zal weer normaal worden. En
python3 sample.py
zal een foutmelding geven, dat er geen module 'randstr' bestaat op je systeem. Dit is precies het gedrag dat we willen!
Je kan een kijkje nemen in de env folder, om te zien hoe het alle nodige dingen meelevert om je Python code te draaien, inclusief libraries, de python executable, pip, en meer.
Debian virtualenv verpakken met dh-virtualenv
OK, nu met de basis uit de weg, wat we willen is een virtualenv inpakken samen met onze code, zodat onze applicatie betrouwbaar zal draaien zonder andere applicaties te storen op de computers van onze gebruikers.
Dit is waar dh-virtualenv komt in beeld. dh-virtualenv is een toevoeging aan de Debian bouwscripts, waarmee je virtuele omgevingen kunt verpakken.
We moeten een basis pakketstructuur maken voor ons nieuwe pakket. Dit is waar cookiecutter zal helpen.
cookiecutter
cookiecutter maakt nieuwe projecten voor u op basis van sjablonen, zodat u minder tijd en moeite hoeft te besteden aan het ontwikkelen van de vele bestanden die nodig zijn.
https://cookiecutter.readthedocs.io/en/latest/
sudo apt install cookiecutter
Opmerking: het pakket python3-cookiecutter levert een Python-module voor Python 3. Wat we willen is de applicatie zelf, die geïnstalleerd wordt met het cookiecutter pakket zoals hierboven te zien is. Dit zou kunnen trekken in Python 2, maar - oh well.
cookiecutter is niet nodig voor uw eindgebruikers, het wordt alleen gebruikt om verschillende bestanden voor uw pakket te maken.
maak een voorbeeld project map aan, waarin we het sjabloon zullen toepassen (ik ben nog steeds in de zelfstudie map):
mkdir voorbeeldproject
cd voorbeeldproject
Met behulp van een speciale mal voor dh-virtualenv kunnen we veel van de benodigde bestanden instellen:
https://github.com/Springerle/dh-virtualenv-mold
cookiecutter https://github.com/Springerle/dh-virtualenv-mold.git
Deze zal u verschillende vragen stellen.
Merk op dat de map debian moet heten, zelfs bij het verpakken voor Raspbian - houd daarom de naam debian aan.
Dit zal de volgende bestanden installeren:
Nu moet je de volgende commando's uitvoeren, volgens de instructies onder de dh-virtualenv-mold:
sudo apt-get install build-essential debhelper devscripts equivssudo mk-build-deps --install debian/control
Om het pakket later te bouwen, moet je het volgende commando uitvoeren vanuit de top level directory van je project:
dpkg-buildpackage -uc -us -b
Op dit moment zal het commando echter falen omdat setup.py ontbreekt. We komen zo bij setup.py en requirements.txt:
/usr/bin/python3: kan bestand 'setup.py' niet openen: [Errno 2] No such file or directory
Informatie over de afzonderlijke bestanden
changelog
Dit bestand bevat uw release en versie informatie voor het pakket. U kunt het bijwerken met een speciaal gereedschap, dch.
Dit bestand is geen changelog voor uw applicatie, maar slechts een changelog voor het inpakken van uw applicatie.
compat
Dit bestand bevat een speciaal magisch nummer "9". (voor compatibiliteits problemen, is het prima om het zo te laten)
controle
Dit is het belangrijkste bestand om pakketinstellingen en afhankelijkheden op Debian-niveau in te stellen. Als uw toepassing bijvoorbeeld afhankelijk is van de installatie van de omxplayer, dan moet die hier als afhankelijkheid worden ingevoerd:
Bron: monsterproject
Sectie: contrib/python
Prioriteit: extra
Onderhouder: Maximilian Batz
Build-Depends: debhelper (>= 9), python, python-dev, dh-virtualenv (>= 0.10), tar
Normen-Versie: 3.9.5
Homepage: https://picockpit.com
Pakket: proefproject
Architectuur: alle
Pre-Depends: dpkg (>= 1.16.1), python2.7 | python3, ${misc:Pre-Depends}
Depends: ${python:Depends}, ${misc:Depends}
Beschrijving: Een voorbeeldpakket om te demonstreren hoe virtualenv Debian verpakt met dh-virtualenv
.
Dit is een distributie van "sampleproject" als een op zichzelf staand
Python virtualenv verpakt in een Debian pakket ("omnibus" pakket,
alle passagiers aan boord). De verpakte virtualenv wordt in sync gehouden met
de interpreter van de host automatisch.
.
Zie https://github.com/spotify/dh-virtualenv voor meer details.
U zult ook de lange beschrijving willen bewerken.
cookiecutter.json
Inclusief uw eerste instellingen. Niet nodig voor verpakking.
auteursrecht
Uw copyright bestand, met uw licentie (b.v. MIT). Het is vooraf ingevuld met uw naam, jaar, e-Mail en "sommige rechten voorbehouden".
regels
Dit is een Makefile, om je pakket te bouwen. Het is vooraf ingevuld door het cookiecutter sjabloon.
voorbeeldproject.links
Dit bestand maakt het mogelijk om links te maken tijdens de installatie . De bestandsnaam zal uw projectnaam bevatten in plaats van voorbeeldproject.
Ref: https://stackoverflow.com/questions/9965717/debian-rules-file-make-a-symlink
voorbeeldproject.postinst
Dit bestand laat u toe om bijkomende setup stappen uit te voeren na de installatie (bv. het activeren van uw python script als een service). De bestandsnaam zal uw projectnaam bevatten in plaats van voorbeeldproject.
voorbeeldproject.triggers
Voor zover ik het begrijp is dit voor dh-virtualenv om een nieuwere python interpreter te installeren in de virtuele omgeving om te verzenden, als die van het systeem (uw ontwikkelingsdoos) wordt bijgewerkt. De bestandsnaam zal je projectnaam bevatten in plaats van voorbeeldproject.
Dit kan wel of niet het geval zijn, ik heb het niet getest.
setup.py
Zoals hierboven vermeld, hebben we een setup.py bestand. Dit is de standaard manier waarop toepassingen onder Python worden verpakt (ze worden geleverd met een setup.py, die wordt uitgevoerd voor verschillende taken met betrekking tot het verpakken).
Een eenvoudige setup.py is te zien op deze pagina:
https://github.com/benjaminirving/python-debian-packaging-example/blob/master/setup.py
Niet alle gegevens in deze bestanden zijn noodzakelijk. Je kunt bijvoorbeeld de classifiers weglaten. Ik heb de volgende setup.py:
Opmerking: het versienummer en andere informatie hier zijn voor uw Python pakket (dat zal worden aangemaakt in de loop van het bouwen van een Debian pakket met uw virtualenv).
Structuur voor uw code
Je code zal nu in een subdirectory van de hoofd sampleproject directory staan:
De subdirectory heeft in dit geval dezelfde naam als de hoofddirectory.
Let op de __init__.py
De sample.py is degene die we hierboven gebruikten, maar een beetje herwerkt om er zo uit te zien:
Daarnaast heb ik een virtuele omgeving opgezet om te testen terwijl ik aan het ontwikkelen ben in de hoofd (top level) sampleproject directory:
virtualenv -p /usr/bin/python3 sp_env
genaamd sp_env voor voorbeeld project omgeving
De omgeving binnengaan:
source sp_env/bin/activate
Installeer de randstr bibliotheek in deze omgeving:
pip3 installeer randstr
en nu kunnen we de code uitvoeren:
python3 monsterproject/monster.py
OK. Sluit de omgeving af (! Belangrijk !)en probeer het pakket opnieuw te bouwen:
deactiveren
dpkg-buildpackage -us -uc
Standaard (omwille van de cookie cutter), zal uw pakket aangemaakt worden voor installatie in /opt/venvs/:
Nieuwe python executable in /home/pi/tutorial/sampleproject/debian/sampleproject/opt/venvs/sampleproject/bin/python3
Dit kan worden gewijzigd in de debian/regels dossier.
Nu is het pakket gebouwd, en gedeponeerd buiten de sampleproject top directory (binnen de tutorial directory):
U kunt het .deb-bestand installeren met dpkg:
sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb
Bekijk de installatie resultaten met
boom /opt/venvs
127 mappen en 945 bestanden werden geïnstalleerd.
Nu kunt u proberen het voorbeeldproject uit te voeren met
/opt/venvs/sampleproject/bin/sampleproject
vereisten / afhankelijkheden
De applicatie draait niet zoals (misschien) verwacht, maar geeft een foutmelding dat randstr niet aanwezig is. Wat geeft dit?
De reden is dat dh-virtualenv niet op de hoogte is van de eis die wij hebben, om het pakket randstr te bundelen tijdens het bouwproces. Dit is het laatste stukje van de puzzel.
De eisen moeten worden toegevoegd aan de setup.py, als een manier om pip te laten weten welke aanvullende pakketten moeten worden geïnstalleerd in de virtuele omgeving die wordt aangemaakt.
voeg het volgende toe aan setup.py:
install_requires=[
"randstr
]
Het hele bestand zal er dan zo uitzien:
In mijn tests deed de requirements.txt op het hoogste niveau niet invloed hebben op het gedrag van dh-virtualenv en de Python pakketten die daadwerkelijk in het Debian pakket zitten. Als je het toch wilt, hier is hoe:
pip biedt u een manier om de exacte afhankelijkheden die u gebruikte voor het ontwikkelen in de virtuele omgeving te plaatsen. Ga de virtuele omgeving binnen:
source sp_env/bin/activate
En maak het requirements.txt bestand:
pip3 freeze > requirements.txt
Nu kun je een kijkje nemen in dat bestand:
cat requirements.txt
Ook al lijkt dit bestand niet gebruikt te worden door dh-virtualenv (misschien moet het in een andere subdirectory), het is een goede referentie voor jezelf, om te zien welke pakketten je als dependencies in het install_requires gedeelte van setup.py moet zetten.
Merk op dat het bestand sampleproject.links ons een handige manier bood om dit te linken naar de /usr/bin map, ik zal daarom het commentaar teken verwijderen voor de volgende build:
Met dat uit de weg, is het tijd om het voorbeeldproject te wissen, het opnieuw te bouwen, en het dan te installeren. Vergeet niet om eerst te deactiveren!
deactiveren
sudo apt purge sampleproject
dpkg-buildpackage -us -uc
cd...
sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb
Deze keer zou het pakket toegankelijk moeten zijn via sampleproject:
welk voorbeeldproject
voorbeeldproject
Ref: https://packaging.python.org/discussions/install-requires-vs-requirements/
Bonustip: de installatielocatie wijzigen
/opt/venvs is niet echt een Debian "plaats" om een pakket te plaatsen.
De specificaties zijn hier:
http://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html
https://unix.stackexchange.com/questions/10127/why-did-my-package-get-installed-to-opt
- /usr/local is niet voor pakketten
- /opt is niet voor de eigenlijke Debian-pakketten (het is voor door de gebruiker geïnstalleerde software van derden)
http://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04s06.html
Toepassingen kunnen gebruik maken van een enkele subdirectory onder /usr/lib
. Indien een toepassing een subdirectory gebruikt, moeten alle architectuur-afhankelijke gegevens die uitsluitend door de toepassing worden gebruikt, in die subdirectory worden geplaatst.
https://wiki.debian.org/HowToPackageForDebian
https://www.debian.org/doc/debian-policy/ch-opersys.html#file-system-hierarchy
"De FHS-eis dat architectuur-onafhankelijke applicatiespecifieke statische bestanden zich bevinden in /usr/share
wordt versoepeld tot een suggestie. In het bijzonder, een subdirectory van /usr/lib
kan worden gebruikt door een pakket (of een verzameling pakketten) om een mengsel van architectuur-onafhankelijke en architectuur-afhankelijke bestanden te bevatten. Wanneer een directory echter geheel bestaat uit architectuuronafhankelijke bestanden, moet deze worden geplaatst in /usr/share
."
De beste locatie lijkt mij /usr/share
We moeten twee bestanden bewerken:
in debian/rules moet DH_VIRTUALENV_INSTALL_ROOT veranderd worden in /usr/share, zoals dit:
en debian/sampleproject.links moeten veranderd worden:
Ook zullen we een nieuw item in de changelog maken:
dch -i
bewerk gewoon de tekst, om een nieuw versienummer weer te geven, en een item voor de changelog.
Dan kan het project opnieuw worden gebouwd:
dpkg-buildpackage -us -uc
Na de installatie kunt u controleren of de nieuwe locatie inderdaad wordt gebruikt:
Het pakket zal ongeveer 16 MB in beslag nemen op uw doelsysteem, dankzij de virtuele omgeving en alles wat erbij geleverd wordt. Dit kan waarschijnlijk verminderd worden met enkele parameters, maar die oefening wordt aan de lezer overgelaten.
Veel plezier met inpakken!