Környezetkezelés
Mi az a Pixi?
A Python service függőségeinek és környezeteinek kezelésére a Pixi környezetkezelőt alkalmazzuk. Ez több forrásból merít (főleg Conda, uv és Poetry), és próbálja ezek pozitívumait megtartva a leguniverzálisabb Python csomagkezelést biztosítani. Több hasznos funkcióval bír, többek között
- rendszerfüggetlen lock-fájlok támogatása és automatikus generálása
- Conda csomagokkal való kompatibilitás
- a Python csomagként való kezelése
- több környezet definiálásának lehetősége
A Pixi használata lehetővé teszi, hogy egyszerűen – és az uv-nek köszönhetően rendkívül gyorsan – definiáljunk, telepítsünk és megosszunk környezeteket (akár különböző Python verziókkal, különböző operációs rendszereken), melyeket minimális manuális munkával, vagy akár automatikusan lehetséges a telepíteni a repo frissítésével.
Pixi és Conda
A Pixi és a Conda környezetkezelése néhol hasonlít, máshol eltér. A Pixi oldalán találunk egy összehasonlítást a kettőről. Ugyanakkor pár dolgot fontos kiemelni a témával kapcsolatban.
A talán legjelentősebb technikai különbség, hogy a Conda globális környezeteket hoz létre, melyeket bárhonnan aktiválhatunk. Ezzel szemben a Pixi lokálisan, az adott projekt mappájában állítja össze a környezeteket (ezeket meg is találjuk a <projekt mappa>/.pixi/envs könyvtárban). Így tehát a Pixi környezeteket nem érjük el automatikusan a projektmappán kívül.
Ennek hozománya, hogy a Pixi környezeteket nem is feltétlen szükséges aktiválni: a pixi run <parancs> a megadott parancsot automatikusan az adott projekt default környezetében futtatja (amennyiben persze a parancsot a projekt mappáján belül adjuk ki).
Fontos, hogy a Conda és a Pixi megél egymás mellett. Azaz nem kell letörölünk a Conda-t, vagy egyéb trükközést végeznünk, hogy használni tudjuk. Amennyiben a pixi run <parancs> parancsot adjuk ki, az a Pixi környezetet fogja használni, független attól, hogy van-e aktiválva Conda környezet.
Ugyanakkor ha csak simán a python <fájl> parancsot adjuk ki, akkor ezt a Pixi nem fogja automatikusan elkapni, így váratlan működés következhet (pl. a rendszerszintű Python interpreter futtat, vagy a Conda környezet, amennyiben aktiválva van). Ennek elkerülése érdekében a Pixi környezetet is tudjuk „aktiválni“ a pixi shell paranccsal. Ekkor bármilyen kiadott parancs a Pixi környezetnek megfelelően fut, továbbá a terminál sorainak elején megjelenik az aktivált környezet neve (Conda-hoz hasonlóan). A környezet deaktiválása az exit paranncsal történik.
Konfiguráció
A Pixi konfigurációja a pyproject.toml fájl tool.pixi táblájában található, itt definiáljuk a függőségeket, környezeteket és támogatott operációs rendszereket. A tool.pixi tábla felépítésének teljes leírásától eltekintenénk, ez megtalálható a Pixi dokumentációjában. Ennek ellenére az általa használt alapvető koncepciókat bemutatjuk.
A workspace tábla
Ez a projektre vonatkozó alapvető leírásokat tartalmaz, mint például a projekt neve, vagy a támogatott operációs rendszerek.
A feature.<feature_name> táblák
Ezek egy-egy aspektust, és az ehhez szükséges függőségeket definiálják. Alapvetően úgy gondolunk egy-egy „feature“-re, mint egyetlen dolog, amit a környezetünk tud (pl. futtatás, formázás, tesztelés).
Az environments.<env_name> táblák
Ezek egy-egy környezetet definiálnak. Pixi-ben egy környezet úgy áll elő, mint feature-ök összessége. Fontos, hogy alapértelmezésként minden környezet tartalmazza a default feature-t (vigyázat, nem a default környezetet). Amennyiben ezt el szeretnénk kerülni, úgy a no-default-feature flag-et be kell állítanunk. Emellett a környezetek esetén támogatott a solve-group paraméter, melynek funkciója, hogy az azonos solve-group-pal rendelkező környezetek azonos csomagverziókkal kerülnek rögzítésre, a rendszer közösen számolja függőségeik verzióit.
Ez utóbbinak segítségével érjük el, hogy a prod és a cicd környezetünk azonos csomagverziókat használjon annak ellenére, hogy a cicd környezet bővebb. Ezzel lehetővé tesszük, hogy a CI/CD job-ok során ugyanazok a problémák állhassanak elő, melyek élőben előjönnének.
A *.tasks táblák
Itt rögzíthetünk olyan „feladatokat“ (akár globálisan, akár feature specifikusan), amiket a pixi run paranccsal futtathatunk. Ezek gyakorlatilag előre definiált parancssoros hívások, esetlegesen definiált task-függőségekkel, melyeket szintén futtat a rendszer megfelelő sorrendben.
Függőségek és módosításuk
A futtatáshoz szükséges PyPI függőségeket a pyproject.toml fájl project táblájának dependencies listája tárolja. Új PyPI függőségeket a legegyszerűbben úgy adhatunk a futtatási környezethez, hogy ebbe a listába beszúrjuk. Ügyeljünk arra, hogy rögzítsük a csomag verzióját (==<verzió> segítségével), illetve az átláthatóság miatt lehetőleg tartsuk a betűrendet.
Miért nem a pixi táblába helyezzük a függőségeket?
Bár a Pixi-t tool.pixi tábla konfigurálja, a PEP 621 definiálja a project tábla szerkezetét, így azt a legtöbb modern csomagkezelő felhasználja, mint „kiindulási alap“. Ennek okán PyPI függőségeket itt definiálni általánosabb (emellett valamennyivel kényelmesebb és átláthatóbb is), mint a pixi saját rendszerében, hiszen ezeket opcionálisan más csomagkezelők is tudják alkalmazni, és egy kompatibilis környezetet összeállítani.
Fontos megjegyezni, hogy a project.dependencies táblát a Pixi a default feature-höz rendeli.
Amennyiben nem Python függőséget akarunk hozzáadni, azt megtehetjük a tool.pixi.dependencies tábla kiegészítésével. Ha ez nem conda-forge csatornát használ, azt vegyük fel a tool.pixi.workspace tábla channels listájába. További információkért látogassunk a Pixi dokumentáció megfelelő oldalára.
A pixi add parancs
Függőségeket definiálhatunk a pixi add parancs segítségével is. Ugyanakkor egyszerűbb és kevésbé ad hibázásra lehetőséget, ha magát a pyproject.toml fájlt módosítjuk. Mindenesetre az add parancs működését megtaláljuk a Pixi dokumentációban
A Pixi automatikusan fenntart egy pixi.lock fájlt, amit frissít is valamennyi Pixi parancs futtatása esetén (pl. pixi run, pixi install). Ha kifejezetten csak a lock fájlt akarjuk frissíteni a pyproject.toml változtatásai alapján, ezt megtehetjük a pixi lock parancs segítségével.
Környezetek és task-ok
Most bemutatjuk a definiált környezeteket, illetve azt, hogy mire használjuk őket. Mindenekelőtt fontos megemlíteni, hogy a default feature a rendszer alapvető futtatására van fenntartva, ahhoz nem kell semmi egyéb.
Először bemutatjuk a task-okat:
| Task | Leírás |
|---|---|
start |
Elindítja a Python service-t |
compile-cache |
Compile-olja a pyc fájlokat. Alapvetően sosem szükséges használni, hiszen ezek automatikusan generálódnak. Viszont az első indítást gyorsítja. |
generate-api |
Legenerálja a DTO-kat az api repo alapján |
lint |
Lefuttatja a linter-t (lásd. linting). |
lint-autofix |
Lefuttatja a linter-t, miközben megpróbálja javítani az automatikusan javítható hibákat. |
check-format |
Ellenőrzi a kódformázási hibákat (lásd. formázás). |
fix-format |
Javítja a kódformázási hibákat. |
check-code |
Ellenőrzi a kódot a linter és formatter segítségével. A CI/CD build job kódminőség-ellenőrzéseit utánozza. |
check-imports |
Ellenőrzi az csomaghasználati és -definiálási hibákat (lásd. függőséghasználat). |
test |
Unit-teszteli a kódot (lásd. unit tesztelés). |
test-coverage |
Unit-teszteli a kódot, miközben ellenőrzi a lefedettséget. |
build-coverage-report |
Teszt-lefedettség ellenőrzése után abból HTML jelentést épít. |
show-coverage |
Teszt-lefedettség ellenőrzése után abból HTML jelentést épít, és megnyitja böngészőben. |
default
Az alapértelmezett környezet a teljes fejlesztői infrastruktúrát tartalmazza, beleértve az összes feature-t és task-ot. Tekintve hogy a fejlesztői gépeken elég tárhely áll rendelkezésre, az összes eszköz telepítése nem okoz problémát. A környezet támogatja a Linux, Windows és ARM-alapú macOS rendszereket, ezek közül utóbbi kettő a fejlesztői laptopok operációs rendszere. Rendelkezésre áll benne a jupyter csomag is notebook-okban való kísérletezéshez.
prod
Feladata, hogy Docker konténerben futtassa a rendszert. Ennek megfelelően csak a futtatáshoz szükséges csomagokat tartalmazza (azaz default feature-t), és kizárólag a Linux rendszert támogatja. Task-okból csak a start és a compile-cache áll rendelkezésre.
prod-api
Ez a környezet nem tudja futtatni a rendszert. Csak a Linux-ot támogatja, és egyetlen használata, hogy legenerálja a DTO-kat, hogy a prod környezet tudja futtatni a rendszert (az nem tartalmazza a DTO-generáláshoz szükséges csomagokat). Egyetlen task-ja ennek megfelelően a generate-api.
cicd
Feladata, hogy futtassa CI/CD build job-ját, a kódminőséget ellenőrző feladatok kivételével. Ennek megfelelően a rendszer futtatásán kívül képes DTO-kat generálni és tesztelni is. Továbbá ebbe a környezetbe tartozik a kódminőséget érintő feladatok közül a függőséghasználat ellenőrzése (ennek oka, hogy az import-ok ellenőrzéséhez szükséges a futtatási környezet létezése, hiszen a különböző csomagneveket így lehet azonosítani).
A környezet kizárólag Linux rendszert támogat, és a csomagverziók a prod és prod-fmt környezetekkel együtt történnek rögzítésre, hogy a prod környezet esetleges hibáit a cicd környezet is felfedje.
cicd-fmt
Ez a környezet nem tudja futtatni a rendszert. Célja a kódminőség ellenőrzése a CI/CD build job-ban. Ennek megfelelően a kódformázási és lint-elési task-okat tudja végezni (a függőséghasználatot nem tudja ellenőrizni a cicd-nél leírtak miatt). Kizárólag a Linux rendszer támogatja, és a csomagverziók a prod és prod-fmt környezetekkel együtt történnek rögzítésre, hogy a build job-ban kevesebb csomagot kelljen letölteni (hiszen a cicd is ezekhez van fixálva).