Die Struktur eines Python-Projekts

Ein Python-Projekt mag am Anfang nur aus ein oder zwei Dateien bestehen. Über eine Projektstruktur muss man sich in diesem Fall keine Gedanken machen. Anders sieht es aber aus, wenn das Programm wächst. Neben den eigentlichen Python-Dateien könnte irgendwann auch noch eine Dokumentation dazukommen. Und in der Regel sollen die Tests in separaten Dateien und einem eigens dafür vorgesehenen Verzeichnis gespeichert werden. Es stellt sich dann zwangsläufig die Frage nach einer sinnvollen Struktur.

Diese Frage ist nicht einfach zu beantworten. Denn im Internet sowie der einschlägigen Fachliteratur finden sich dazu unterschiedliche Vorschläge. Mit anderen Worten: Es gibt nicht die Projektstruktur. So sind die nachfolgenden Ausführungen ebenfalls nur als Vorschlag zu verstehen.

Eine einfache Python-Projektstruktur

Eine typische Struktur für ein Projekt mit dem Namen „my_project“ könnte folgendermaßen aussehen:

.
├── README.md
├── docs
├── my_project
│       ├── __init__.py
│       └── main.py
├── pytest.ini
├── requirements-dev.txt
├── requirements.txt
├── setup.cfg
├── setup.py
└── tests
    └── __init__.py

Innerhalb des Projekts „my_project“ befinden sich drei Unterordner:

  • my_project: Dieser Ordner hat (hier) die gleiche Bezeichnung wie das Projekt. Anstelle des Projektnamens verwenden manche Entwickler einen Ordner mit der Bezeichnung src. Der Ordner mit dem Projektnamen ist dann ein Unterordner von src. (Diesbezüglich wird manchmal auch vom „src Layout“ gesprochen.)
    Bei dem Verzeichnis my_project handelt sich um ein Paket (Package), weswegen dieser Ordner eine Datei namens __init__.py enthält. Diese Datei ist (heutzutage) in der Regel leer. Sie wird aufgerufen, wenn ein Paket oder ein Modul dieses Pakets importiert wird.
  • docs: In diesem Verzeichnis befinden sich alle notwendigen Dateien für die Dokumentation (z.B. für den Dokumentations-Generator Sphinx).
  • tests: Hier befinden sich alle Dateien, die Tests enthalten. Auch dieses Verzeichnis hat eine Datei mit dem Namen __init__.py. Sofern als Test-Framework pytest verwendet wird, kann im Projektordner noch optional eine Konfigurationsdatei für pytest dazukommen: pytest.ini.

Die für dieses Projekt erforderlichen externen Bibliotheken, zum Beispiel numpy oder matplotlib werden in der Datei requirements.txt aufgeführt. Sie können dann mit pip wie folgt installiert werden:

pip3 install -r requirements.txt # Linux, macOS
pip install -r requirements.txt  # Windows

Manche Entwickler lagern jene Pakete, die nicht unmittelbar für die Ausführung dieses Projekts erforderlich sind, in eine Datei namens requirements-dev.txt aus (z.B. pytest). Dies ist jedoch optional.

Damit bleiben noch die Dateien setup.py und setup.cfg. In manchen Projekten findet sich nur eine Datei mit der Bezeichnung setup.py.

Diese Datei bzw. diese Dateien ermöglichen das Erstellen eines Installations-Pakets. Sie sind z.B. erforderlich, wenn ein Python-Programm auf der Plattform pypi.org veröffentlicht werden soll (so dass es sich über pip installieren lässt).

Früher existierte nur eine Datei mit dem Namen setup.py. Falls nur diese Datei (und nicht auch noch setup.cfg) verwendet wird, enthält sie die Basisinformationen zum Projekt. Für unser Beispielprojekt könnte sie folgenden Inhalt haben:

from setuptools import setup, find_packages

VERSION = '0.1.0'

setup(
    name='my_project',
    version=VERSION,
    license='MIT',
    description='Just an example.',
    author='My Name',
    author_email='my_name@xyz.com',
    url='https://github.com/<user>/<project>',
    packages=find_packages(exclude=('tests', 'docs')),
    python_requires='>=3.8'
)

Die Datei setup.py kann recht komplex werden. Deswegen wurde die Konfigurationsdatei setup.cfg eingeführt, die dann die erforderlichen Metadaten enthält. Wird setup.cfg verwendet, dann reduziert sich der Inhalt von setup.py auf zwei Zeilen:

import setuptools

setuptools.setup()

Und setup.cfg könnte folgenden Inhalt haben:

[metadata]
name = my_project
author = 
author-email = 
license =
long_description = file: README.md
url = https://
requires-python = >= 3.8

Ergänzende Hinweise

Die Datei main.py stellt den Einstiegspunkt des Programms dar. Die Bezeichnung kann frei gewählt werden, aber häufig heißt diese Datei main.py oder cli.py (wenn es sich um ein Konsolenprogramm handelt).

Es ist eine gute Idee, zu jedem Projekt eine README.md hinzuzufügen. Spätestens wenn ein Projekt veröffentlicht wird, ist so eine Datei erforderlich und bietet Dritten eine Orientierung. Ergänzend findet sich in Projekten (bei Github, GitLab, etc.) häufig auch eine CONTRIBUTING.md, die anderen Entwicklern Hinweise zur Teilnahme am Projekt bietet.

Werft bei Github einen Blick auf die Dateien setup.py und setup.cfg. Dadurch erhaltet Ihr einen Eindruck davon, welche Metadaten andere Entwickler hinzugefügt haben.

Der Ordner „tests“ befindet sich in diesem Beispiel in der obersten Verzeichnisebene. Manche Entwickler bevorzugen es hingegen, dieses Verzeichnis als Unterverzeichnis zum Paketverzeichnis anzulegen.

Auf Github findet Ihr ein Shellskript, das dafür verwenden werden kann, automatisch ein Projekt-Grundgerüst zu erstellen. Dieses Skript erhebt keinen Anspruch auf Vollständigkeit. Es mag für auch aber ein guter Ausgangspunkt für ein eigenes Skript sein.

Im Internet finden sich weitere gute Beispiele zu Python-Projektstrukturen, zum Beispiel im Artikel „Ultimate Setup for Your Next Python Project“, der auch Beispiele zu den Konfigurationsdateien enthält.

Eine sehr umfangreiche Anleitung zur Einrichtung eines Python-Projekts hat Claudio Jolowicz in der Artikelserie Hypermodern Python veröffentlicht.

Und schließlich möchte ich auf eines meiner Projekte hinweisen: fetch-hackernews. Auf Github könnt Ihr Euch die Projektstruktur ansehen. Darüber hinaus findet Ihr dort die Konfigurationsdateien pytest.ini und setup.cfg. Deren Inhalt könnt Ihr als Ausgangspunkt für Euer eigenes Projekt verwenden.

Eine Übersicht zu weiteren Artikeln zur Programmiersprache Python findest Du auf dieser Seite.

Zuletzt aktualisiert am 15. Oktober 2022