Skip to main content

A sample Python package

Project description

license pypi

Hogyan készítsünk python csomagot

1. Bevezetés

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.

2. Könyvtárszerkezet

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). A requirements.txt tartalmazza magának a csomagnak a függőségeit, a requirements-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.

3. Környezet

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 a setup.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).

4. Az __init__.py fájl

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

5. Tesztelés

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.

6. A setup.py fájl

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', 'r') 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 adható meg, hol keresse a python fájlokat. Érdemes a setuptools find_packages() függvényére bízni a dolgot. Az exclude=[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 . paranccal, 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

7. További lehetőségek

További tanácsok és lehetőségek a terjeszthető csomag testreszabására.

7.1. Verzió

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__,
    # ...
)

7.2. Fájlok hozzáadása

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.

  1. 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
    
  2. A setup.py-ba is bele kell írni, hogy további fájlok is lesznek.

    # setup.py
    # ...
    setuptools.setup(
        # ...
        include_package_data=True,
        # ...
    )
    

7.3. Parancssori futtatás

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.

  1. 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.

  2. 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",
            ]
        },
        # ...
    )
    

8. Make

Á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.

TODO

  • 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???

Irodalom

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hellopypa-0.0.11.tar.gz (10.1 kB view hashes)

Uploaded Source

Built Distribution

hellopypa-0.0.11-py3-none-any.whl (9.2 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page