Ebben az alfejezetben egy projektkörnyezet három, egymástól élesen
különböző pillanatfelvételét választjuk szét: a
pyproject.toml-ban megfogalmazott függőségi tartományt, az
uv.lock-ban rögzített pontos feloldást, és a
.venv-ben ténylegesen telepített csomagkészletet. A
megfigyelési egység most nem adatsor, hanem egy projektkörnyezeti
állapot.
A labor bemenete a mellékelt lab/pyproject.toml, amely a
Northstar-projekt alapvető numerikus függőségeit írja le. A szállított
labor szándékosan nem tartalmaz uv.lock
fájlt. A feladat: saját gépen készítsük el a lockot, telepítsük a
környezetet, majd bizonyítsuk, hogy a futás friss feloldás nélkül,
--locked módban megismételhető.
Előzetes becslés: az első uv lock létrehoz egy, a
pyproject.toml-nál nagyobb uv.lock fájlt, mert
a tranzitív függőségeket is rögzíti. A uv sync --locked
parancs 0 kilépési kóddal zárul, a környezet Python-verziója 3.12.x, és
a --locked módú második futtatás között a lock fájl hash-e
változatlan marad.
A leggyakoribb félreértés az, hogy a pyproject.toml, az
uv.lock és a .venv ugyanannak a dolognak három
neve. Valójában három különböző kérdésre válaszolnak:
| Réteg | Mit mond? | Példa |
|---|---|---|
pyproject.toml |
Mi az elfogadható? | pandas>=2.2,<3 |
uv.lock |
Mit választottunk pontosan? | pandas==2.2.3 |
.venv |
Mi van ténylegesen telepítve? | site-packages/pandas, importálható |
A függőségi tartomány (dependency range) egy verzióhalmazt enged meg.
A pandas>=2.2,<3 feltétel két részből áll: a verzió
legyen legalább 2.2, és legyen kisebb 3-nál. Például a 2.2.3 mindkét
feltételt teljesíti:
igaz, és
is igaz. A tartomány azonban önmagában nem mondja meg, hogy éppen
2.2.1-et, 2.2.3-at vagy egy jövőbeli 2.2.x-et telepítsünk.
A lockfájl (lockfile) ezt a döntést rögzíti. Az uv lock
parancs feloldja (resolve) az összes tartományt, azaz megkeresi az
egymással kompatibilis pontos verziókat, és a teljes függőségi fát
kiírja az uv.lock fájlba. Egy szemléltető kivonat:
# uv.lock, szemléltető kivonat; a pontos szerkezet uv-verziófüggő lehet
version = 1
requires-python = ">=3.12,<3.13"
[[package]]
name = "numpy"
version = "2.2.1"
source = { registry = "https://pypi.org/simple" }
[[package]]
name = "pandas"
version = "2.2.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy" },
{ name = "python-dateutil" },
{ name = "pytz" },
]A .venv könyvtár a harmadik réteg: itt már nem előírás,
hanem tényleges importálható anyag van. Ez a három réteg eltérhet
egymástól. A lock pontos verziója nem garantálja, hogy a
.venv-ben is az van, ha valaki kézzel beleír a környezetbe;
a pyproject tartománya pedig akkor is érvényben marad, ha a
lock egy régebbi feloldást őriz.
uv lock,
uv sync és a zárolt/fagyasztott módA laborban a következő parancssort használjuk:
uv lock: explicit feloldás. Beolvassa a
pyproject.toml függőségeit, és létrehozza vagy frissíti az
uv.lock-ot. Az első futtatás hálózatot igényel.uv sync --locked: a lock alapján telepíti a
.venv-et. A --locked kapcsoló előtte
ellenőrzi, hogy a lock még összhangban van-e a
pyproject.toml-lal. A lock egy kivonatot tárol a projekt
definíciójáról; ha a pyproject változott, a parancs hibával
megáll. Így a friss feloldás nem történik meg véletlenül.uv run --locked --no-sync: a projekt környezetében
futtat egy parancsot. A --locked itt is a lock aktualitását
követeli meg; a --no-sync pedig megakadályozza, hogy a
futás maga módosítsa a környezetet. Ez kényelmes a lock rögzítésének
utólagos bizonyításához.A --frozen kapcsoló nem erősebb a
--locked-nál, hanem más célt szolgál: kihagyja az
aktualitásvizsgálatot. A parancs a lockot tekinti igazságnak, és nem
ellenőrzi, hogy a pyproject.toml időközben megváltozott-e.
A --frozen gyorsabb, és hasznos lehet olyan automatizált
környezetben, ahol a lockot már korábban érvényesítettük; a fejlesztői
munkamenetben viszont a --locked a biztonságosabb
választás.
Az uv lock --check read-only ellenőrzést végez: 0
kilépési kóddal tér vissza, ha a lock érvényes, és nem nulla kóddal, ha
a projekt definíciója megváltozott. A pontos kilépési kód és a
hibaszöveg a helyi uv verzió dokumentációjában ellenőrizhető.
A pyproject.toml két, egymástól eltérő szerepű
kiegészítő szakaszt ismerhet. A függőségi csoport (dependency group) a
projekt belső fejlesztői környezetét szervezi:
[dependency-groups]
dev = [
"pytest>=8,<9",
"ruff>=0.5,<1",
]Az opcionális extra (optional extra) viszont a projekt mint közzétett csomag fogyasztói számára kínál kiegészítő képességet:
[project.optional-dependencies]
plot = [
"matplotlib>=3.8,<4",
]Az uv.lock a csoportokat és az extrákat is rögzíti, de a
telepítéskor kiválasztjuk, melyikre van szükség. Például a
uv sync --locked --group dev a törzsfüggőségek mellett a
dev csoportot is telepíti, míg a
uv sync --locked --extra plot a plot extrát
adja hozzá. A laborban az alapút csak a törzsfüggőségeket igényli; a
bővítő fejezetek eszközei külön csoportként vagy extraként állnak
rendelkezésre, és az adott fejezetben kapcsoljuk be őket. A pontos
kapcsolók a helyi uv sync --help kimenetében
ellenőrizhetők, mert a CLI alakja verziófüggő.
Készítsünk egy kis uv_demo projektet, amelyen mindhárom
réteg és a --locked üzemmód kézzel ellenőrizhető.
# uv_demo/pyproject.toml
[project]
name = "lock-demo"
version = "0.1.0"
requires-python = ">=3.12,<3.13"
dependencies = [
"numpy>=1.26,<3",
"pandas>=2.2,<3",
]
[dependency-groups]
dev = [
"pytest>=8,<9",
]
[project.optional-dependencies]
plot = [
"matplotlib>=3.8,<4",
]A környezetjelentéshez egy apró, függőség nélküli scriptet
használunk. Ez az 3.1-ben megismert sys.executable és
sys.prefix szerződést egészíti ki a csomagverziókkal:
# uv_demo/check_lock.py
import importlib.metadata as md
import json
import sys
packages = sys.argv[1:]
print(json.dumps({p: md.version(p) for p in packages}, indent=2))Linux/macOS rendszeren, bash munkakörnyezetben a uv_demo
munkakönyvtárból:
# munkakönyvtár: uv_demo
uv lock
uv lock --check
# szemléltető kimenet; exit code 0, ha a lock érvényes
uv sync --locked --group dev
uv run --locked --no-sync python check_lock.py numpy pandasA példában várható, szemléltető kimenet:
{
"numpy": "2.2.1",
"pandas": "2.2.3"
}
A verziók az adott nap elérhető csomagjaitól és a tartományoktól
függnek; a pandas>=2.2,<3 tartományban a 2.2.3 a
legfrissebb 2.2-es kiadás, ezért ez a várható érték, de a lockot nem a
várakozás, hanem a fájl tartalma ellenőrzi.
Az ismétléshez rögzítsük a lock hashét a futás előtt és után. Linux/macOS:
shasum -a 256 uv.lock > /tmp/lock_before.txt
uv run --locked --no-sync python check_lock.py pandas
shasum -a 256 uv.lock > /tmp/lock_after.txt
diff /tmp/lock_before.txt /tmp/lock_after.txt && echo "lock unchanged"Windows PowerShellben ugyanez:
# munkakönyvtár: uv_demo
$before = (Get-FileHash uv.lock -Algorithm SHA256).Hash
uv run --locked --no-sync python check_lock.py pandas
$after = (Get-FileHash uv.lock -Algorithm SHA256).Hash
$before -eq $afterAz elvárt eredmény szemléltető jelleggel True, tehát a
lock fájl a második futtatás során sem változott.
A munkapéldában három ellenőrző invariantet rögzítünk.
uv.lock pandas
bejegyzésének verziója a >=2.2,<3 intervallumba esik,
és a requires-python mező megfelel a projekt
Python-korlátjának.check_lock.py kimenete és a lock megfelelő bejegyzése
megegyezik. Ha nem, a uv sync --locked újratelepíti a lock
szerinti verziót.--locked futás alatt
változatlan. A hash-egyenlőség azt igazolja, hogy a parancs nem
végzett csendes újrafeloldást.A uv run --locked --no-sync tehát nem a környezet
tartalmát hasonlítja a lockhoz, hanem a projekt definícióját. A
--no-sync arra szolgál, hogy a futás maga ne módosítsa a
.venv-et. Így a munkamenet a következő sémára épül: előbb
explicit uv lock, utána uv sync --locked,
végül uv run --locked --no-sync a tényleges munkához.
Lockfájl és hordozhatóság. A lockfájl a függőségfeloldás eredményét
rögzíti, de nem helyettesíti az interpreter-, operációsrendszer- és
architektúra-követelmények leírását. A uv sync --locked
sikerét a jelen dokumentációhoz ténylegesen használt
uv --version mellett kell igazolni; egy generált lockfájl
jelenléte nem önmagában futtatási bizonyíték.
Tisztasági kontroll: új virtuális környezetben telepítés rögzített függőségekkel, a projekthez tartozó importok füsttesztje és az eltérés dokumentálása. A rövid távú gyakorlati parancsot mindig a verzióhoz tartozó hivatalos súgóval kell egyeztetni.
1. feladat — Értelmezés. Egy projekt
pyproject.toml-jában
dependencies = ["pandas>=2.2,<3"] áll, az
uv.lock-ban pandas==2.2.3, és a
uv run --locked --no-sync python check_lock.py pandas
parancs kimenete {"pandas": "2.3.1"}. Mit jelent a kimenet?
Melyik parancs állítja helyre a lock és a környezet egyezését? Miért nem
elegendő ehhez a pyproject.toml tartománya?
2. feladat — Implementálás a labon. A mellékelt
lab mappa nem tartalmaz uv.lock fájlt. A
lab/pyproject.toml alapján készítsd el a lockot, telepítsd
a környezetet --locked módban, majd futtasd le a fenti
check_lock.py scriptet a lab három alapvető csomagjára:
numpy, pandas, scikit-learn. A
scriptet a lab/scripts/check_lock.py útvonalon helyezd el,
ha még nincs ott. Rögzítsd a lock hashét a futás előtt és után; az
elvárt eredmény változatlan hash.
3. feladat — Hibadiagnózis. Egy friss klónban a
tanuló a
uv run --locked --no-sync python scripts/check_lock.py pandas
parancsot adta ki, és a következő hibát kapta:
error: No uv.lock found. Mi a hiba oka? Mi a helyes
parancssor a hibából való kilábaláshoz? Indokold meg, miért nem a
uv run --frozen a megoldás.
4. feladat — Megváltozott feltétel. A fenti
uv_demo miniprojekt pyproject.toml-jában add
hozzá az alábbi opcionális extrát:
[project.optional-dependencies]
plot = [
"matplotlib>=3.8,<4",
]Friss lock készítése nélkül add ki a
uv run --locked --no-sync python check_lock.py pandas
parancsot. Milyen kimenet várható, és miért? Ezután add meg a helyes
parancssort, és ellenőrizd, hogy a matplotlib is
importálható.
1. feladat. A kimenet azt mutatja, hogy a
.venv eltér a locktól: a lock 2.2.3-at ír elő, a telepített
környezetben 2.3.1 van. A helyreállítás uv sync --locked,
mert ez a locknak megfelelő verziót telepíti. A pyproject
tartománya önmagában nem elegendő, mert a 2.3.1 is teljesíti a
>=2.2,<3 feltételt; a lock az, amely a pontos verziót
rögzíti.
2. feladat. A lab pyproject.toml-jában
ellenőrizd, hogy a dependencies szakasz tartalmazza a
numpy, pandas, scikit-learn
csomagokat; a mellékelt lab szerződése szerint a
starter_experiment.py ezeket vagy ezek egy részhalmazát
használja. Ha a script még nincs ott:
# lab/scripts/check_lock.py
import importlib.metadata as md
import json
import sys
packages = sys.argv[1:]
print(json.dumps({p: md.version(p) for p in packages}, indent=2))Futtatás a lab munkakönyvtárból, Linux/macOS bash
alatt:
cd lab
uv lock
uv lock --check
uv sync --locked
shasum -a 256 uv.lock > /tmp/before.txt
uv run --locked --no-sync python scripts/check_lock.py numpy pandas scikit-learn
shasum -a 256 uv.lock > /tmp/after.txt
diff /tmp/before.txt /tmp/after.txt && echo "lock unchanged"Windows PowerShell alatt a hash rögzítése:
cd lab
uv lock
uv sync --locked
$before = (Get-FileHash uv.lock -Algorithm SHA256).Hash
uv run --locked --no-sync python scripts/check_lock.py numpy pandas scikit-learn
$after = (Get-FileHash uv.lock -Algorithm SHA256).Hash
$before -eq $afterA lab fájl szerinti pontos kimenet a helyi gépen mért verzióktól függ, ezért azt a tanulónak kell rögzítenie. A lényegi ellenőrzés a hash-egyenlőség, nem a kézzel kitalált verziószám.
3. feladat. A hiba oka az, hogy a friss klónban
nincs uv.lock; a --locked mód nem hozza létre,
hanem megköveteli a lock meglétét. A helyes sorrend:
uv lock
uv sync --locked
uv run --locked --no-sync python scripts/check_lock.py pandasA uv run --frozen nem oldja meg a hibát, mert a
fagyasztott mód sem hoz létre hiányzó lockot; ráadásul kihagyja a
pyproject és a lock egyezésének ellenőrzését, így csendes
elavuláshoz vezethet.
4. feladat. A pyproject.toml módosítása
után a uv run --locked --no-sync parancs hibával áll meg,
mert a lock korábban rögzített kivonata nem egyezik az új projekt
definícióval. A pontos hibaszöveg a helyi uv kiadásban ellenőrizhető; a
lényeg az, hogy a --locked megakadályozza a szándéktalan
újrafeloldást. A helyes sorrend:
# munkakönyvtár: uv_demo
uv lock
uv sync --locked --extra plot
uv run --locked --no-sync python check_lock.py pandas matplotlibAz ellenőrző invariant: az új lockban a plot extra
függőségei is megjelennek, a lock hash-e megváltozik, és a
matplotlib verzió importálhatóvá válik.
Az egyik jellegzetes hiba az, hogy a tanuló a friss laborban
uv run --locked parancsot ad ki, mert úgy gondolja, a
--locked ellenőrzi, sőt létrehozza a lockot. Az ellenpélda:
a lab/pyproject.toml létezik, de a uv.lock még
nem; a --locked parancs hibát ad, mert nincs mit
ellenőriznie. A csomag tehát nem állítja, hogy egy még nem létező
lockfájlt már ellenőrzött.
A másik gyakori félreértés: „a --frozen erősebb, mert
teljesen fagyasztott”. Az ellenpélda ugyanez a projekt, de most a lock
már létezik, és a pyproject.toml-t megváltoztatjuk. A
uv run --locked hibát ad; a uv run --frozen
viszont a régi lockkal tovább dolgozik, és nem jelzi, hogy a projekt
definíciója már mást ír elő. A --frozen tehát nem erősebb
garancia, hanem az aktualitásvizsgálat kihagyása. Reprodukálható
átadásnál a --locked ellenőrzött friss lockot követel, a
--frozen csak a már érvényesített lock gyors végrehajtására
való.
Önellenőrző állítások: „a lock a telepített környezet pontos listája”
hamis, mert a .venv ettől függetlenül eltérhet; „a
tartomány a lockban van” hamis, mert a tartomány a
pyproject-ben, a pontos verzió a lockban van. Az 2.2-ból
ismert kilépési kód és az 3.1-ből ismert
sys.prefix-ellenőrzés együtt adja a rétegek bizonyítékát: a
parancsok exit code-ja a lock érvényességét, a környezetjelentés a
telepített anyag valódi forrását mutatja.
A pyproject.toml tartománya azt mondja meg, mi
elfogadható; az uv.lock azt, hogy az adott feloldáskor
pontosan mit választottunk; a .venv azt, hogy mi van
ténylegesen telepítve. A uv lock explicit feloldást készít,
a uv sync --locked a lockot és a környezetet hozza
összhangba, a uv run --locked --no-sync pedig friss
feloldás nélkül futtat. A --frozen kihagyja az
aktualitásvizsgálatot, ezért nem erősebb, hanem más üzemmód. A következő
alfejezetben a bináris csomagok, a BLAS és a conda-döntés kerül sorra:
ott az eddigi lockolt függőségek mellett a natív futtatási környezet
kérdéseit vizsgáljuk.