PEP 258 – Docutils Design Specification
- Autor:
- David Goodger <goodger at python.org>
- Discussions-To:
- Doc-SIG list
- Status:
- Abgelehnt
- Typ:
- Standards Track
- Benötigt:
- 256, 257
- Erstellt:
- 31.-Mai-2001
- Post-History:
- 13-Jun-2001
Ablehnungsbescheid
Obwohl dies als interessantes Design-Dokument für das nun unabhängige Docutils dienen mag, ist es nicht mehr für die Aufnahme in die Standardbibliothek vorgesehen.
Zusammenfassung
Dieses PEP dokumentiert Designfragen und Implementierungsdetails für Docutils, ein Python Docstring Processing System (DPS). Die Begründung und die High-Level-Konzepte eines DPS sind in PEP 256, „Docstring Processing System Framework“ dokumentiert. Siehe auch PEP 256 für eine „Road Map zu den Docstring-PEPs“.
Docutils wird modular entworfen, so dass jede seiner Komponenten leicht ersetzt werden kann. Darüber hinaus ist Docutils nicht auf die Verarbeitung von Python-Docstrings beschränkt; es verarbeitet auch eigenständige Dokumente in verschiedenen Kontexten.
Keine Änderungen an der Kern-Python-Sprache sind durch dieses PEP erforderlich. Seine Ergebnisse bestehen aus einem Paket für die Standardbibliothek und dessen Dokumentation.
Spezifikation
Docutils Projektmodell
Projektkomponenten und Datenfluss
+---------------------------+
| Docutils: |
| docutils.core.Publisher, |
| docutils.core.publish_*() |
+---------------------------+
/ | \
/ | \
1,3,5 / 6 | \ 7
+--------+ +-------------+ +--------+
| READER | ----> | TRANSFORMER | ====> | WRITER |
+--------+ +-------------+ +--------+
/ \\ |
/ \\ |
2 / 4 \\ 8 |
+-------+ +--------+ +--------+
| INPUT | | PARSER | | OUTPUT |
+-------+ +--------+ +--------+
Die Zahlen über jeder Komponente geben den Pfad an, den die Daten eines Dokuments nehmen. Doppelbreite Linien zwischen Reader & Parser und zwischen Transformer & Writer zeigen an, dass die auf diesen Pfaden gesendeten Daten standardmäßige (reine & unveränderte) Docutils Doc-Trees sein sollten. Einfachbreite Linien bedeuten, dass interne Baum-Erweiterungen oder völlig unabhängige Darstellungen möglich sind, aber sie müssen an beiden Enden unterstützt werden.
Publisher
Das Modul docutils.core enthält eine „Publisher“-Fassade-Klasse und mehrere praktische Funktionen: „publish_cmdline()“ (für Kommandozeilen-Frontends), „publish_file()“ (für programmatische Nutzung mit dateiähnlicher I/O) und „publish_string()“ (für programmatische Nutzung mit String-I/O). Die Publisher-Klasse kapselt die High-Level-Logik eines Docutils-Systems. Die Publisher-Klasse ist verantwortlich für die Verarbeitung, gesteuert durch die Methode Publisher.publish().
- Einrichten interner Einstellungen (kann Konfigurationsdateien & Kommandozeilenoptionen umfassen) und I/O-Objekte.
- Aufrufen des Reader-Objekts, um Daten vom Quell-Input-Objekt zu lesen und die Daten mit dem Parser-Objekt zu parsen. Ein Dokumentenobjekt wird zurückgegeben.
- Einrichten und Anwenden von Transformationen über das dem Dokument zugeordnete Transformer-Objekt.
- Aufrufen des Writer-Objekts, das das Dokument in das endgültige Ausgabeformat übersetzt und die formatierten Daten in das Ziel-Output-Objekt schreibt. Abhängig vom Output-Objekt kann die Ausgabe vom Writer zurückgegeben werden, und dann von der Methode
publish().
Das Aufrufen der „publish“-Funktion (oder das Instanziieren eines „Publisher“-Objekts) mit Komponentennamen führt zu Standardverhalten. Für benutzerdefiniertes Verhalten (Anpassen von Komponenten-Einstellungen) erstellen Sie zuerst benutzerdefinierte Komponentenobjekte und übergeben *diese* dem Publisher oder den publish_*-Hilfsfunktionen.
Leser (Readers)
Reader verstehen den Eingabekontext (woher die Daten stammen), senden die gesamten Eingaben oder einzelne „Chunks“ an den Parser und stellen den Kontext bereit, um die Chunks wieder zu einem kohärenten Ganzen zusammenzufügen.
Jeder Reader ist ein Modul oder Paket, das eine „Reader“-Klasse mit einer „read“-Methode exportiert. Die Basis-„Reader“-Klasse befindet sich im Modul docutils/readers/__init__.py.
Die meisten Reader müssen wissen, welcher Parser verwendet werden soll. Bisher (siehe unten die Liste der Beispiele) kann nur der Python Source Reader („PySource“; noch unvollständig) den Parser selbst bestimmen.
Verantwortlichkeiten
- Eingabetext aus der Quell-I/O abrufen.
- Übergabe des Eingabetextes an den Parser zusammen mit der Wurzel eines neuen Dokumentenbaums.
Beispiele
- Standalone (Roh/Einfach): Eine Textdatei lesen und verarbeiten. Der Reader muss wissen, welcher Parser verwendet werden soll.
Der „Standalone Reader“ wurde im Modul
docutils.readers.standaloneimplementiert. - Python-Quelle: Siehe Python Source Reader unten. Dieser Reader befindet sich derzeit in der Entwicklung im Docutils-Sandbox.
- E-Mail: RFC 822-Header, zitierte Auszüge, Signaturen, MIME-Teile.
- PEP: RFC 822-Header, Konvertierung von „PEP xxxx“ und „RFC xxxx“ in URIs. Der „PEP Reader“ wurde im Modul
docutils.readers.pepimplementiert; siehe PEP 287 und PEP 12. - Wiki: Globale Referenzsuche von „Wiki-Links“ in Transformationen integriert. (Nur CamelCase oder uneingeschränkt?) Lazy-Einrückung?
- Webseite: Wie Standalone, aber Meta-Felder als Meta-Tags erkennen. Unterstützung für Vorlagen irgendeiner Art? (Nach
<body>, vor</body>?) - FAQ: Strukturierte „Frage & Antwort(en)“-Konstrukte.
- Verbunddokument: Kapitel zu einem Buch zusammenführen. Master-Manifestdatei?
Parser
Parser analysieren ihre Eingaben und erzeugen einen Docutils-Dokumentenbaum (Document Tree). Sie wissen nichts und kümmern sich nicht um die Quelle oder das Ziel der Daten.
Jeder Eingabe-Parser ist ein Modul oder Paket, das eine „Parser“-Klasse mit einer „parse“-Methode exportiert. Die Basis-„Parser“-Klasse befindet sich im Modul docutils/parsers/__init__.py.
Aufgaben: Rohen Eingabetext und einen Doctree-Wurzelknoten erhalten, den Doctree durch Parsen des Eingabetextes füllen.
Beispiel: Der bisher einzige implementierte Parser ist für die reStructuredText-Markup-Sprache. Er ist im Paket docutils/parsers/rst/ implementiert.
Die Entwicklung und Integration anderer Parser ist möglich und erwünscht.
Transformer
Die Klasse `Transformer` in docutils/transforms/__init__.py speichert Transformationen und wendet sie auf Dokumente an. Ein Transformer-Objekt wird jedem neuen Dokumentenbaum zugeordnet. Der Publisher ruft Transformer.apply_transforms() auf, um alle gespeicherten Transformationen auf den Dokumentenbaum anzuwenden. Transformationen ändern den Dokumentenbaum von einer Form in eine andere, fügen dem Baum Elemente hinzu oder beschneiden ihn. Transformationen lösen Referenzen und Fußnotennummern auf, verarbeiten interpretierte Texte und führen andere kontextabhängige Verarbeitungen durch.
Einige Transformationen sind spezifisch für Komponenten (Reader, Parser, Writer, Input, Output). Standard-komponentenspezifische Transformationen sind im Attribut default_transforms von Komponentenklassen angegeben. Nachdem der Reader die Verarbeitung abgeschlossen hat, ruft der Publisher Transformer.populate_from_components() mit einer Liste von Komponenten auf, und alle Standardtransformationen werden gespeichert.
Jede Transformation ist eine Klasse in einem Modul im Paket docutils/transforms/, eine Unterklasse von docutils.transforms.Transform. Transformationsklassen haben jeweils ein Attribut default_priority, das vom Transformer verwendet wird, um Transformationen in Reihenfolge (niedrig bis hoch) anzuwenden. Die Standardpriorität kann beim Hinzufügen von Transformationen zum Transformer-Objekt überschrieben werden.
Aufgaben des Transformers
- Transformationen in der angegebenen Reihenfolge auf den Dokumentenbaum anwenden.
- Eine Zuordnung von Komponententypnamen („reader“, „writer“ usw.) zu Komponentenobjekten speichern. Diese werden von bestimmten Transformationen (wie „components.Filter“) verwendet, um die Eignung zu bestimmen.
Aufgaben der Transformation
- Ein Doctree im In-Place modifizieren, entweder rein eine Struktur in eine andere transformieren oder neue Strukturen basierend auf dem Doctree und/oder externen Daten hinzufügen.
Beispiele für Transformationen (im Paket docutils/transforms/)
- frontmatter.DocInfo: Konvertierung von Dokumentenmetadaten (bibliografische Informationen).
- references.AnonymousHyperlinks: Auflösung anonymer Referenzen zu entsprechenden Zielen.
- parts.Contents: Generiert ein Inhaltsverzeichnis für ein Dokument.
- document.Merger: Zusammenführen mehrerer gefüllter Doctrees zu einem. (Noch nicht implementiert oder vollständig verstanden.)
- document.Splitter: Teilt ein Dokument in eine Baumstruktur von Unterdokumenten, vielleicht nach Abschnitten. Es muss Referenzen entsprechend transformieren. (Weder implementiert noch annähernd verstanden.)
- components.Filter: Schließt Elemente ein oder aus, die von einer bestimmten Docutils-Komponente abhängen.
Writer
Writer erzeugen die endgültige Ausgabe (HTML, XML, TeX usw.). Writer übersetzen die interne Dokumentenbaumstruktur (Document Tree) in das endgültige Datenformat, möglicherweise nachdem sie Writer-spezifische Transformationen ausgeführt haben.
Wenn das Dokument den Writer erreicht, sollte es in seiner endgültigen Form sein. Die Aufgabe des Writers ist einfach (und nur) die Übersetzung von der Docutils-Doctree-Struktur in das Zielformat. Einige kleine Transformationen können erforderlich sein, aber sie sollten lokal und formatspezifisch sein.
Jeder Writer ist ein Modul oder Paket, das eine „Writer“-Klasse mit einer „write“-Methode exportiert. Die Basis-„Writer“-Klasse befindet sich im Modul docutils/writers/__init__.py.
Verantwortlichkeiten
- Übersetzen von Doctrees in spezifische Ausgabeformate.
- Referenzen in format-native Formen übersetzen.
- Die übersetzte Ausgabe in die Ziel-I/O schreiben.
Beispiele
- XML: Verschiedene Formen, wie z.B.
- Docutils XML (ein Ausdruck des internen Dokumentenbaums, implementiert als
docutils.writers.docutils_xml). - DocBook (wird im Docutils-Sandbox implementiert).
- Docutils XML (ein Ausdruck des internen Dokumentenbaums, implementiert als
- HTML (XHTML implementiert als
docutils.writers.html4css1). - PDF (eine ReportLabs-Schnittstelle wird im Docutils-Sandbox entwickelt).
- TeX (ein LaTeX Writer wird im Sandbox implementiert).
- Docutils-native Pseudo-XML (implementiert als
docutils.writers.pseudoxml, zum Testen verwendet). - Reintext
- reStructuredText?
Input/Output
I/O-Klassen bieten eine einheitliche API für Low-Level-Input und Output. Unterklassen werden für eine Vielzahl von Ein- und Ausgabemechanismen existieren. Sie können jedoch als Implementierungsdetail betrachtet werden. Die meisten Anwendungen sollten mit einer der Hilfsfunktionen, die mit dem Publisher verbunden sind, zufrieden sein.
I/O-Klassen befinden sich derzeit in der Vorbereitungsphase; es gibt noch viel zu tun. Fragen
- Wie sollen Mehrdatei-Inputs (Dateien & Verzeichnisse) in der API dargestellt werden?
- Wie soll Mehrdatei-Output dargestellt werden? Vielleicht „Writer“-Varianten, eine für jeden Ausgabe-Distributions-Typ? Oder Output-Objekte mit zugehörigen Transformationen?
Verantwortlichkeiten
- Daten aus der Input-Quelle (Input-Objekte) lesen oder Daten zum Output-Ziel schreiben (Output-Objekte).
Beispiele für Input-Quellen
- Eine einzelne Datei auf der Festplatte oder ein Stream (implementiert als
docutils.io.FileInput). - Mehrere Dateien auf der Festplatte (
MultiFileInput?). - Python-Quellcodedateien: Module und Pakete.
- Python-Strings, wie sie von einer Client-Anwendung empfangen werden (implementiert als
docutils.io.StringInput).
Beispiele für Output-Ziele
- Eine einzelne Datei auf der Festplatte oder ein Stream (implementiert als
docutils.io.FileOutput). - Ein Baum von Verzeichnissen und Dateien auf der Festplatte.
- Ein Python-String, zurückgegeben an eine Client-Anwendung (implementiert als
docutils.io.StringOutput). - Keine Ausgabe; nützlich für programmatische Anwendungen, bei denen nur ein Teil der normalen Ausgabe verwendet werden soll (implementiert als
docutils.io.NullOutput). - Eine einzelne Baum-förmige Datenstruktur im Speicher.
- Einige andere Datenstrukturen im Speicher.
Docutils Paketstruktur
- Paket „docutils“.
- Das Modul „__init__.py“ enthält: Klasse „Component“, eine Basisklasse für Docutils-Komponenten; Klasse „SettingsSpec“, eine Basisklasse zur Spezifizierung von Laufzeiteinstellungen (verwendet von docutils.frontend); und Klasse „TransformSpec“, eine Basisklasse zur Spezifizierung von Transformationen.
- Das Modul „docutils.core“ enthält die Fassadenklasse „Publisher“ und Hilfsfunktionen. Siehe Publisher oben.
- Das Modul „docutils.frontend“ stellt Unterstützung für Laufzeiteinstellungen bereit, für die programmatische Nutzung und für Front-End-Tools (einschließlich Unterstützung für Konfigurationsdateien und Verarbeitung von Kommandozeilenargumenten und -optionen).
- Das Modul „docutils.io“ stellt eine einheitliche API für Low-Level-Input und Output bereit. Siehe Input/Output oben.
- Das Modul „docutils.nodes“ enthält die Klassenbibliothek für Docutils-Dokumentenbaum-Elemente sowie Basisklassen für das Visitor-Muster zur Traversierung von Bäumen. Siehe Document Tree unten.
- Das Modul „docutils.statemachine“ enthält eine Zustandsmaschine, die für textbasierte Filter und Parser auf Regex-Basis spezialisiert ist. Die reStructuredText-Parserimplementierung basiert auf diesem Modul.
- Das Modul „docutils.urischemes“ enthält eine Zuordnung bekannter URI-Schemata („http“, „ftp“, „mail“ usw.).
- Das Modul „docutils.utils“ enthält Hilfsfunktionen und -klassen, einschließlich einer Logger-Klasse („Reporter“; siehe Error Handling unten).
- Paket „docutils.parsers“: Markup-Parser.
- Die Funktion „get_parser_class(parser_name)“ gibt ein Parser-Modul nach Namen zurück. Die Klasse „Parser“ ist die Basisklasse spezifischer Parser. (
docutils/parsers/__init__.py) - Paket „docutils.parsers.rst“: der reStructuredText-Parser.
- Alternative Markup-Parser können hinzugefügt werden.
Siehe Parsers oben.
- Die Funktion „get_parser_class(parser_name)“ gibt ein Parser-Modul nach Namen zurück. Die Klasse „Parser“ ist die Basisklasse spezifischer Parser. (
- Paket „docutils.readers“: kontextbezogene Input-Reader.
- Die Funktion „get_reader_class(reader_name)“ gibt ein Reader-Modul nach Namen oder Alias zurück. Die Klasse „Reader“ ist die Basisklasse spezifischer Reader. (
docutils/readers/__init__.py) - Das Modul „docutils.readers.standalone“ liest eigenständige Dokumentdateien.
- Das Modul „docutils.readers.pep“ liest PEPs (Python Enhancement Proposals).
- Reader, die hinzugefügt werden sollen: Python-Quellcode (Struktur & Docstrings), E-Mail, FAQ und vielleicht Wiki und andere.
Siehe Readers oben.
- Die Funktion „get_reader_class(reader_name)“ gibt ein Reader-Modul nach Namen oder Alias zurück. Die Klasse „Reader“ ist die Basisklasse spezifischer Reader. (
- Paket „docutils.writers“: Output-Format-Writer.
- Die Funktion „get_writer_class(writer_name)“ gibt ein Writer-Modul nach Namen zurück. Die Klasse „Writer“ ist die Basisklasse spezifischer Writer. (
docutils/writers/__init__.py) - Das Modul „docutils.writers.html4css1“ ist ein einfacher HyperText Markup Language Dokumentenbaum-Writer für HTML 4.01 und CSS1.
- Das Modul „docutils.writers.docutils_xml“ schreibt den internen Dokumentenbaum im XML-Format.
- Das Modul „docutils.writers.pseudoxml“ ist ein einfacher interner Dokumentenbaum-Writer; es schreibt eingerücktes Pseudo-XML.
- Zu ergänzende Writer: HTML 3.2 oder 4.01-loose, XML (verschiedene Formen, wie DocBook), PDF, TeX, Plaintext, reStructuredText und vielleicht andere.
Siehe Writers oben.
- Die Funktion „get_writer_class(writer_name)“ gibt ein Writer-Modul nach Namen zurück. Die Klasse „Writer“ ist die Basisklasse spezifischer Writer. (
- Paket „docutils.transforms“: Baumtransformationsklassen.
- Die Klasse „Transformer“ speichert Transformationen und wendet sie auf Dokumentenbäume an. (
docutils/transforms/__init__.py) - Die Klasse „Transform“ ist die Basisklasse spezifischer Transformationen. (
docutils/transforms/__init__.py) - Jedes Modul enthält verwandte Transformationsklassen.
Siehe Transforms oben.
- Die Klasse „Transformer“ speichert Transformationen und wendet sie auf Dokumentenbäume an. (
- Paket „docutils.languages“: Sprachmodule enthalten sprachabhängige Zeichenketten und Zuordnungen. Sie sind nach ihrem Sprach-Identifier benannt (wie in Choice of Docstring Format unten definiert), wobei Bindestriche durch Unterstriche ersetzt werden.
- Die Funktion „get_language(language_code)“ gibt das passende Sprachmodul zurück. (
docutils/languages/__init__.py) - Module: en.py (Englisch), de.py (Deutsch), fr.py (Französisch), it.py (Italienisch), sk.py (Slowakisch), sv.py (Schwedisch).
- Andere Sprachen sollen hinzugefügt werden.
- Die Funktion „get_language(language_code)“ gibt das passende Sprachmodul zurück. (
- Drittanbieter-Module: Verzeichnis „extras“. Diese Module werden nur installiert, wenn sie nicht bereits in der Python-Installation vorhanden sind.
extras/optparse.pyundextras/textwrap.pybieten Optionsanalyse und Hilfe für die Kommandozeile; von Greg Wards http://optik.sf.net/-Projekt, zur Bequemlichkeit enthalten.extras/roman.pyenthält Routinen zur Konvertierung von römischen Zahlen.
Front-End-Tools
Das Verzeichnis tools/ enthält mehrere Frontends für die gängige Docutils-Verarbeitung. Siehe Docutils Front-End Tools für Details.
Dokumentenbaum
Eine einzelne Zwischen-Datenstruktur wird intern von Docutils verwendet, in den Schnittstellen zwischen Komponenten; sie ist im Modul docutils.nodes definiert. Es ist nicht erforderlich, dass diese Datenstruktur *intern* von einer der Komponenten verwendet wird, nur *zwischen* Komponenten, wie im Diagramm im Docutils Project Model oben dargestellt.
Benutzerdefinierte Knotentypen sind erlaubt, vorausgesetzt, entweder (a) eine Transformation konvertiert sie in Standard-Docutils-Knoten, bevor sie den eigentlichen Writer erreichen, oder (b) der benutzerdefinierte Knoten wird explizit von bestimmten Writern unterstützt und in einen gefilterten „pending“-Knoten eingebettet. Ein Beispiel für Bedingung (a) ist der Python Source Reader (siehe unten), bei dem eine „Stylist“-Transformation benutzerdefinierte Knoten konvertiert. Der HTML-Tag <meta> ist ein Beispiel für Bedingung (b); er wird vom HTML Writer, aber nicht von anderen unterstützt. Die reStructuredText-Direktive „meta“ erzeugt einen „pending“-Knoten, der das Wissen enthält, dass der eingebettete „meta“-Knoten nur von HTML-kompatiblen Writern verarbeitet werden kann. Der „pending“-Knoten wird durch die Transformation docutils.transforms.components.Filter aufgelöst, die prüft, ob der aufrufende Writer HTML unterstützt; wenn nicht, wird der „pending“-Knoten (und der eingeschlossene „meta“-Knoten) aus dem Dokument entfernt.
Die Dokumentenbaum-Datenstruktur ist ähnlich einem DOM-Baum, aber mit spezifischen Knotennamen (Klassen) anstelle der generischen DOM-Knoten. Das Schema ist in einer XML-DTD (eXtensible Markup Language Document Type Definition) dokumentiert, die aus zwei Teilen besteht:
- die Docutils Generic DTD, docutils.dtd, und
- das OASIS Exchange Table Model, soextbl.dtd.
Die DTD definiert eine reiche Menge von Elementen, die für viele Ein- und Ausgabeformate geeignet sind. Die DTD behält alle Informationen, die zur Rekonstruktion des ursprünglichen Eingabetextes oder einer angemessenen Facsimile davon erforderlich sind.
Siehe The Docutils Document Tree für Details (unvollständig).
Fehlerbehandlung
Wenn der Parser einen Fehler in der Markup-Sprache feststellt, fügt er eine Systemmeldung (DTD-Element „system_message“) ein. Es gibt fünf Stufen von Systemmeldungen:
- Stufe 0, „DEBUG“: ein internes Berichtsproblem. Es hat keine Auswirkung auf die Verarbeitung. Stufe-0-Systemmeldungen werden getrennt von den anderen behandelt.
- Stufe 1, „INFO“: ein geringfügiges Problem, das ignoriert werden kann. Es hat geringe oder keine Auswirkungen auf die Verarbeitung. Typischerweise werden Stufe-1-Systemmeldungen nicht gemeldet.
- Stufe 2, „WARNING“: ein Problem, das behoben werden sollte. Wenn es ignoriert wird, kann es zu geringfügigen Problemen mit der Ausgabe kommen. Typischerweise werden Stufe-2-Systemmeldungen gemeldet, aber die Verarbeitung nicht gestoppt.
- Stufe 3, „ERROR“: ein Hauptproblem, das behoben werden sollte. Wenn es ignoriert wird, wird die Ausgabe unvorhersehbare Fehler enthalten. Typischerweise werden Stufe-3-Systemmeldungen gemeldet, aber die Verarbeitung nicht gestoppt.
- Stufe 4, „SEVERE“: ein kritischer Fehler, der behoben werden muss. Typischerweise werden Stufe-4-Systemmeldungen in Ausnahmen umgewandelt, die die Verarbeitung stoppen. Wenn sie ignoriert werden, wird die Ausgabe schwerwiegende Fehler enthalten.
Obwohl die anfänglichen Meldungsstufen unabhängig voneinander entwickelt wurden, haben sie eine starke Entsprechung zu den Schweregradstufen von VMS-Fehlerbedingungen; die in Anführungszeichen gesetzten Namen für die Stufen 1 bis 4 wurden von VMS übernommen. Die Fehlerbehandlung wurde seitdem vom log4j-Projekt beeinflusst.
Python Quellcode-Leser
Der Python Source Reader („PySource“) ist die Docutils-Komponente, die Python-Quellcodedateien liest, Docstrings im Kontext extrahiert, dann parst, verknüpft und die Docstrings zu einem kohärenten Ganzen zusammenfügt. Es ist eine wichtige und nicht triviale Komponente, die derzeit im Docutils-Sandbox experimentell entwickelt wird. High-Level-Designfragen werden hier vorgestellt.
Verarbeitungsmodell
Dieses Modell wird sich im Laufe der Zeit weiterentwickeln und Erfahrungen und Erkenntnisse integrieren.
- Der PySource Reader verwendet eine Input-Klasse, um Python-Pakete und Module zu lesen und in einen Baum von Strings zu konvertieren.
- Die Python-Module werden geparst, wodurch der Baum von Strings in einen Baum von abstrakten Syntaxbäumen mit Docstring-Knoten umgewandelt wird.
- Die abstrakten Syntaxbäume werden in eine interne Darstellung der Pakete/Module konvertiert. Docstrings werden extrahiert, ebenso wie Code-Strukturdetails. Siehe AST Mining unten. Namensräume werden für die Suche in Schritt 6 konstruiert.
- Einzeln werden die Docstrings geparst, was zu Standard-Docutils-Doctrees führt.
- PySource fügt alle einzelnen Docstring-Doctrees zu einem Python-spezifischen benutzerdefinierten Docutils-Baum zusammen, der die Paket-/Modul-/Klassenstruktur widerspiegelt; dies ist eine benutzerdefinierte Reader-spezifische interne Darstellung (siehe die Docutils Python Source DTD). Namensräume müssen zusammengeführt werden: Python-Identifier, Hyperlink-Ziele.
- Querverweise von Docstrings (interpretierter Text) zu Python-Identifikatoren werden gemäß den Python-Namensraum-Lookup-Regeln aufgelöst. Siehe Identifier Cross-References unten.
- Eine „Stylist“-Transformation wird auf den benutzerdefinierten Doctree angewendet (vom Transformer), benutzerdefinierte Knoten werden mithilfe von Standardknoten als Primitive gerendert, und ein Standard-Dokumentenbaum wird ausgegeben. Siehe Stylist Transforms unten.
- Andere Transformationen werden vom Transformer auf den Standard-Doctree angewendet.
- Der Standard-Doctree wird an einen Writer gesendet, der das Dokument in ein konkretes Format (HTML, PDF usw.) übersetzt.
- Der Writer verwendet eine Output-Klasse, um die resultierenden Daten an sein Ziel zu schreiben (Festplattendatei, Verzeichnisse und Dateien usw.).
AST-Mining
Abstract Syntax Tree Mining-Code wird geschrieben (oder angepasst), der ein geparstes Python-Modul scannt und einen geordneten Baum zurückgibt, der die Namen, Docstrings (einschließlich Attribut- und zusätzlicher Docstrings; siehe unten) und zusätzliche Informationen (in Klammern unten) aller folgenden Objekte enthält:
- Pakete
- Module
- Modulattribute (+ Anfangswerte)
- Klassen (+ Vererbung)
- Klassenattribute (+ Anfangswerte)
- Instanzattribute (+ Anfangswerte)
- Methoden (+ Parameter & Standardwerte)
- Funktionen (+ Parameter & Standardwerte)
(Auch Kommentare extrahieren? Zum Beispiel wären Kommentare am Anfang eines Moduls ein guter Ort für bibliografische Feldlisten.)
Um interpretierte Text-Querverweise auszuwerten, werden auch Namensräume für jeden der oben genannten Punkte benötigt.
Siehe den Thread „AST mining“ in python-dev/docstring-develop, begonnen am 14.08.2001.
Regeln zur Docstring-Extraktion
- Was zu untersuchen ist
- Wenn die Variable „
__all__“ im zu dokumentierenden Modul vorhanden ist, werden nur die in „__all__“ aufgeführten Bezeichner auf Docstrings untersucht. - In Abwesenheit von „
__all__“ werden alle Bezeichner untersucht, außer denen, deren Namen privat sind (Namen beginnen mit „_“, aber beginnen und enden nicht mit „__“). - 1a und 1b können durch Laufzeiteinstellungen überschrieben werden.
- Wenn die Variable „
- Wo
Docstrings sind String-Literal-Ausdrücke und werden an folgenden Stellen innerhalb von Python-Modulen erkannt:
- Am Anfang einer Modul-, Funktions-, Klassendefinition oder Methodendefinition, nach etwaigen Kommentaren. Dies ist der Standard für Python
__doc__-Attribute. - Unmittelbar nach einer einfachen Zuweisung auf der obersten Ebene eines Moduls, einer Klassendefinition oder einer
__init__-Methodendefinition, nach etwaigen Kommentaren. Siehe Attribute Docstrings unten. - Zusätzliche String-Literale, die unmittelbar nach den Docstrings in (a) und (b) gefunden werden, werden erkannt, extrahiert und verkettet. Siehe Additional Docstrings unten.
- @@@ 2.2-Style „Properties“ mit Attribut-Docstrings? Auf Syntax warten?
- Am Anfang einer Modul-, Funktions-, Klassendefinition oder Methodendefinition, nach etwaigen Kommentaren. Dies ist der Standard für Python
- Wie
Wo immer möglich, sollten Python-Module von Docutils geparst und nicht importiert werden. Dafür gibt es mehrere Gründe:
- Das Importieren von nicht vertrauenswürdigem Code ist von Natur aus unsicher.
- Informationen aus dem Quellcode gehen verloren, wenn Introspektion verwendet wird, um ein importiertes Modul zu untersuchen, wie z. B. Kommentare und die Reihenfolge der Definitionen.
- Docstrings sollen an Stellen erkannt werden, wo der Bytecode-Compiler String-Literal-Ausdrücke ignoriert (2b und 2c oben), was bedeutet, dass der Import des Moduls diese Docstrings verlieren würde.
Selbstverständlich sollten Standard-Python-Parsing-Tools wie das Modul „parser“ verwendet werden.
Wenn der Python-Quellcode eines Moduls nicht verfügbar ist (d. h. nur die
.pyc-Datei existiert) oder für C-Erweiterungsmodule, kann das Modul nur importiert werden, um auf Docstrings zuzugreifen, und alle Einschränkungen müssen hingenommen werden.
Da Attribut-Docstrings und zusätzliche Docstrings vom Python-Bytecode-Compiler ignoriert werden, entstehen durch ihre Verwendung keine Namensraumverschmutzung oder Laufzeitüberladung. Sie werden nicht zu __doc__ oder einem anderen Attribut zugewiesen. Das anfängliche Parsen eines Moduls kann einen leichten Performance-Einbruch verursachen.
Attribut-Docstrings
(Dies ist eine vereinfachte Version von PEP 224.)
Ein String-Literal, das unmittelbar auf eine Zuweisungsanweisung folgt, wird von der Docstring-Extraktionsmaschinerie als Docstring des Ziels der Zuweisungsanweisung interpretiert, unter den folgenden Bedingungen:
- Die Zuweisung muss in einem der folgenden Kontexte erfolgen:
- Auf der obersten Ebene eines Moduls (d. h. nicht verschachtelt in einer zusammengesetzten Anweisung wie einer Schleife oder Bedingung): ein Modulattribut.
- Auf der obersten Ebene einer Klassendefinition: ein Klassenattribut.
- Auf der obersten Ebene der Methode „
__init__“ einer Klasse: ein Instanzattribut. Instanzattribute, die in anderen Methoden zugewiesen werden, werden als Implementierungsdetails angesehen. (@@@__new__-Methoden?) - Eine Funktionsattributzuweisung auf der obersten Ebene eines Moduls oder einer Klassendefinition.
Da jeder der obigen Kontexte auf der obersten Ebene liegt (d. h. im äußersten Block einer Definition), kann es notwendig sein, Dummy-Zuweisungen für Attribute zu platzieren, die bedingt oder in einer Schleife zugewiesen werden.
- Die Zuweisung muss an ein einzelnes Ziel erfolgen, nicht an eine Liste oder ein Tupel von Zielen.
- Die Form des Ziels
- Für die Kontexte 1a und 1b oben muss das Ziel ein einfacher Bezeichner sein (kein Punktbezeichner, keine indizierte Expression, keine geslicte Expression).
- Für Kontext 1c oben muss das Ziel die Form „
self.attrib“ haben, wobei „self“ dem ersten Parameter der Methode „__init__“ (dem Instanzparameter) entspricht und „attrib“ ein einfacher Bezeichner wie in 3a ist. - Für Kontext 1d oben muss das Ziel die Form „
name.attrib“ haben, wobei „name“ einem bereits definierten Funktions- oder Methodennamen entspricht und „attrib“ ein einfacher Bezeichner wie in 3a ist.
Leerzeilen können nach Attribut-Docstrings verwendet werden, um die Verbindung zwischen der Zuweisung und dem Docstring zu betonen.
Beispiele
g = 'module attribute (module-global variable)'
"""This is g's docstring."""
class AClass:
c = 'class attribute'
"""This is AClass.c's docstring."""
def __init__(self):
"""Method __init__'s docstring."""
self.i = 'instance attribute'
"""This is self.i's docstring."""
def f(x):
"""Function f's docstring."""
return x**2
f.a = 1
"""Function attribute f.a's docstring."""
Zusätzliche Docstrings
(Diese Idee wurde aus PEP 216 übernommen.)
Viele Programmierer möchten Docstrings ausgiebig für die API-Dokumentation verwenden. Docstrings verbrauchen jedoch Speicher im laufenden Programm, daher zögern einige Programmierer, ihren Code „aufzublähen“. Außerdem ist nicht jede API-Dokumentation für interaktive Umgebungen geeignet, in denen __doc__ angezeigt würde.
Die Docstring-Extraktionswerkzeuge von Docutils werden alle String-Literal-Ausdrücke, die am Anfang einer Definition oder nach einer einfachen Zuweisung erscheinen, verketten. Nur die ersten Strings in Definitionen sind als __doc__ verfügbar und können für kurze Nutzungstexte verwendet werden, die für interaktive Sitzungen geeignet sind; nachfolgende String-Literale und alle Attribut-Docstrings werden vom Python-Bytecode-Compiler ignoriert und können umfangreichere API-Informationen enthalten.
Beispiel
def function(arg):
"""This is __doc__, function's docstring."""
"""
This is an additional docstring, ignored by the byte-code
compiler, but extracted by Docutils.
"""
pass
Wahl des Docstring-Formats
Anstatt alle zur Verwendung eines einzigen Docstring-Formats zu zwingen, erlaubt das Verarbeitungssystem mehrere Eingabeformate. Eine spezielle Variable, __docformat__, kann auf der obersten Ebene eines Moduls erscheinen, bevor Funktionen oder Klassendefinitionen erfolgen. Im Laufe der Zeit oder durch Dekret sollte sich ein Standardformat oder eine Reihe von Formaten herausbilden.
Die __docformat__-Variable eines Moduls gilt nur für die Objekte, die in der Datei des Moduls definiert sind. Insbesondere gilt die __docformat__-Variable in der __init__.py-Datei eines Pakets nicht für Objekte, die in Unterpaketen und Untermodulen definiert sind.
Die __docformat__-Variable ist eine Zeichenkette, die den Namen des verwendeten Formats enthält, eine case-insensitive Zeichenkette, die mit dem Modul- oder Paketnamen des Eingabeparsers übereinstimmt (d. h. dem gleichen Namen, der zum „Importieren“ des Moduls oder Pakets erforderlich ist), oder ein registriertes Alias. Wenn keine __docformat__ angegeben ist, ist das Standardformat vorerst „plaintext“; dies kann auf das Standardformat geändert werden, falls jemals eines festgelegt wird.
Die __docformat__-Zeichenkette kann ein optionales zweites Feld enthalten, das durch ein einzelnes Leerzeichen vom Formatenamen (erstes Feld) getrennt ist: eine case-insensitive Sprachkennung, wie in RFC 1766 definiert. Eine typische Sprachkennung besteht aus einem 2-Buchstaben-Sprachcode aus ISO 639 (3-Buchstaben-Codes werden nur verwendet, wenn kein 2-Buchstaben-Code vorhanden ist; RFC 1766 wird derzeit überarbeitet, um 3-Buchstaben-Codes zuzulassen). Wenn keine Sprachkennung angegeben ist, ist der Standardwert „en“ für Englisch. Die Sprachkennung wird an den Parser übergeben und kann für sprachabhängige Markup-Funktionen verwendet werden.
Identifier-Querverweise
In Python-Docstrings werden interpretierte Texte verwendet, um Programmierbezeichner wie Namen von Variablen, Funktionen, Klassen und Modulen zu klassifizieren und zu markieren. Wenn nur der Bezeichner angegeben wird, wird seine Rolle implizit nach den Regeln der Python-Namensraumsuche abgeleitet. Für Funktionen und Methoden (auch wenn sie dynamisch zugewiesen werden) können Klammern („()“) enthalten sein.
This function uses `another()` to do its work.
Für Klassen-, Instanz- und Modulattribute werden bei Bedarf Punktbezeichner verwendet. Zum Beispiel (unter Verwendung von reStructuredText-Markup)
class Keeper(Storer):
"""
Extend `Storer`. Class attribute `instances` keeps track
of the number of `Keeper` objects instantiated.
"""
instances = 0
"""How many `Keeper` objects are there?"""
def __init__(self):
"""
Extend `Storer.__init__()` to keep track of instances.
Keep count in `Keeper.instances`, data in `self.data`.
"""
Storer.__init__(self)
Keeper.instances += 1
self.data = []
"""Store data in a list, most recent last."""
def store_data(self, data):
"""
Extend `Storer.store_data()`; append new `data` to a
list (in `self.data`).
"""
self.data = data
Jeder der mit Backticks („`“) zitierten Bezeichner wird zu Verweisen auf die Definitionen der Bezeichner selbst.
Stylist-Transformationen
Stylist-Transformationen sind spezielle Transformationen, die spezifisch für den PySource Reader sind. Der PySource Reader muss keine Stilentscheidungen treffen; er erzeugt lediglich einen logisch aufgebauten Dokumentenbaum, der geparst und verlinkt ist, einschließlich benutzerdefinierter Knotentypen. Stylist-Transformationen verstehen die vom Reader erstellten benutzerdefinierten Knoten und konvertieren sie in Standard-Docutils-Knoten.
Mehrere Stylist-Transformationen können implementiert werden und eine kann zur Laufzeit ausgewählt werden (über eine Kommandozeilenoption „--style“ oder „--stylist“). Jede Stylist-Transformation implementiert ein anderes Layout oder einen anderen Stil; daher der Name. Sie entkoppeln den kontextverständnisorientierten Teil des Readers vom Layout-generierenden Teil der Verarbeitung, was zu einem flexibleren und robusteren System führt. Dies dient auch dazu, „Stil von Inhalt zu trennen“, das SGML/XML-Ideal.
Indem das Styling-Stück klein und modular gehalten wird, wird es für Leute viel einfacher, ihre eigenen Stile zu entwickeln. Die „Einstiegshürde“ ist bei bestehenden Werkzeugen zu hoch; das Extrahieren des Stylist-Codes wird die Hürde erheblich senken.
Projekt-Webseite
Für diese Arbeit wurde ein SourceForge-Projekt unter http://docutils.sourceforge.net/ eingerichtet.
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Danksagungen
Dieses Dokument lehnt sich an Ideen aus den Archiven der Python Doc-SIG an. Danke an alle Mitglieder, ehemalige und gegenwärtige.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0258.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT