Skip to content

Commit 682ae3b

Browse files
authored
fix(docs): Fix doc strings such that the docs and the json-schemas don't differ (#949)
* Unify doc string style for `bo` and `com` * Unify doc string style with `enum` * Only use pydantics docstring feature instead of custom logic * 🔥
1 parent 6d018e2 commit 682ae3b

File tree

168 files changed

+2684
-1681
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

168 files changed

+2684
-1681
lines changed

src/bo4e/bo/angebot.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,27 +39,31 @@ class Angebot(Geschaeftsobjekt):
3939
"""
4040

4141
typ: Annotated[Literal[Typ.ANGEBOT], Field(alias="_typ")] = Typ.ANGEBOT
42-
#: Eindeutige Nummer des Angebotes
4342
angebotsnummer: Optional[str] = None
44-
#: Erstellungsdatum des Angebots
43+
"""Eindeutige Nummer des Angebotes"""
4544
angebotsdatum: Optional[pydantic.AwareDatetime] = None
46-
#: Sparte, für die das Angebot abgegeben wird (Strom/Gas)
45+
"""Erstellungsdatum des Angebots"""
4746
sparte: Optional["Sparte"] = None
48-
#: Ersteller des Angebots
47+
"""Sparte, für die das Angebot abgegeben wird (Strom/Gas)"""
4948
angebotsgeber: Optional["Geschaeftspartner"] = None
50-
#: Empfänger des Angebots
49+
"""Ersteller des Angebots"""
5150
angebotsnehmer: Optional["Geschaeftspartner"] = None
51+
"""Empfänger des Angebots"""
5252

5353
varianten: Optional[list["Angebotsvariante"]] = None
54-
""" Eine oder mehrere Varianten des Angebots mit den Angebotsteilen;
55-
Ein Angebot besteht mindestens aus einer Variante."""
54+
"""
55+
Eine oder mehrere Varianten des Angebots mit den Angebotsteilen;
56+
Ein Angebot besteht mindestens aus einer Variante.
57+
"""
5658

5759
anfragereferenz: Optional[str] = None
58-
""" Referenz auf eine Anfrage oder Ausschreibung;
59-
Kann dem Empfänger des Angebotes bei Zuordnung des Angebotes zur Anfrage bzw. Ausschreibung helfen."""
60-
#: Bis zu diesem Zeitpunkt (Tag/Uhrzeit) inklusive gilt das Angebot
60+
"""
61+
Referenz auf eine Anfrage oder Ausschreibung;
62+
Kann dem Empfänger des Angebotes bei Zuordnung des Angebotes zur Anfrage bzw. Ausschreibung helfen.
63+
"""
6164
bindefrist: Optional[pydantic.AwareDatetime] = None
62-
#: Person, die als Angebotsnehmer das Angebot angenommen hat
65+
"""Bis zu diesem Zeitpunkt (Tag/Uhrzeit) inklusive gilt das Angebot"""
6366
unterzeichner_angebotsnehmer: Optional["Person"] = None
64-
#: Person, die als Angebotsgeber das Angebots ausgestellt hat
67+
"""Person, die als Angebotsnehmer das Angebot angenommen hat"""
6568
unterzeichner_angebotsgeber: Optional["Person"] = None
69+
"""Person, die als Angebotsgeber das Angebots ausgestellt hat"""

src/bo4e/bo/ausschreibung.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,16 @@ class Ausschreibung(Geschaeftsobjekt):
3737
"""
3838

