Zu gutem Code gehört eine saubere Dokumentation. Wurde alles im Code dokumentiert? Funktionieren die Beispiele? Wir zeigen, wie Sie das überprüfen.
|
Teil 1 |
Code prüfen |
LU 02/2024, S. 84 |
|
Teil 2 |
Code optimieren |
LU 03/2024, S. 78 |
|
Teil 3 |
Dokumentation prüfen |
LU 04/2023, S. 86 |
Der erste [1] und zweite Teil [2] unserer Artikelserie rund um guten Python-Code legten den Schwerpunkt auf das Validieren und Optimieren von Python-Code, beispielsweise durch das Identifizieren unnötiger Funktionen und Module. Zu jedem Programmierprojekt gehört, auch wenn sich dieser Schritt kaum großer Beliebtheit erfreut, jedoch genauso Dokumentation. Ohne sie lässt sich der Programmcode nur bedingt nutzen, weil keiner dessen Daseinszweck versteht [3]. Dementsprechend kümmern wir uns nun darum, den Code auf bestehende Dokumentation sowie deren Vollständigkeit und Korrektheit zu überprüfen [4]. Der Fokus liegt hier auf Methoden, die sich automatisieren lassen, um damit im Idealfall CI/CD-Pipelines ausstatten zu können.
Die Tabelle “Werkzeugübersicht” vergleicht die verfügbaren, unter einer freien Lizenz stehenden Werkzeuge und deren Funktion. Darin finden sich Werkzeuge zur stilistischen und orthografischen Prüfung wie PyDocstyle [5], PyLint [6] und PyEnchant [7].
|
Aufgabe/Funktion |
PyDocstyle |
Darglint [8] |
Interrogate [9] |
PyEnchant |
PyLint |
Docstr-coverage [10] |
Doctest [11] |
Xdoctest [12] |
Pyment [13] |
|---|---|---|---|---|---|---|---|---|---|
|
Stil prüfen |
x |
x |
x |
– |
– |
– |
– |
– |
– |
|
Stil umwandeln |
– |
– |
– |
– |
– |
– |
– |
– |
x |
|
Rechtschreibprüfung |
– |
– |
– |
x |
x |
– |
– |
– |
– |
|
Vollständigkeit prüfen |
– |
x |
x |
– |
– |
x |
– |
– |
– |
|
Beispiele prüfen |
– |
– |
– |
– |
– |
– |
x |
x |
– |
Docstrings
Als Docstrings bezeichnet man speziell formatierte Kommentare im Python-Programmcode. Sie bilden die Basis, um daraus später automatisiert Dokumentation zu erzeugen [14]. Verbreitet sind derzeit sechs Stile: gemäß Python Enhancement Proposal (PEP) 257 [15], für Sphinx [16], NumPy [17] / SciPy [18] (Listing 1), Pydoc [19], Epydoc/Epytext [20] und Google Docstrings [21] (Listing 2). Beide Listing-Beispiele stammen aus der Sphinx-Dokumentation.
In welchem Stil Sie die Kommentare schreiben, hängt von dem Werkzeug ab, das die Kommentare in einem nachfolgenden Schritt auswertet und zu Dokumentation in einem anderen Format verarbeitet, beispielsweise zu HTML. Dabei sollten Sie darauf achten, nicht mehrere verschiedene Stile zu mischen, da ansonsten das Werkzeug beim Erstellen der Dokumentation durcheinanderkommt. Sphinx kann ursprünglich nur mit ReStructuredText [22] umgehen. Die Dokumentationsstile NumPy/SciPy [23] erfordern die Erweiterung Napoleon [24], die Sphinx ab Version 1.3 bereits enthält.
Listing 1
Docstrings im Stil von NumPy/SciPy
def func1(arg1, arg2):
"""Summary line.
Extended description of function.
Parameters
----------
arg1 : int
Description of arg1
arg2 : str
Description of arg2
Returns
-------
bool
Description of return value
"""
return True
Listing 2
Docstrings gemäß Google Python Style Guide
def func2(arg1, arg2):
"""Summary line.
Extended description of function.
Args:
arg1 (int): Description of arg1
arg2 (str): Description of arg2
Returns:
bool: Description of return value
"""
return True
Stilistisch prüfen
Nun prüfen Sie mithilfe von PyDocstyle, ob die Schreibweise der Docstrings dem gewünschten Stil entspricht und ob alle einheitlich sind. Dazu kennt PyDocstyle den Parameter --convention, gefolgt von der Angabe des Stils: pep257 für PEP 257, numpy für NumPy/SciPy und google für Google Docstrings.
Hinsichtlich der beiden Formate Pydoc und Epydoc/Epytext kann PyDocstyle nicht prüfen. Listing 3 zeigt das Ergebnis für den Stil NumPy/SciPy für Listing 1 und Listing 2. Zusammengefasst finden Sie es in der lokalen Datei docstring-test.py. Dabei identifiziert PyDocstyle auf Grundlage der Stile PEP 257 und Google Docstrings lediglich den ersten Fehler (dritte Zeile). Das entspricht allerdings nicht den Erwartungen.
Listing 3
Konformitätstest NumPy/SciPy
$ pydocstyle --convention=numpy docstring-test.py
docstring-test.py:1 at module level:
D100: Missing docstring in public module
docstring-test.py:22 in public function `func2`:
D407: Missing dashed underline after section ('Returns')
docstring-test.py:22 in public function `func2`:
D406: Section name should end with a newline ('Returns', not 'Returns:')
Umwandeln
Die Prüfung der Docstrings hat mehrere anzupassende Stellen offenbart. Bei wenigen zu korrigierenden Zeilen wie in Listing 3 geht das durchaus von Hand. Steigt die Zahl, greifen Sie auf das Werkzeug Pyment zurück. Es wandelt die Docstrings aus einem Format in ein anderes um und vereinheitlicht so die Dokumentation. Dabei unterstützt es Javadoc [25], ReStructuredText, NumPy/SciPy und das Google-Format.
Im ersten Beispiel (Listing 4, erster Aufruf) erhält Pyment beim Aufruf kein Eingabeformat als Parameter und versucht es dementsprechend automatisch zu erkennen. Als Ausgabeformat ist ReStructuredText voreingestellt. Als Ergebnis liefert Pyment eine Patch-Datei im Format ReStructuredText mit den vorgeschlagenen Änderungen auf der Basis der automatischen Erkennung des Docstring-Formats. Explizite Formatangaben machen Sie gegebenenfalls mithilfe der beiden Parameter -i (--input) und -o (--output), jeweils gefolgt vom gewünschten Format.
Listing 4
Patch-Datei
#### datei.py.patch erzeugen $ pyment datei.py #### Patch anwenden $ patch -p1 < datei.py.patch
Die letzte Zeile des Listings veranschaulicht das Einspielen des erzeugten Patches, Abbildung 1 zeigt seinen Inhalt. Zeilen, die mit einem Minuszeichen beginnen, verschwinden beim Einspielen des Patches in der Zieldatei, Zeilen mit einem vorangestellten Pluszeichen fließen dagegen ein.

Abbildung 1: Die Software markiert einzufügende und zu entfernende Zeilen in der Patch-Datei mithilfe von Plus- und Minuszeichen.
Der erste Aufruf in Listing 5 zeigt das Erzeugen eines Patches mit NumPy/SciPy als Eingabeformat und dem Google-Stil als Ausgabeformat. Die Option -b (--backup) bewirkt, dass Patch vor dem Einspielen des Patches eine Sicherheitskopie der Zieldatei erzeugt (zweiter Aufruf). Die dadurch erstellte Backup-Datei heißt docstring-test.py.orig. Möchten Sie hingegen direkt korrigieren und somit weder Patch noch Backup erzeugen lassen, nutzen Sie den Parameter -w (letzter Aufruf).
Listing 5
Patches erzeugen
#### datei.py.patch erzeugen $ pyment -i numpy -o google datei.py #### Patch mit Backup anwenden $ patch -b -p1 < datei.py.patch #### direkte Korrektur $ pyment -i numpy -o google -w datei.py
Inhaltlich prüfen
Dokumentation hilft nur dann tatsächlich weiter, wenn sie stimmt. Mithilfe des Werkzeugs Darglint kommen Sie Unstimmigkeiten zwischen Programmcode und der Dokumentation auf die Schliche. Es prüft, ob die Angaben im Docstring mit dem Funktionskopf übereinstimmen und somit die Dokumentation aller Parameter vollständig ist. Als Formate des Docstrings akzeptiert Darglint Sphinx, NumPy/SciPy und Google.
Listing 6 zeigt den Aufruf von Darglint mit dem Parameter -s (--docstring-style), gefolgt von der Angabe numpy für das Docstring-Format von NumPy/SciPy. Ganz zu Recht bemängelt das Tool die fehlerhaften Parameter und den nicht beschriebenen Rückgabewert für func2(), da die Dokumentation im falschen Format vorliegt.
Listing 6
Darglint
$ darglint -s numpy docstring-test.py
docstring-test.py:func2:21: DAR101: - arg1
docstring-test.py:func2:21: DAR101: - arg2
docstring-test.py:func2:21: DAR201: - return
Eine ähnliche Ausgabe liefert Darglint, wenn Parameter entweder im Funktionskopf oder der Dokumentation fehlen (Listing 7). Ein Minuszeichen in der Ausgabe besagt, dass der Parameter zwar im Funktionskopf vorhanden, aber nicht dokumentiert ist. Ein Pluszeichen bedeutet das Gegenteil – der Parameter ist zwar dokumentiert, fehlt aber im Funktionskopf. Auf diese Weise kommen zudem Tippfehler und falsche Schreibweisen ans Licht, beispielsweise Buchstabendreher im Namen des Parameters.
Listing 7
Fehlende Parameter aufspüren
$ darglint -s google docstring-test.py
docstring-test.py:func3:41: DAR101: - arg3
docstring-test.py:func3:43: DAR102: + arg2
Vollständigkeit prüfen
Nachdem Sie alle Docstrings vereinheitlicht haben und feststeht, dass keine Parameter unter den Tisch gefallen sind, werfen Sie mithilfe von Docstring-coverage einen Blick auf die Vollständigkeit. Das gewährleistet, dass Sie nicht noch andere Dinge vergessen haben. Listing 8 zeigt die Ausgabe des Werkzeugs, die daran erinnert, noch die Dokumentation für das Modul hinzuzufügen (Zeile 4).
Listing 8
Docstr-coverage
$ docstr-coverage docstring-test.py
Checking python files: 100%|??????????????| 1.00/1.00 [00:00<00:00, 574files/s]
File: "docstring-test.py"
- No module docstring
Needed: 4; Found: 3; Missing: 1; Coverage: 75.0%
Häufig finden sich in der Dokumentation kleine Grafiken für unterstützte Formate, sogenannte Badges. Mithilfe des Parameters -b, gefolgt von Pfad und Namen der Bilddatei, erzeugt Docstr-coverage ein Badge zur Abdeckung im SVG-Format.
Rechtschreibung prüfen
Wirkt bestehende Dokumentation stilistisch sauber, heißt das noch nicht automatisch, dass dasselbe für die Orthografie gilt. Fehlern bezüglich Rechtschreibung und Grammatik kommen Sie mit einer passenden Rechtschreibprüfung auf die Spur.
Über PyEnchant besteht von Python aus Zugriff auf die Enchant-Bibliothek [26]. PyLint bietet eine Schnittstelle zu den Unix/Linux-Werkzeugen Ispell, Aspell und Myspell an. Für Flake8 [27] gibt es ein Modul namens Flake8-spellcheck [28], das sich so konfigurieren lässt, dass es ausschließlich Python Docstrings überprüft. Dazu setzt es intern auf das bereits erwähnte PyDocstyle auf.
Beispiele prüfen
Fehlerhafte Beispiele in der Dokumentation erweisen sich häufig als großes Ärgernis. Führen Sie hinterlegte Beispiele aus und entdecken gravierende Unterschiede zwischen den gezeigten und den tatsächlich erzielten Ergebnissen, stellt sich die Frage, was nicht stimmt. Nicht immer sitzt die Fehlerursache vor dem Rechner.
Hier kommen die zwei Pakete Doctest und Xdoctest ins Spiel. Beide suchen nach Programmcode, der in den Docstrings als Beispiel mit passender Ausgabe hinterlegt ist. Doctest und Xdoctest führen den Programmcode aus und prüfen, ob die hinterlegte Ausgabe mit der tatsächlichen Ausgabe übereinstimmt. Sie schlagen Alarm, falls dabei Diskrepanzen auftreten.
Die beiden Werkzeuge unterscheiden sich in zweierlei Hinsicht: Während es sich bei Doctest um einen festen Bestandteil der Python-Distribution handelt, müssen Sie Xdoctest nachinstallieren. Intern setzt Doctest auf reguläre Ausdrücke zum Identifizieren von Fehlern, Xdoctest dagegen auf das Ast-Modul für abstrakte Syntaxbäume [29]. Abbildung 2 zeigt einen Aufruf zur Prüfung von Listing 9, mit dem Ergebnis, dass der erste Aufruf von add() im Beispiel zum dokumentierten Ergebnis passt, der zweite sich jedoch als fehlerhaft erweist.
Listing 9
Python-Code mit Codebeispiel in Docstrings
# calculations.py
def add(a, b):
"""Berechne die Summe aus zwei Zahlenwerten
Beispielaufruf:
>>> add(4.0, 2.0)
6.0
>>> add(4, 2)
7.0
"""
return float(a + b)

Abbildung 2: In calculation.py entspricht lediglich der erste Aufruf von add() der dokumentierten Ausgabe.
Dokumentation erzeugen
Jetzt stimmt Ihre Dokumentation – ein guter Moment, sie in andere Ausgabeformate umzuwandeln. Für eine Ausgabe im Pager wie in Abbildung 3 genügt der Aufruf pydoc3 docstring-test mittels Pydoc völlig. Das Werkzeug liest damit die lokale Datei docstring-test.py aus Listing 1 und Listing 2 und generiert eine passende Ausgabe als Text.
Für eine Ausgabe im Webbrowser erweist sich Pydoc ebenfalls als nützlich. Listing 10 zeigt die nötigten Aufrufe, um aus den enthaltenen Docstrings passende HTML-Dateien zu erzeugen (Abbildung 4).
Listing 10
HTML-Dateien erzeugen
$ pydoc3 -b docstring-test
Server ready at http://localhost:35757/
Server commands: [b]rowser, [q]uit
server>
[...]
Für Dokumentation mit komplexerer Struktur gilt Sphinx als passendes Mittel der Wahl [30]. Das erfordert jedoch mehr Vorarbeit im Programmcode, die den Rahmen des Artikels sprengen würde. Ausführliche Informationen dazu finden sich in der Dokumentation zu Sphinx und im Python Basics Tutorial.
Zusammenfassung
Fehler und Unstimmigkeiten in einer Dokumentation kommen im Alltag häufig vor. Mit den hier vorgestellten Werkzeugen überprüfen und bereinigen Sie Ihre Dokumentation Schritt für Schritt. Für die regelmäßige Praxis empfiehlt es sich, die Anwendungen projektbezogen in einer Werkzeugkette aneinanderzureihen, um den gesamten Vorgang automatisieren zu können. csi
Danksagung
Der Autor bedankt sich bei Veit Schiele für seine Hilfe und Kritik bei der Vorbereitung des Artikels.
Über den Autor
Frank Hofmann arbeitet bevorzugt von Berlin, Genf und Kapstadt aus als Entwickler, Trainer und Autor. Er gehört zu den Verfassern des Debian-Paketmanagement-Buches [31].
Glossar
-
CI/CD
-
Continuous Integration / Continuous Deployment. Bezeichnet in der Softwareentwicklung die Praxis von kontinuierlicher Integration und kontinuierlicher Bereitstellung.
Infos
-
Guten Python-Code schreiben (Teil 1): Frank Hofmann, “Schnüffelnase”, LU 02/2024, S. 84: https://www.linux-community.de/50379
-
Guten Python-Code schreiben (Teil 2): Frank Hofmann, “Auf Diät setzen”, LU 03/2024, S. 78: https://www.linux-community.de/50220
-
“Documenting Python Code and Projects”: https://testdriven.io/blog/documenting-python/
-
Python Basics Tutorial, Dokumentieren: https://python-basics-tutorial.readthedocs.io/de/latest/document/index.html
-
PyDocstyle: http://www.pydocstyle.org/en/stable/
-
PyLint: https://pylint.org
-
PyEnchant: https://pypi.org/project/pyenchant/
-
Interrogate: https://pypi.org/project/interrogate/
-
Docstr-coverage: https://pypi.org/project/docstr-coverage/
-
Xdoctest: https://github.com/Erotemic/xdoctest
-
Pyment: https://pypi.org/project/pyment/
-
Docstrings im Python Tutorial: https://www.datacamp.com/tutorial/docstrings-python
-
PEP 257: https://peps.python.org/pep-0257/
-
Python Sphinx: https://www.sphinx-doc.org
-
NumPy: https://numpy.org
-
SciPy: https://scipy.org
-
Epydoc: https://epydoc.sourceforge.net
-
Google Python Style Guide: https://google.github.io/styleguide/pyguide.html
-
ReStructuredText: https://docutils.sourceforge.io/rst.html
-
“Documenting Python code”: https://cerfacs.fr/coop/python-docs
-
Javadoc: https://www.oracle.com/java/technologies/javase/javadoc.html
-
Enchant: https://abiword.github.io/enchant/
-
Flake8: https://github.com/pycqa/flake8
-
Flake8-spellcheck: https://github.com/MichaelAquilina/flake8-spellcheck
-
Sphinx vs. Asciidoc(tor): Frank Hofmann, Veit Schiele, “Gut angeleitet”, LU 04/2021, S. 86, https://www.linux-community.de/45730
-
“Automatic documentation generation from code using Sphinx”: https://www.sphinx-doc.org/en/master/tutorial/automatic-doc-generation.html
-
Debian-Paketmanagement-Buch: https://dpmb.org







