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:

afbeelding

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.

afbeelding

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:

afbeelding

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

afbeelding

Deze keer laat het zien dat randstr is geïnstalleerd. Het is geïnstalleerd in env/lib/python3.5/site-packages:

afbeelding

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:

afbeelding

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!

afbeelding

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.

afbeelding

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:

afbeelding

Nu moet je de volgende commando's uitvoeren, volgens de instructies onder de dh-virtualenv-mold:

sudo apt-get install build-essential debhelper devscripts equivs
sudo 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:

afbeelding

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:

afbeelding

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:

afbeelding

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

afbeelding

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):

afbeelding

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?

afbeelding

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:

afbeelding

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

afbeelding

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:

afbeelding

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

afbeelding

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:

afbeelding

en debian/sampleproject.links moeten veranderd worden:

afbeelding

Ook zullen we een nieuw item in de changelog maken:

dch -i

afbeelding

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:

afbeelding

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!