3939
typ: Annotated[Literal[Typ.AUSSCHREIBUNG], Field(alias="_typ")] = Typ.AUSSCHREIBUNG
40-
#: Vom Herausgeber der Ausschreibung vergebene eindeutige Nummer
4140
ausschreibungsnummer: Optional[str] = None
42-
#: Aufzählung für die Typisierung von Ausschreibungen
41+
"""Vom Herausgeber der Ausschreibung vergebene eindeutige Nummer"""
4342
ausschreibungstyp: Optional["Ausschreibungstyp"] = None
44-
#: Bezeichnungen für die Ausschreibungsphasen
43+
"""Aufzählung für die Typisierung von Ausschreibungen"""
4544
ausschreibungsstatus: Optional["Ausschreibungsstatus"] = None
46-
#: Kennzeichen, ob die Ausschreibung kostenpflichtig ist
45+
"""Bezeichnungen für die Ausschreibungsphasen"""
4746
ist_kostenpflichtig: Optional[bool] = None
48-
#: Gibt den Veröffentlichungszeitpunkt der Ausschreibung an
47+
"""Kennzeichen, ob die Ausschreibung kostenpflichtig ist"""
4948
veroeffentlichungszeitpunkt: Optional[pydantic.AwareDatetime] = None
49+
"""Gibt den Veröffentlichungszeitpunkt der Ausschreibung an"""
5050
ausschreibender: Optional["Geschaeftspartner"] = None
5151
"""
5252
Mit diesem Objekt können Geschäftspartner übertragen werden.
@@ -62,10 +62,10 @@ class Ausschreibung(Geschaeftsobjekt):
6262
Diese Komponente wird zur Abbildung von Zeiträumen in Form von Dauern oder der Angabe von Start und Ende verwendet.
6363
Es muss daher entweder eine Dauer oder ein Zeitraum in Form von Start und Ende angegeben sein
6464
"""
65-
#: Die einzelnen Lose, aus denen sich die Ausschreibung zusammensetzt
6665
lose: Optional[list["Ausschreibungslos"]] = None
66+
"""Die einzelnen Lose, aus denen sich die Ausschreibung zusammensetzt"""
6767

68-
#: Aufzählung der unterstützten Ausschreibungsportale
6968
ausschreibungportal: Optional["Ausschreibungsportal"] = None
70-
#: Internetseite, auf der die Ausschreibung veröffentlicht wurde (falls vorhanden)
69+
"""Aufzählung der unterstützten Ausschreibungsportale"""
7170
webseite: Optional[str] = None
71+
"""Internetseite, auf der die Ausschreibung veröffentlicht wurde (falls vorhanden)"""

src/bo4e/bo/buendelvertrag.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,32 +41,36 @@ class Buendelvertrag(Geschaeftsobjekt):
4141
typ: Annotated[Literal[Typ.BUENDELVERTRAG], Field(alias="_typ")] = Typ.BUENDELVERTRAG
4242

4343
# pylint: disable=duplicate-code
44-
#: Eine im Verwendungskontext eindeutige Nummer für den Vertrag
4544
vertragsnummer: Optional[str] = None
46-
#: Hier ist festgelegt, um welche Art von Vertrag es sich handelt. Z.B. Netznutzungvertrag
45+
"""Eine im Verwendungskontext eindeutige Nummer für den Vertrag"""
4746
vertragsart: Optional["Vertragsart"] = None
48-
#: Gibt den Status des Vertrages an
47+
"""Hier ist festgelegt, um welche Art von Vertrag es sich handelt. Z.B. Netznutzungvertrag"""
4948
vertragsstatus: Optional["Vertragsstatus"] = None
50-
#: Unterscheidungsmöglichkeiten für die Sparte
49+
"""Gibt den Status des Vertrages an"""
5150
sparte: Optional["Sparte"] = None
52-
#: Gibt an, wann der Vertrag beginnt (inklusiv)
51+
"""Unterscheidungsmöglichkeiten für die Sparte"""
5352
vertragsbeginn: Optional[pydantic.AwareDatetime] = None
54-
#: Gibt an, wann der Vertrag (voraussichtlich) endet oder beendet wurde (exklusiv)
53+
"""Gibt an, wann der Vertrag beginnt (inklusiv)"""
5554
vertragsende: Optional[pydantic.AwareDatetime] = None
56-
#: Der "erstgenannte" Vertragspartner. In der Regel der Aussteller des Vertrags.
57-
#: Beispiel: "Vertrag zwischen Vertagspartner 1 ..."
55+
"""Gibt an, wann der Vertrag (voraussichtlich) endet oder beendet wurde (exklusiv)"""
5856
vertragspartner1: Optional["Geschaeftspartner"] = None
59-
#: Der "zweitgenannte" Vertragspartner. In der Regel der Empfänger des Vertrags.
60-
#: Beispiel "Vertrag zwischen Vertagspartner 1 und Vertragspartner 2"
57+
"""
58+
Der "erstgenannte" Vertragspartner. In der Regel der Aussteller des Vertrags.
59+
Beispiel: "Vertrag zwischen Vertagspartner 1 ..."
60+
"""
6161
vertragspartner2: Optional["Geschaeftspartner"] = None
62+
"""
63+
Der "zweitgenannte" Vertragspartner. In der Regel der Empfänger des Vertrags.
64+
Beispiel "Vertrag zwischen Vertagspartner 1 und Vertragspartner 2"
65+
"""
6266

