- 1. Bevezetés
- 2. Könyvtárszerkezet
- 3. Környezet
- 4. Az
__init__.py
fájl - 5. Tesztelés
- 6. A
setup.py
fájl - 7. További lehetőségek
- TODO
- Irodalom
A modul (module) egy python fájl, ami importálható, névteret alkot és tetszőleges további python objektumokat tartalmazhat.
A csomag (package) egy olyan könyvtár, ami tartalmaz egy __init__.py
fájlt, továbbá tartalmazhat további alcsomagokat (alkönyvtárakat) és
modulokat (python fájlokat). A csomag is importálható, névteret alkot és
további python objektumokat tartalmazhat.
Megjegyzés: A modul~fájl és a csomag~könyvtár csak analógia, nem minden esetben igaz. Részletek itt.
A csomagokat a Python csomagkezelőjével, a
pip
-pel lehet telepíteni, frissíteni,
eltávolítani. A pip
képes verziókezelő repozitóriumokból is telepíteni, így
pl. a Github-ról is, de a python csomagok publikálásának szokott módja a
csomag feltöltése a pypi.org-ra (PyPI: Python Package
Index). Ennek mikéntjéről lesz szó az alábbiakban.
A pypi.org-ot és a csomagoláshoz szükséges eszközöket a PyPA (Python Packaging Authority) fejleszti és tartja karban. Honlapjukon (pypa.io) sok hasznos anyag elérhető csomagolás és terjesztés témakörben.
hellopypa/
hellopypa/
__init__.py
__main__.py
example.cfg
hellopypa.py
version.py
test/
__init__.py
test_hello.py
LICENSE
MANIFEST.in
README.md
requirements.txt
requirements-dev.txt
setup.py
Fontosabb könyvtárak és fájlok:
hellopypa/
: A csomagunk fő könyvtára. Általában jó, ha ez megegyezik magának a repónak a nevével (külsőhellopypa/
könyvtár), de nem szükséges.test/
: A csomaghoz való tesztek könyvtára. A tesztek nem részei a csomagnak, csak a repónak.LICENSE
: Licenc, a lehetőségeket l. itt és itt, további tanácsok itt.MANIFEST.in
: Itt soroljuk fel a csomaghoz tartozó nem python fájlokat (binárisok, konfig fájlok, stb).README.md
: Readme fájl, röviden leírja, hogy mire jó a csomag, hogyan kell telepíteni és hogyan lehet futtatni. A markdown formátumról bővebben itt, a tartalmáról itt lehet olvasni.requirements*.txt
: Ezekben vannak felsorolva azok a python csomagok, amelyeket használunk (függőségek). Arequirements.txt
tartalmazza magának a csomagnak a függőségeit, arequirements-dev.txt
pedig a fejlesztéshez szükséges függőségeket (tesztelés, linter, stb).setup.py
: Ez a fájl tartalmazza csomagoláshoz kellő metaadatokat.
Hozzunk létre a csomagnak külön virtuális környezetet és aktiváljuk (részletek itt és itt):
python3 -m venv .venv
source .venv/bin/activate
Telepítsük a csomaghoz (requirements.txt
) valamint a csomagoláshoz és
fejlesztéshez szükséges függőségeket (requirements-dev.txt
):
pip install -r requirements-dev.txt
Megjegyzés: A requirements-dev.txt
importálja sima requirements.txt
-t is.
A requirements.txt
fájlok leírását l.
itt
és itt.
A csomagoláshoz az alábbi csomagok szükségesek:
setuptools
: Ez asetup.py
függősége.twine
: Ezzel lehet a pypi.org-ra feltölteni az elkészült csomagot.wheel
: Ez kell a 2012-ben bevezetett wheel csomagformátumhoz (l. PEP 427).
Az __init__.py
lehet üres is, de ekkor is léteznie kell. Ha nem üres, akkor
a csomag importálásánál a tartalma végrehajtódik. Szokás a metaadatok és az
API meghatározására használni.
Metaadatok: Kisebb projekteknél itt lehet felsorolni a csomag szerzőit, verzióját, licencét, megadni email-címet, karbantartót, hálát kifejezni a hozzájárulóknak, stb. Részletek itt. A verziót érdemes külön fájlban tartani, l. alább a Verzió fejezetet.
API: Alapesetben ha használni szeretnénk egy importált csomag egy függvényét, akkor azt így tudjuk hívni:
csomag[.alcsomag].fájl.függvény()
Ebből a csomag
-ot és a függvény
-t nem lehet elhagyni, de az alcsomag
és
a fájl
általában felesleges. A felhasználónak csak azt kellene
megjegyeznie, hogy melyik függvény melyik csomagban van, azt nem, hogy melyik
csomag melyik fájljában van. Ráadásul a csomag írói is szeretik a kódot
rugalmasan átszervezni a háttérben, pl. egy nagyra nőtt fájl egy részét
új fájlba írni anélkül, hogy eltörnék az API-t.
Mivel az __init__.py
-ban található kód importáláskor végrehajtódik,
ezért érdemes itt importálni a publikusnak szánt függvényeket, osztályokat, ezzel a csomag importálásakor ezek az objektumok is közvetlenül használhatók lesznek. Példa:
# mypackage/__init__.py
from file1 import function1, function2
from file2 import function3
Ezután a használat egyszerű:
import mypackage
mypackage.function1()
Megjegyzés: Ha az __init__.py
-ban csillaggal importálunk (from file import *
), akkor az alulvonással kezdődő objektumok nem kerülnek
importálásra (a teljes elérési útjukon keresztül továbbra is elérhetőek
lesznek, részletek
itt).
Mielőtt csomagolnánk, teszteljük le az alkalmazásunkat. A teszteléshez
használhatjuk a hagyományos
unittest-et, vagy az
újabban elterjedt pytest-et. A
test/
könyvtárban vannak a tesztfájlok, ezeket pytest estén a következő
paranccsal futtathatjuk:
pytest --verbose test/
Megjegyzés: a test/
könyvtár maga is csomag, kell benne lennie
__init__.py
fájlnak.
Magát a csomagolást (a terjeszthető és telepíthető formátum létrehozását) a
setuptools nevű python
csomag végzi. A setup.py
fájl tartalmazza a setuptools számára szükséges
adatokat. Az adatokat lehet közvetlenül a setup.py
-ba is beírni, de néha
hasznosabb máshol tárolni az adatot és a setup.py
-ban csak importálni, vagy
más módon beolvasni.
Egy viszonylag minimalista példa:
import setuptools
with open('README.md') as fh:
long_description = fh.read()
setuptools.setup(
name='csomagnév',
version='0.0.1',
author='szerző',
description='Minimalista példa csomag',
long_description=long_description,
long_description_content_type='text/markdown',
url='https://github.com/szerző/csomagnév',
packages=setuptools.find_packages(exclude=['test']),
classifiers=[
'Programming Language :: Python :: 3',
'License :: OSI Approved :: MIT License',
'Operating System :: POSIX :: Linux',
],
python_requires='>=3.6',
)
A setuptools.setup fontosabb mezői:
name
: A csomag neve (kötelező).version
: A csomag verziója (kötelező). A pypi.org-ra nem lehet kétszer ugyanazt a verziószámú csomagot feltölteni, akkor sem, ha amúgy különböznek.author
: A csomag szerzője.description
: Rövid leírás.long_description
: Hosszú leírás, jellemzően magát a README.md-t szokták megadni. A PyPI ezt fogja a csomag oldalán megjeleníteni. Ha markdown fájlt adunk meg, akkor meg kell adnunk a formátumot is (.rst az alapértelmezett).url
: A projekt honlapja.packages
: Itt lehet megadni a csomag kódját tartalmazó könyvtárak listáját. Ezekben fogja kereseni a python fájlokat. Nagyobb projekteknél érdemes a setuptoolsfind_packages()
függvényére bízni a dolgot. Azexclude=[dir1, dir2, ...]
paraméternek megadott könyvtárakban nem fog keresni.classifiers
: A PyPI számára megadható címkék listája itt.python_requires
: Megadható a minimum python verzió.
Futtassuk a setup.py
fájlt:
python3 setup.py sdist bdist_wheel
A repónkban három új könyvtár fog létrejönni: egy build/
, egy dist/
és
egy csomagnév.egg-info/
(érdemes ezeket a .gitignore
fájlba felvenni,
vagy a GitHub python-hoz írt .gitignore
fájlját
használni). Ezek közül a dist/
ami fontos, ebben található ugyanis a
csomagunk terjeszthető és telepíthető változata.
A csomag közvetlenül telepíthető a pip install .
paranccsal, vagy
regisztrációt követően feltölthető a pypi.org oldalra a következő paranccsal:
python3 -m twine upload dist/*
Ezután bármelyik gépen telepíthető a csomag a pip install csomagnév
paranccsal.
A pypi.org oldalnak van egy teszt változata is, ha csak kísérletezni szeretnénk, javasolt ezt használni. A fenti parancsok ekkor így módosulnak:
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
pip install --index-url https://test.pypi.org/simple/ hellopypa
További tanácsok és lehetőségek a terjeszthető csomag testreszabására.
A csomag verzióját érdemes egy helyen tárolni csak és máshol csak innen beolvasni. A lehetőségeket l. itt. Az alábbi megoldás lényege, hogy a csomagon belül egy külön fájlt használunk erre (hellopypa/version.py
). Ezt a fájlt importáljuk a setup.py
-ban és a hellopypa/__init__.py
-ban is. Ezzel elkerülhetők a hellopypa/__init__.py
közvetlen importálásának problémái (l. az előbbi cikk 6. pontjához írt figyelmeztetést), de telepítés nélkül is hozzáférhető lesz a verzió, mintha az __init__.py
-ban lenne közvetlenül.
# hellopypa/version.py
__version__ = '0.0.3'
# hellopypa/__init__.py
# ...
from hellopypa.version import __version__
# ...
# setup.py
# ...
from hellopypa.version import __version__
# ...
setuptools.setup(
# ...
version=__version__,
# ...
)
A setuptools csak a python fájlokat veszi figyelembe. Ha más fájlokat is a csomaghoz szeretnénk adni (konfigurációs fájlokat, binárisokat, adatot), akkor két dolgot kell csinálnunk.
-
Létre kell hoznunk egy MANIFEST.in fájlt, amiben felsoroljuk, hogy miket szeretnénk még a csomaghoz adni. Részletek itt. Példa: adjuk a projekthez a .cfg kiterjesztésű fájlokat.
# MANIFEST.in include hellopypa/*.cfg
-
A setup.py-ba is bele kell írni, hogy további fájlok is lesznek.
# setup.py # ... setuptools.setup( # ... include_package_data=True, # ... )
Ha csomagunkat a pip install hellopypa
után nem csak importálva, de
parancssori alkalmazásként is szeretnénk használni, akkor két dolgot
tehetünk.
-
Egy python csomag futtatható az
-m
kapcsolóval (pl.# python -m hellopypa
). Ehhez az kell, hogy a csomagban legyen egy__main__.py
fájl, a python ezt fogja keresni és ha létezik, akkor futtatni. Részletek (nem mintha nagyon lennének) itt. -
Egy python csomag futtatható rendes, telepített parancsként is (pl.
# hellopypa
). Ekkor a setup.py-ban meg kell adni egy úgynevezett belépési pontot, konkrétan egy függvényt, amit meg fog hívni a python. Részletek itt. Példa:# setup.py # ... setuptools.setup( # ... entry_points={ "console_scripts": [ "hellopypa=hellopypa.__main__:main", ] }, # ... )
Átmeneti megoldás, amíg nincs rendes automatizálás.
make clean
: A build-elés során keletkezett könyvtárak törlése (buld/
,
dist/
, *.egg-info/
).
make test
: Tesztek futtatása.
make build
: Build-elés.
make release_major
: Major verziószám váltás, új release a GitHub-on és a
PyPI-n.
make release_minor
: Minor verziószám váltás, új release a GitHub-on és a
PyPI-n.
make release_patch
: Patch verziószám váltás, új release a GitHub-on és a
PyPI-n.
- Tartalom
- Bevezetés: modul, csomag, pypi
- Könyvtárszerkezet
- Környezet
- Tesztelés
- Dokumentáció
- A
setup.py
fájl - A
MANIFEST.in
fájl -
__main__.py
, CLI -
__init__.py
, API - Verziózás
- Csomagolás
- Közzététel
- Automatizálás
- Telepítés
- lokálisan
- pypi
- make
- függőség buildelése a setup.py használatával???
- függőség letöltése telepítéskor???
- PyPA gyorstalpalója: https://packaging.python.org/tutorials/packaging-projects/
- PyPA útmutatói egyes témákhoz: https://packaging.python.org/guides/
- Real Python tutorial: https://realpython.com/pypi-publish-python-package/
- setuptools dokumentáció: https://setuptools.readthedocs.io/en/latest/