63-
#: Die Liste mit den Einzelverträgen zu den Abnahmestellen
6467
einzelvertraege: Optional[list["Vertrag"]] = None
65-
#: Festlegungen zu Laufzeiten und Kündigungsfristen
68+
"""Die Liste mit den Einzelverträgen zu den Abnahmestellen"""
6669
vertragskonditionen: Optional[list["Vertragskonditionen"]] = None
67-
#: Unterzeichner des Vertragspartners1
70+
"""Festlegungen zu Laufzeiten und Kündigungsfristen"""
6871
unterzeichnervp1: Optional[list["Unterschrift"]] = None
69-
#: Unterzeichner des Vertragspartners2
72+
"""Unterzeichner des Vertragspartners1"""
7073
unterzeichnervp2: Optional[list["Unterschrift"]] = None
71-
#: Beschreibung zum Vertrag
74+
"""Unterzeichner des Vertragspartners2"""
7275
beschreibung: Optional[str] = None
76+
"""Beschreibung zum Vertrag"""

src/bo4e/bo/energiemenge.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ class Energiemenge(Geschaeftsobjekt):
3535
"""
3636

3737
typ: Annotated[Literal[Typ.ENERGIEMENGE], Field(alias="_typ")] = Typ.ENERGIEMENGE
38-
#: Eindeutige Nummer der Marktlokation bzw. der Messlokation, zu der die Energiemenge gehört
3938
lokations_id: Optional[str] = None
39+
"""Eindeutige Nummer der Marktlokation bzw. der Messlokation, zu der die Energiemenge gehört"""
4040
# todo: add validator such that only mess- or marktlokations IDs are accepted + cross check with lokationstyp
41-
#: Gibt an, ob es sich um eine Markt- oder Messlokation handelt
4241
lokationstyp: Optional["Lokationstyp"] = None
42+
"""Gibt an, ob es sich um eine Markt- oder Messlokation handelt"""
4343

44-
#: Gibt den Verbrauch in einer Zeiteinheit an
4544
energieverbrauch: Optional[list["Verbrauch"]] = None
45+
"""Gibt den Verbrauch in einer Zeiteinheit an"""
4646
# there are no optional attributes

src/bo4e/bo/fremdkosten.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ class Fremdkosten(Geschaeftsobjekt):
3636
"""
3737

3838
typ: Annotated[Literal[Typ.FREMDKOSTEN], Field(alias="_typ")] = Typ.FREMDKOSTEN
39-
#: Für diesen Zeitraum wurden die Kosten ermittelt
4039
gueltigkeit: Optional["Zeitraum"] = None
41-
#: Die Gesamtsumme über alle Kostenblöcke und -positionen
40+
"""Für diesen Zeitraum wurden die Kosten ermittelt"""
4241
summe_kosten: Optional["Betrag"] = None
43-
#: In Kostenblöcken werden Kostenpositionen zusammengefasst. Beispiele: Netzkosten, Umlagen, Steuern etc
42+
"""Die Gesamtsumme über alle Kostenblöcke und -positionen"""
4443
kostenbloecke: Optional[list["Fremdkostenblock"]] = None
44+
"""In Kostenblöcken werden Kostenpositionen zusammengefasst. Beispiele: Netzkosten, Umlagen, Steuern etc"""

src/bo4e/bo/geraet.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ class Geraet(Geschaeftsobjekt):
3535

3636
typ: Annotated[Literal[Typ.GERAET], Field(alias="_typ")] = Typ.GERAET
3737

38-
#: Die auf dem Gerät aufgedruckte Nummer, die vom MSB vergeben wird.
3938
geraetenummer: Optional[str] = None
40-
#: Bezeichnung des Geräts
39+
"""Die auf dem Gerät aufgedruckte Nummer, die vom MSB vergeben wird."""
4140
bezeichnung: Optional[str] = None
42-
#: Die übergreifende Klasse eines Geräts, beispielsweise Wandler
41+
"""Bezeichnung des Geräts"""
4342
geraeteklasse: Optional["Geraeteklasse"] = None
44-
#: Der speziellere Typ eines Gerätes, beispielsweise Stromwandler
43+
"""Die übergreifende Klasse eines Geräts, beispielsweise Wandler"""
4544
geraetetyp: Optional["Geraetetyp"] = None
45+
"""Der speziellere Typ eines Gerätes, beispielsweise Stromwandler"""

src/bo4e/bo/geschaeftsobjekt.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ class Geschaeftsobjekt(BaseModel): # pragma: no cover
3131
"""
3232

3333
# required attributes
34-
version: Annotated[Optional[str], Field(alias="_version")] = (
35-
__version__ #: Version der BO-Struktur aka "fachliche Versionierung"
36-
)
34+
version: Annotated[Optional[str], Field(alias="_version")] = __version__
35+
"""
36+
Version der BO-Struktur aka "fachliche Versionierung"
37+
"""
3738

3839
zusatz_attribute: Optional[list["ZusatzAttribut"]] = None
3940
# zusatz_attribute is a list of ZusatzAttribut objects which are used to store additional information
@@ -46,8 +47,8 @@ class Geschaeftsobjekt(BaseModel): # pragma: no cover
4647
Z.B. könnten hier UUIDs aus einer Datenbank stehen oder URLs zu einem Backend-System.
4748
"""
4849

49-
#: Hier können IDs anderer Systeme hinterlegt werden (z.B. eine SAP-GP-Nummer oder eine GUID)
5050
# pylint: disable=duplicate-code
51+
# basic configuration for pydantic's behaviour
5152
model_config = ConfigDict(
5253
alias_generator=camelize,
5354
populate_by_name=True,
@@ -56,7 +57,5 @@ class Geschaeftsobjekt(BaseModel): # pragma: no cover
5657
# an annotated version of Decimal, but you would have to use it everywhere in the pydantic models.
5758
# See this issue for more info: https://github.com/pydantic/pydantic/issues/6375
5859
json_encoders={Decimal: str},
60+
use_attribute_docstrings=True,
5961
)
60-
"""
61-
basic configuration for pydantic's behaviour
62-
"""

src/bo4e/bo/geschaeftspartner.py

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,19 @@ class Geschaeftspartner(Geschaeftsobjekt):
4040
"""
4141

4242
typ: Annotated[Literal[Typ.GESCHAEFTSPARTNER], Field(alias="_typ")] = Typ.GESCHAEFTSPARTNER
43-
#: Mögliche Anrede der Person
4443
anrede: Optional["Anrede"] = None
44+
"""Mögliche Anrede der Person"""
4545
individuelle_anrede: Optional[str] = None
4646
"""
4747
Im Falle einer nicht standardisierten Anrede kann hier eine frei definierbare Anrede vorgegeben werden.
4848
Beispiel: "Vereinsgemeinschaft", "Pfarrer", "Hochwürdigster Herr Abt".
4949
"""
50-
#: Möglicher Titel der Person
5150
titel: Optional["Titel"] = None
52-
#: Vorname der Person
51+
"""Möglicher Titel der Person"""
5352
vorname: Optional[str] = None
54-
#: Nachname (Familienname) der Person
53+
"""Vorname der Person"""
5554
nachname: Optional[str] = None
55+
"""Nachname (Familienname) der Person"""
5656

5757
ansprechpartner: Optional[list["Person"]] = None
5858
organisationstyp: Optional["Organisationstyp"] = None
@@ -63,22 +63,26 @@ class Geschaeftspartner(Geschaeftsobjekt):
6363
"""
6464
Name der Firma, wenn Gewerbe oder andere Organisation.
6565
"""
66-
#: Kontaktwege des Geschäftspartners
6766
kontaktwege: Optional[list["Kontaktweg"]] = None
68-
#: Rollen, die die Geschäftspartner inne haben (z.B. Interessent, Kunde)
67+
"""Kontaktwege des Geschäftspartners"""
6968
geschaeftspartnerrollen: Optional[list["Geschaeftspartnerrolle"]] = None
70-
#: Handelsregisternummer des Geschäftspartners
69+
"""Rollen, die die Geschäftspartner inne haben (z.B. Interessent, Kunde)"""
7170
handelsregisternummer: Optional[str] = None
72-
#: Amtsgericht bzw Handelsregistergericht, das die Handelsregisternummer herausgegeben hat
71+
"""Handelsregisternummer des Geschäftspartners"""
7372
amtsgericht: Optional[str] = None
74-
#: Die Steuer-ID des Geschäftspartners; Beispiel: "DE 813281825"
73+
"""Amtsgericht bzw Handelsregistergericht, das die Handelsregisternummer herausgegeben hat"""
7574
umsatzsteuer_id: Optional[str] = None
76-
#: Die Gläubiger-ID welche im Zahlungsverkehr verwendet wird; Z.B. "DE 47116789"
75+
"""
76+
Die Steuer-ID des Geschäftspartners; Beispiel: "DE 813281825"
77+
"""
7778
glaeubiger_id: Optional[str] = None
78-
#: Internetseite des Marktpartners
79+
"""
80+
Die Gläubiger-ID welche im Zahlungsverkehr verwendet wird; Z.B. "DE 47116789"
81+
"""
7982
website: Optional[str] = None
80-
#: Adresse des Geschäftspartners
83+
"""Internetseite des Marktpartners"""
8184
adresse: Optional["Adresse"] = None
82-
#: Todo: Add optional connection to marktteilnehmer as discussed in workshop
83-
#: not clear what is the best solution here - circular import marktteilnehmer?
84-
#: discussed in workshop on Feb 6 2024: yes we need the bidirectional option, let's figure out a solution somehow.
85+
"""Adresse des Geschäftspartners"""
86+
# Todo: Add optional connection to marktteilnehmer as discussed in workshop
87+
# not clear what is the best solution here - circular import marktteilnehmer?
88+
# discussed in workshop on Feb 6 2024: yes we need the bidirectional option, let's figure out a solution somehow.

src/bo4e/bo/kosten.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ class Kosten(Geschaeftsobjekt):
3737
"""
3838

3939
typ: Annotated[Literal[Typ.KOSTEN], Field(alias="_typ")] = Typ.KOSTEN
40-
#: Klasse der Kosten, beispielsweise Fremdkosten
4140
kostenklasse: Optional["Kostenklasse"] = None
42-
#: Für diesen Zeitraum wurden die Kosten ermittelt
41+
"""Klasse der Kosten, beispielsweise Fremdkosten"""
4342
gueltigkeit: Optional["Zeitraum"] = None
44-
#: In Kostenblöcken werden Kostenpositionen zusammengefasst. Beispiele: Netzkosten, Umlagen, Steuern etc
43+
"""Für diesen Zeitraum wurden die Kosten ermittelt"""
4544
kostenbloecke: Optional[list["Kostenblock"]] = None
45+
"""In Kostenblöcken werden Kostenpositionen zusammengefasst. Beispiele: Netzkosten, Umlagen, Steuern etc"""
4646

47-
#: Die Gesamtsumme über alle Kostenblöcke und -positionen
4847
summe_kosten: Optional[list["Betrag"]] = None
48+
"""Die Gesamtsumme über alle Kostenblöcke und -positionen"""

src/bo4e/bo/lastgang.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,18 @@ class Lastgang(Geschaeftsobjekt):
4141
"""
4242

4343
typ: Annotated[Literal[Typ.LASTGANG], Field(alias="_typ")] = Typ.LASTGANG
44-
#: Angabe, ob es sich um einen Gas- oder Stromlastgang handelt
4544
sparte: Optional["Sparte"] = None
46-
#: Definition der gemessenen Größe anhand ihrer Einheit
45+
"""Angabe, ob es sich um einen Gas- oder Stromlastgang handelt"""
4746
messgroesse: Optional["Mengeneinheit"] = None
47+
"""Definition der gemessenen Größe anhand ihrer Einheit"""
4848
#:Marktlokation, zu der der Lastgang gehört
4949
marktlokation: Optional["Marktlokation"] = None
5050
#:Marktlokation, zu der der Lastgang gehört
5151
messlokation: Optional["Messlokation"] = None
52-
#: Die im Lastgang enthaltenen Messwerte
5352
werte: Optional[list["Zeitreihenwert"]] = None
54-
#: Versionsnummer des Lastgangs
53+
"""Die im Lastgang enthaltenen Messwerte"""
5554
version: Optional[str] = None
56-
#: Die OBIS-Kennzahl für den Wert, die festlegt, welche Größe mit dem Stand gemeldet wird, z.B. '1-0:1.8.1'
55+
"""Versionsnummer des Lastgangs"""
5756
obis_kennzahl: Optional[str] = None
57+
"""Die OBIS-Kennzahl für den Wert, die festlegt, welche Größe mit dem Stand gemeldet wird, z.B. '1-0:1.8.1'"""
5858
zeit_intervall_laenge: Optional["Menge"]

src/bo4e/bo/lokationszuordnung.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,19 @@ class Lokationszuordnung(Geschaeftsobjekt):
3535

3636
typ: Annotated[Literal[Typ.LOKATIONSZUORDNUNG], Field(alias="_typ")] = Typ.LOKATIONSZUORDNUNG
3737

38-
#: Liste mit referenzierten Marktlokationen
3938
marktlokationen: Optional[list["Marktlokation"]] = None
40-
#: Liste mit referenzierten Messlokationen
39+
"""Liste mit referenzierten Marktlokationen"""
4140
messlokationen: Optional[list["Messlokation"]] = None
42-
#: Liste mit referenzierten Netzlokationen
41+
"""Liste mit referenzierten Messlokationen"""
4342
netzlokationen: Optional[list["Netzlokation"]] = None
44-
#: Liste mit referenzierten technischen Ressourcen
43+
"""Liste mit referenzierten Netzlokationen"""
4544
technische_ressourcen: Optional[list["TechnischeRessource"]] = None
46-
#: Liste mit referenzierten steuerbaren Ressourcen
45+
"""Liste mit referenzierten technischen Ressourcen"""
4746
steuerbare_ressourcen: Optional[list["SteuerbareRessource"]] = None
48-
#: Zeitspanne der Gültigkeit
47+
"""Liste mit referenzierten steuerbaren Ressourcen"""
4948
gueltigkeit: Optional["Zeitspanne"] = None
50-
#: Verknüpfungsrichtung z.B. Malo-Melo [TODO: Eventuell anderer Datentyp]
49+
"""Zeitspanne der Gültigkeit"""
5150
zuordnungstyp: Optional[str] = None
52-
#: Code, der angibt wie die Lokationsbündelstruktur zusammengesetzt ist (zu finden unter "Codeliste der Lokationsbündelstrukturen" auf https://www.edi-energy.de/index.php?id=38)
51+
"""Verknüpfungsrichtung z.B. Malo-Melo [TODO: Eventuell anderer Datentyp]"""
5352
lokationsbuendelcode: Optional[str] = None
53+
"""Code, der angibt wie die Lokationsbündelstruktur zusammengesetzt ist (zu finden unter "Codeliste der Lokationsbündelstrukturen" auf https://www.edi-energy.de/index.php?id=38)"""

0 commit comments

Comments
 (0)