From b29fc2eb23f063c07bb72a276ce74d7c5eadfb42 Mon Sep 17 00:00:00 2001 From: Leon Haffmans <49658102+lord-haffi@users.noreply.github.com> Date: Thu, 10 Oct 2024 18:19:22 +0200 Subject: [PATCH] Use literal type instead of enum type for `_typ` (#905) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use literal type instead of enum type for `_typ` * 🔥 * 🩹mypy * 🩹pylint * 🩹coverage * 🩹tests * 🩹docs * 🩹pylint --- docs/compatibility/change_schemas.py | 1 + docs/compatibility/diff.py | 39 ++++++++++++++------ src/bo4e/bo/angebot.py | 4 +-- src/bo4e/bo/ausschreibung.py | 4 +-- src/bo4e/bo/buendelvertrag.py | 4 +-- src/bo4e/bo/energiemenge.py | 4 +-- src/bo4e/bo/fremdkosten.py | 4 +-- src/bo4e/bo/geraet.py | 4 +-- src/bo4e/bo/geschaeftsobjekt.py | 6 +--- src/bo4e/bo/geschaeftspartner.py | 4 +-- src/bo4e/bo/kosten.py | 4 +-- src/bo4e/bo/lastgang.py | 8 ++--- src/bo4e/bo/lokationszuordnung.py | 4 +-- src/bo4e/bo/marktlokation.py | 4 +-- src/bo4e/bo/marktteilnehmer.py | 4 +-- src/bo4e/bo/messlokation.py | 4 +-- src/bo4e/bo/netzlokation.py | 4 +-- src/bo4e/bo/person.py | 4 +-- src/bo4e/bo/preisblatt.py | 4 +-- src/bo4e/bo/preisblattdienstleistung.py | 6 ++-- src/bo4e/bo/preisblatthardware.py | 6 ++-- src/bo4e/bo/preisblattkonzessionsabgabe.py | 6 ++-- src/bo4e/bo/preisblattmessung.py | 6 ++-- src/bo4e/bo/preisblattnetznutzung.py | 6 ++-- src/bo4e/bo/rechnung.py | 4 +-- src/bo4e/bo/region.py | 4 +-- src/bo4e/bo/regionaltarif.py | 4 +-- src/bo4e/bo/standorteigenschaften.py | 4 +-- src/bo4e/bo/steuerbareressource.py | 4 +-- src/bo4e/bo/tarif.py | 4 +-- src/bo4e/bo/tarifinfo.py | 4 +-- src/bo4e/bo/tarifkosten.py | 4 +-- src/bo4e/bo/tarifpreisblatt.py | 4 +-- src/bo4e/bo/technischeressource.py | 4 +-- src/bo4e/bo/vertrag.py | 4 +-- src/bo4e/bo/zaehler.py | 4 +-- src/bo4e/bo/zeitreihe.py | 4 +-- src/bo4e/utils/__init__.py | 2 +- tests/test_geschaeftsobjekt.py | 42 ---------------------- 39 files changed, 111 insertions(+), 129 deletions(-) delete mode 100644 tests/test_geschaeftsobjekt.py diff --git a/docs/compatibility/change_schemas.py b/docs/compatibility/change_schemas.py index 9716af1b7..b7aa54928 100644 --- a/docs/compatibility/change_schemas.py +++ b/docs/compatibility/change_schemas.py @@ -17,6 +17,7 @@ class ChangeType(StrEnum): FIELD_REMOVED = "field_removed" FIELD_DEFAULT_CHANGED = "field_default_changed" FIELD_DESCRIPTION_CHANGED = "field_description_changed" + FIELD_TITLE_CHANGED = "field_title_changed" # field type change types FIELD_CARDINALITY_CHANGED = "field_cardinality_changed" FIELD_REFERENCE_CHANGED = "field_reference_changed" diff --git a/docs/compatibility/diff.py b/docs/compatibility/diff.py index 5f53eaad1..f54bbaf02 100644 --- a/docs/compatibility/diff.py +++ b/docs/compatibility/diff.py @@ -3,6 +3,7 @@ """ import itertools +import logging import re from pathlib import Path from typing import Iterable, Sequence @@ -11,6 +12,8 @@ from . import change_schemas, loader +logger = logging.getLogger(__name__) + REGEX_IGNORE_VERSION = re.compile(r"v\d+\.\d+\.\d+(-rc\d+)?") @@ -21,11 +24,23 @@ def _diff_type_base( This function compares two type base schemas and yields the changes. """ if schema_old.title != schema_new.title: - raise RuntimeError( + logger.warning( ( "Title should not change. Renaming is not detectable and the titles are autogenerated.\n" - f"{schema_old.title} -> {schema_new.title}" - ) + "'%s' -> '%s'\n" + "%s -> %s" + ), + schema_old.title, + schema_new.title, + old_trace, + new_trace, + ) + yield change_schemas.Change( + type=change_schemas.ChangeType.FIELD_TITLE_CHANGED, + old=schema_old.title, + new=schema_new.title, + old_trace=old_trace, + new_trace=new_trace, ) if REGEX_IGNORE_VERSION.sub(schema_old.description, "{__gh_version__}") != REGEX_IGNORE_VERSION.sub( schema_new.description, "{__gh_version__}" @@ -288,7 +303,9 @@ def _diff_root_schemas( yield from _diff_schema_type(schema_old, schema_new, old_trace, new_trace) -def diff_schemas(schemas_old: Path, schemas_new: Path) -> Iterable[change_schemas.Change]: +def diff_schemas( + schemas_old: Path, schemas_new: Path, old_trace: str, new_trace: str +) -> Iterable[change_schemas.Change]: """ This function compares two BO4E versions and yields the changes. Note: The paths to the old and the new schemas should correspond to the same root node of the tree structure. @@ -302,23 +319,23 @@ def diff_schemas(schemas_old: Path, schemas_new: Path) -> Iterable[change_schema type=change_schemas.ChangeType.CLASS_REMOVED, old=loader.load_schema_file(schemas_old / schema_file), new=None, - old_trace=f"{'/'.join(schema_file.with_suffix('').parts)}#", - new_trace="#", + old_trace=f"{old_trace}/{'/'.join(schema_file.with_suffix('').parts)}#", + new_trace=f"{new_trace}/#", ) for schema_file in new_schema_files - old_schema_files: yield change_schemas.Change( type=change_schemas.ChangeType.CLASS_ADDED, old=None, new=loader.load_schema_file(schemas_new / schema_file), - old_trace="#", - new_trace=f"{'/'.join(schema_file.with_suffix('').parts)}#", + old_trace=f"{old_trace}/#", + new_trace=f"{new_trace}/{'/'.join(schema_file.with_suffix('').parts)}#", ) for schema_file in old_schema_files & new_schema_files: yield from _diff_root_schemas( loader.load_schema_file(schemas_old / schema_file), loader.load_schema_file(schemas_new / schema_file), - f"{'/'.join(schema_file.with_suffix('').parts)}#", - f"{'/'.join(schema_file.with_suffix('').parts)}#", + f"{old_trace}/{'/'.join(schema_file.with_suffix('').parts)}#", + f"{new_trace}/{'/'.join(schema_file.with_suffix('').parts)}#", ) @@ -333,7 +350,7 @@ def compare_bo4e_versions( dir_old_schemas = loader.pull_or_reuse_bo4e_version(version_old, gh_token) dir_new_schemas = loader.pull_or_reuse_bo4e_version(version_new, gh_token, from_local=from_local) print(f"Comparing {version_old} with {version_new}") - yield from diff_schemas(dir_old_schemas, dir_new_schemas) + yield from diff_schemas(dir_old_schemas, dir_new_schemas, version_old, version_new) def compare_bo4e_versions_iteratively( diff --git a/src/bo4e/bo/angebot.py b/src/bo4e/bo/angebot.py index 7245741b7..6eaac3380 100644 --- a/src/bo4e/bo/angebot.py +++ b/src/bo4e/bo/angebot.py @@ -4,7 +4,7 @@ # pylint: disable=too-few-public-methods, too-many-instance-attributes # pylint: disable=no-name-in-module -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional import pydantic from pydantic import Field @@ -38,7 +38,7 @@ class Angebot(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.ANGEBOT + typ: Annotated[Literal[Typ.ANGEBOT], Field(alias="_typ")] = Typ.ANGEBOT #: Eindeutige Nummer des Angebotes angebotsnummer: Optional[str] = None #: Erstellungsdatum des Angebots diff --git a/src/bo4e/bo/ausschreibung.py b/src/bo4e/bo/ausschreibung.py index 59840cefe..4c3b05524 100644 --- a/src/bo4e/bo/ausschreibung.py +++ b/src/bo4e/bo/ausschreibung.py @@ -4,7 +4,7 @@ # pylint: disable=too-few-public-methods, too-many-instance-attributes # pylint: disable=no-name-in-module -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional import pydantic from pydantic import Field @@ -36,7 +36,7 @@ class Ausschreibung(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.AUSSCHREIBUNG + typ: Annotated[Literal[Typ.AUSSCHREIBUNG], Field(alias="_typ")] = Typ.AUSSCHREIBUNG #: Vom Herausgeber der Ausschreibung vergebene eindeutige Nummer ausschreibungsnummer: Optional[str] = None #: Aufzählung für die Typisierung von Ausschreibungen diff --git a/src/bo4e/bo/buendelvertrag.py b/src/bo4e/bo/buendelvertrag.py index 0710713c4..20747b66d 100644 --- a/src/bo4e/bo/buendelvertrag.py +++ b/src/bo4e/bo/buendelvertrag.py @@ -4,7 +4,7 @@ # pylint: disable=too-few-public-methods # pylint: disable=no-name-in-module -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional import pydantic from pydantic import Field @@ -38,7 +38,7 @@ class Buendelvertrag(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.BUENDELVERTRAG + typ: Annotated[Literal[Typ.BUENDELVERTRAG], Field(alias="_typ")] = Typ.BUENDELVERTRAG # pylint: disable=duplicate-code #: Eine im Verwendungskontext eindeutige Nummer für den Vertrag diff --git a/src/bo4e/bo/energiemenge.py b/src/bo4e/bo/energiemenge.py index fc6a33bb0..712ee59f2 100644 --- a/src/bo4e/bo/energiemenge.py +++ b/src/bo4e/bo/energiemenge.py @@ -3,7 +3,7 @@ and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -34,7 +34,7 @@ class Energiemenge(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.ENERGIEMENGE + typ: Annotated[Literal[Typ.ENERGIEMENGE], Field(alias="_typ")] = Typ.ENERGIEMENGE #: Eindeutige Nummer der Marktlokation bzw. der Messlokation, zu der die Energiemenge gehört lokations_id: Optional[str] = None # todo: add validator such that only mess- or marktlokations IDs are accepted + cross check with lokationstyp diff --git a/src/bo4e/bo/fremdkosten.py b/src/bo4e/bo/fremdkosten.py index 1f4a6bbfb..322877bb8 100644 --- a/src/bo4e/bo/fremdkosten.py +++ b/src/bo4e/bo/fremdkosten.py @@ -2,7 +2,7 @@ Contains Fremdkosten class and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -35,7 +35,7 @@ class Fremdkosten(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.FREMDKOSTEN + typ: Annotated[Literal[Typ.FREMDKOSTEN], Field(alias="_typ")] = Typ.FREMDKOSTEN #: Für diesen Zeitraum wurden die Kosten ermittelt gueltigkeit: Optional["Zeitraum"] = None #: Die Gesamtsumme über alle Kostenblöcke und -positionen diff --git a/src/bo4e/bo/geraet.py b/src/bo4e/bo/geraet.py index 104ef4f3e..54cf4cfc3 100644 --- a/src/bo4e/bo/geraet.py +++ b/src/bo4e/bo/geraet.py @@ -3,7 +3,7 @@ and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -33,7 +33,7 @@ class Geraet(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.GERAET + typ: Annotated[Literal[Typ.GERAET], Field(alias="_typ")] = Typ.GERAET #: Die auf dem Gerät aufgedruckte Nummer, die vom MSB vergeben wird. geraetenummer: Optional[str] = None diff --git a/src/bo4e/bo/geschaeftsobjekt.py b/src/bo4e/bo/geschaeftsobjekt.py index e3db0e657..780d52ca7 100644 --- a/src/bo4e/bo/geschaeftsobjekt.py +++ b/src/bo4e/bo/geschaeftsobjekt.py @@ -10,14 +10,13 @@ from bo4e.version import __version__ from bo4e.zusatzattribut import ZusatzAttribut -from ..enum.typ import Typ from ..utils import postprocess_docstring # pylint: disable=too-few-public-methods @postprocess_docstring -class Geschaeftsobjekt(BaseModel): +class Geschaeftsobjekt(BaseModel): # pragma: no cover """ Das BO Geschäftsobjekt ist der Master für alle Geschäftsobjekte. Alle Attribute, die hier in diesem BO enthalten sind, werden an alle BOs vererbt. @@ -35,9 +34,6 @@ class Geschaeftsobjekt(BaseModel): version: Annotated[Optional[str], Field(alias="_version")] = ( __version__ #: Version der BO-Struktur aka "fachliche Versionierung" ) - # src/_bo4e_python_version.py - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.GESCHAEFTSOBJEKT #: Der Typ des Geschäftsobjektes - # bo_typ is used as discriminator f.e. for databases or deserialization zusatz_attribute: Optional[list["ZusatzAttribut"]] = None # zusatz_attribute is a list of ZusatzAttribut objects which are used to store additional information diff --git a/src/bo4e/bo/geschaeftspartner.py b/src/bo4e/bo/geschaeftspartner.py index 992bb0650..0efad7b58 100644 --- a/src/bo4e/bo/geschaeftspartner.py +++ b/src/bo4e/bo/geschaeftspartner.py @@ -4,7 +4,7 @@ """ # pylint: disable=too-many-instance-attributes, too-few-public-methods, disable=duplicate-code -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -39,7 +39,7 @@ class Geschaeftspartner(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.GESCHAEFTSPARTNER + typ: Annotated[Literal[Typ.GESCHAEFTSPARTNER], Field(alias="_typ")] = Typ.GESCHAEFTSPARTNER #: Mögliche Anrede der Person anrede: Optional["Anrede"] = None individuelle_anrede: Optional[str] = None diff --git a/src/bo4e/bo/kosten.py b/src/bo4e/bo/kosten.py index afac21efa..29e3a48a0 100644 --- a/src/bo4e/bo/kosten.py +++ b/src/bo4e/bo/kosten.py @@ -2,7 +2,7 @@ Contains Kosten class and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -36,7 +36,7 @@ class Kosten(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.KOSTEN + typ: Annotated[Literal[Typ.KOSTEN], Field(alias="_typ")] = Typ.KOSTEN #: Klasse der Kosten, beispielsweise Fremdkosten kostenklasse: Optional["Kostenklasse"] = None #: Für diesen Zeitraum wurden die Kosten ermittelt diff --git a/src/bo4e/bo/lastgang.py b/src/bo4e/bo/lastgang.py index dda96e180..f334cec1a 100644 --- a/src/bo4e/bo/lastgang.py +++ b/src/bo4e/bo/lastgang.py @@ -3,11 +3,11 @@ and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional # pylint: disable=too-few-public-methods # pylint: disable=no-name-in-module -from pydantic import Field, constr +from pydantic import Field from ..enum.typ import Typ from ..utils import postprocess_docstring @@ -40,7 +40,7 @@ class Lastgang(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.LASTGANG + typ: Annotated[Literal[Typ.LASTGANG], Field(alias="_typ")] = Typ.LASTGANG #: Angabe, ob es sich um einen Gas- oder Stromlastgang handelt sparte: Optional["Sparte"] = None #: Definition der gemessenen Größe anhand ihrer Einheit @@ -54,5 +54,5 @@ class Lastgang(Geschaeftsobjekt): #: Versionsnummer des Lastgangs version: Optional[str] = None #: Die OBIS-Kennzahl für den Wert, die festlegt, welche Größe mit dem Stand gemeldet wird, z.B. '1-0:1.8.1' - obis_kennzahl: Optional[constr(strict=True)] = None # type: ignore[valid-type] + obis_kennzahl: Optional[str] = None zeit_intervall_laenge: Optional["Menge"] diff --git a/src/bo4e/bo/lokationszuordnung.py b/src/bo4e/bo/lokationszuordnung.py index e856d4dc5..1aecf8008 100644 --- a/src/bo4e/bo/lokationszuordnung.py +++ b/src/bo4e/bo/lokationszuordnung.py @@ -2,7 +2,7 @@ Contains Lokationszuordnung class """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -33,7 +33,7 @@ class Lokationszuordnung(Geschaeftsobjekt): `Lokationszuordnung JSON Schema `_ """ - typ: Annotated[Optional[Typ], Field(alias="_typ")] = Typ.LOKATIONSZUORDNUNG + typ: Annotated[Literal[Typ.LOKATIONSZUORDNUNG], Field(alias="_typ")] = Typ.LOKATIONSZUORDNUNG #: Liste mit referenzierten Marktlokationen marktlokationen: Optional[list["Marktlokation"]] = None diff --git a/src/bo4e/bo/marktlokation.py b/src/bo4e/bo/marktlokation.py index d94cd0cce..9724bac98 100644 --- a/src/bo4e/bo/marktlokation.py +++ b/src/bo4e/bo/marktlokation.py @@ -4,7 +4,7 @@ """ # pylint: disable=too-many-instance-attributes, too-few-public-methods -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -46,7 +46,7 @@ class Marktlokation(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.MARKTLOKATION + typ: Annotated[Literal[Typ.MARKTLOKATION], Field(alias="_typ")] = Typ.MARKTLOKATION #: Identifikationsnummer einer Marktlokation, an der Energie entweder verbraucht, oder erzeugt wird. marktlokations_id: Optional[str] = None diff --git a/src/bo4e/bo/marktteilnehmer.py b/src/bo4e/bo/marktteilnehmer.py index a1691389a..6474acfd9 100644 --- a/src/bo4e/bo/marktteilnehmer.py +++ b/src/bo4e/bo/marktteilnehmer.py @@ -5,7 +5,7 @@ # pylint: disable=too-few-public-methods # pylint: disable=no-name-in-module -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -34,7 +34,7 @@ class Marktteilnehmer(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.MARKTTEILNEHMER + typ: Annotated[Literal[Typ.MARKTTEILNEHMER], Field(alias="_typ")] = Typ.MARKTTEILNEHMER #: Gibt im Klartext die Bezeichnung der Marktrolle an marktrolle: Optional["Marktrolle"] = None #: Gibt die Codenummer der Marktrolle an diff --git a/src/bo4e/bo/messlokation.py b/src/bo4e/bo/messlokation.py index a2eb9f713..8c6705b80 100644 --- a/src/bo4e/bo/messlokation.py +++ b/src/bo4e/bo/messlokation.py @@ -3,7 +3,7 @@ and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -39,7 +39,7 @@ class Messlokation(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.MESSLOKATION + typ: Annotated[Literal[Typ.MESSLOKATION], Field(alias="_typ")] = Typ.MESSLOKATION #: Die Messlokations-Identifikation; Das ist die frühere Zählpunktbezeichnung messlokations_id: Optional[str] = None diff --git a/src/bo4e/bo/netzlokation.py b/src/bo4e/bo/netzlokation.py index b4e37cf97..034f88741 100644 --- a/src/bo4e/bo/netzlokation.py +++ b/src/bo4e/bo/netzlokation.py @@ -3,7 +3,7 @@ and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -37,7 +37,7 @@ class Netzlokation(Geschaeftsobjekt): """ - typ: Annotated[Optional[Typ], Field(alias="_typ")] = Typ.NETZLOKATION + typ: Annotated[Literal[Typ.NETZLOKATION], Field(alias="_typ")] = Typ.NETZLOKATION #: Identifikationsnummer einer Netzlokation, an der Energie entweder verbraucht, oder erzeugt wird netzlokations_id: Optional[str] = None diff --git a/src/bo4e/bo/person.py b/src/bo4e/bo/person.py index c6e246083..0a4b17e65 100644 --- a/src/bo4e/bo/person.py +++ b/src/bo4e/bo/person.py @@ -3,7 +3,7 @@ and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional import pydantic from pydantic import Field @@ -37,7 +37,7 @@ class Person(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.PERSON + typ: Annotated[Literal[Typ.PERSON], Field(alias="_typ")] = Typ.PERSON #: Mögliche Anrede der Person anrede: Optional["Anrede"] = None individuelle_anrede: Optional[str] = None diff --git a/src/bo4e/bo/preisblatt.py b/src/bo4e/bo/preisblatt.py index 1c6803719..fcb8a7809 100644 --- a/src/bo4e/bo/preisblatt.py +++ b/src/bo4e/bo/preisblatt.py @@ -5,7 +5,7 @@ # pylint: disable=too-few-public-methods # pylint: disable=no-name-in-module -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -40,7 +40,7 @@ class Preisblatt(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.PREISBLATT + typ: Annotated[Literal[Typ.PREISBLATT], Field(alias="_typ")] = Typ.PREISBLATT #: Eine Bezeichnung für das Preisblatt bezeichnung: Optional[str] = None #: Preisblatt gilt für angegebene Sparte diff --git a/src/bo4e/bo/preisblattdienstleistung.py b/src/bo4e/bo/preisblattdienstleistung.py index 6cebe560d..b61142e78 100644 --- a/src/bo4e/bo/preisblattdienstleistung.py +++ b/src/bo4e/bo/preisblattdienstleistung.py @@ -2,7 +2,7 @@ Contains PreisblattDienstleistung class and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -33,7 +33,9 @@ class PreisblattDienstleistung(Preisblatt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.PREISBLATTDIENSTLEISTUNG + typ: Annotated[Literal[Typ.PREISBLATTDIENSTLEISTUNG], Field(alias="_typ")] = ( + Typ.PREISBLATTDIENSTLEISTUNG # type: ignore[assignment] + ) # required attributes (additional to those of Preisblatt) #: Die Preise gelten für Marktlokationen der angebebenen Bilanzierungsmethode bilanzierungsmethode: Optional["Bilanzierungsmethode"] = None diff --git a/src/bo4e/bo/preisblatthardware.py b/src/bo4e/bo/preisblatthardware.py index 3170f3c0e..f18261307 100644 --- a/src/bo4e/bo/preisblatthardware.py +++ b/src/bo4e/bo/preisblatthardware.py @@ -2,7 +2,7 @@ Contains PreisblattHardware class and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -34,7 +34,9 @@ class PreisblattHardware(Preisblatt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.PREISBLATTHARDWARE + typ: Annotated[Literal[Typ.PREISBLATTHARDWARE], Field(alias="_typ")] = ( + Typ.PREISBLATTHARDWARE # type: ignore[assignment] + ) # required attributes (additional to those of Preisblatt) #: Die Preise gelten für Marktlokationen der angebebenen Bilanzierungsmethode bilanzierungsmethode: Optional["Bilanzierungsmethode"] = None diff --git a/src/bo4e/bo/preisblattkonzessionsabgabe.py b/src/bo4e/bo/preisblattkonzessionsabgabe.py index 6f3ad1b25..d98b6c44e 100644 --- a/src/bo4e/bo/preisblattkonzessionsabgabe.py +++ b/src/bo4e/bo/preisblattkonzessionsabgabe.py @@ -2,7 +2,7 @@ Contains PreisblattKonzessionsabgabe class and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -31,7 +31,9 @@ class PreisblattKonzessionsabgabe(Preisblatt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.PREISBLATTKONZESSIONSABGABE + typ: Annotated[Literal[Typ.PREISBLATTKONZESSIONSABGABE], Field(alias="_typ")] = ( + Typ.PREISBLATTKONZESSIONSABGABE # type: ignore[assignment] + ) # required attributes (additional to those of Preisblatt) #: Kundegruppe anhand derer die Höhe der Konzessionabgabe festgelegt ist kundengruppe_k_a: Optional["KundengruppeKA"] = None diff --git a/src/bo4e/bo/preisblattmessung.py b/src/bo4e/bo/preisblattmessung.py index b6b8e100b..f0cb7a871 100644 --- a/src/bo4e/bo/preisblattmessung.py +++ b/src/bo4e/bo/preisblattmessung.py @@ -2,7 +2,7 @@ Contains PreisblattMessung class and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -35,7 +35,9 @@ class PreisblattMessung(Preisblatt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.PREISBLATTMESSUNG + typ: Annotated[Literal[Typ.PREISBLATTMESSUNG], Field(alias="_typ")] = ( + Typ.PREISBLATTMESSUNG # type: ignore[assignment] + ) # required attributes (additional to those of Preisblatt) #: Die Preise gelten für Marktlokationen der angebebenen Bilanzierungsmethode bilanzierungsmethode: Optional["Bilanzierungsmethode"] = None diff --git a/src/bo4e/bo/preisblattnetznutzung.py b/src/bo4e/bo/preisblattnetznutzung.py index 030b4bf40..74521e585 100644 --- a/src/bo4e/bo/preisblattnetznutzung.py +++ b/src/bo4e/bo/preisblattnetznutzung.py @@ -2,7 +2,7 @@ Contains PreisblattNetnutzung class and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -33,7 +33,9 @@ class PreisblattNetznutzung(Preisblatt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.PREISBLATTNETZNUTZUNG + typ: Annotated[Literal[Typ.PREISBLATTNETZNUTZUNG], Field(alias="_typ")] = ( + Typ.PREISBLATTNETZNUTZUNG # type: ignore[assignment] + ) # required attributes (additional to those of Preisblatt) #: Die Preise gelten für Marktlokationen der angebebenen Bilanzierungsmethode bilanzierungsmethode: Optional["Bilanzierungsmethode"] = None diff --git a/src/bo4e/bo/rechnung.py b/src/bo4e/bo/rechnung.py index 2672dbbea..2d17f7c05 100644 --- a/src/bo4e/bo/rechnung.py +++ b/src/bo4e/bo/rechnung.py @@ -3,7 +3,7 @@ and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional import pydantic from pydantic import Field @@ -43,7 +43,7 @@ class Rechnung(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.RECHNUNG + typ: Annotated[Literal[Typ.RECHNUNG], Field(alias="_typ")] = Typ.RECHNUNG ist_storno: Optional[bool] = None """ Kennzeichnung, ob es sich um eine Stornorechnung handelt; diff --git a/src/bo4e/bo/region.py b/src/bo4e/bo/region.py index 0b95b8bd8..85637068e 100644 --- a/src/bo4e/bo/region.py +++ b/src/bo4e/bo/region.py @@ -2,7 +2,7 @@ Contains Region class and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -32,7 +32,7 @@ class Region(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.REGION + typ: Annotated[Literal[Typ.REGION], Field(alias="_typ")] = Typ.REGION #: Bezeichnung der Region bezeichnung: Optional[str] = None diff --git a/src/bo4e/bo/regionaltarif.py b/src/bo4e/bo/regionaltarif.py index bd0b0d890..ad5dd9ce4 100644 --- a/src/bo4e/bo/regionaltarif.py +++ b/src/bo4e/bo/regionaltarif.py @@ -2,7 +2,7 @@ Contains Regionaltarif class and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional import pydantic from pydantic import Field @@ -35,7 +35,7 @@ class Regionaltarif(Tarifinfo): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.REGIONALTARIF + typ: Annotated[Literal[Typ.REGIONALTARIF], Field(alias="_typ")] = Typ.REGIONALTARIF # type: ignore[assignment] #: Gibt an, wann der Preis zuletzt angepasst wurde preisstand: Optional[pydantic.AwareDatetime] = None #: Für die Berechnung der Kosten sind die hier abgebildeten Parameter heranzuziehen diff --git a/src/bo4e/bo/standorteigenschaften.py b/src/bo4e/bo/standorteigenschaften.py index 607631a8f..632eb8ca8 100644 --- a/src/bo4e/bo/standorteigenschaften.py +++ b/src/bo4e/bo/standorteigenschaften.py @@ -5,7 +5,7 @@ # pylint: disable=too-few-public-methods # pylint: disable=no-name-in-module -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -32,7 +32,7 @@ class Standorteigenschaften(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.STANDORTEIGENSCHAFTEN + typ: Annotated[Literal[Typ.STANDORTEIGENSCHAFTEN], Field(alias="_typ")] = Typ.STANDORTEIGENSCHAFTEN #: Eigenschaften zur Sparte Strom eigenschaften_strom: Optional[list["StandorteigenschaftenStrom"]] = None diff --git a/src/bo4e/bo/steuerbareressource.py b/src/bo4e/bo/steuerbareressource.py index 89bca3186..ae35f7ec0 100644 --- a/src/bo4e/bo/steuerbareressource.py +++ b/src/bo4e/bo/steuerbareressource.py @@ -3,7 +3,7 @@ and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -34,7 +34,7 @@ class SteuerbareRessource(Geschaeftsobjekt): """ - typ: Annotated[Optional[Typ], Field(alias="_typ")] = Typ.STEUERBARERESSOURCE + typ: Annotated[Literal[Typ.STEUERBARERESSOURCE], Field(alias="_typ")] = Typ.STEUERBARERESSOURCE #: Id der steuerbaren Ressource steuerbare_ressource_id: Optional[str] = None diff --git a/src/bo4e/bo/tarif.py b/src/bo4e/bo/tarif.py index 23face00b..4abb523ec 100644 --- a/src/bo4e/bo/tarif.py +++ b/src/bo4e/bo/tarif.py @@ -2,7 +2,7 @@ Contains Tarif class and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional import pydantic from pydantic import Field @@ -37,7 +37,7 @@ class Tarif(Tarifinfo): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.TARIF + typ: Annotated[Literal[Typ.TARIF], Field(alias="_typ")] = Typ.TARIF # type: ignore[assignment] #: Gibt an, wann der Preis zuletzt angepasst wurde preisstand: Optional[pydantic.AwareDatetime] = None #: Für die Berechnung der Kosten sind die hier abgebildeten Parameter heranzuziehen diff --git a/src/bo4e/bo/tarifinfo.py b/src/bo4e/bo/tarifinfo.py index 9919eb232..ddb22c44c 100644 --- a/src/bo4e/bo/tarifinfo.py +++ b/src/bo4e/bo/tarifinfo.py @@ -5,7 +5,7 @@ # pylint: disable=too-many-instance-attributes, too-few-public-methods # pylint: disable=no-name-in-module -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional import pydantic from pydantic import Field @@ -41,7 +41,7 @@ class Tarifinfo(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.TARIFINFO + typ: Annotated[Literal[Typ.TARIFINFO], Field(alias="_typ")] = Typ.TARIFINFO #: Name des Tarifs bezeichnung: Optional[str] = None #: Der Name des Marktpartners, der den Tarif anbietet diff --git a/src/bo4e/bo/tarifkosten.py b/src/bo4e/bo/tarifkosten.py index 273d3c17f..0d8b3b80a 100644 --- a/src/bo4e/bo/tarifkosten.py +++ b/src/bo4e/bo/tarifkosten.py @@ -3,7 +3,7 @@ and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -32,7 +32,7 @@ class Tarifkosten(Tarifinfo): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.TARIFKOSTEN + typ: Annotated[Literal[Typ.TARIFKOSTEN], Field(alias="_typ")] = Typ.TARIFKOSTEN # type: ignore[assignment] kosten: Optional["Kosten"] = None """ Referenz (Link) zu einem Kostenobjekt, in dem die Kosten für die Anwendung diff --git a/src/bo4e/bo/tarifpreisblatt.py b/src/bo4e/bo/tarifpreisblatt.py index 28de8b998..c1337839b 100644 --- a/src/bo4e/bo/tarifpreisblatt.py +++ b/src/bo4e/bo/tarifpreisblatt.py @@ -2,7 +2,7 @@ Contains Tarifpreisblatt class and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional import pydantic from pydantic import Field @@ -37,7 +37,7 @@ class Tarifpreisblatt(Tarifinfo): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.TARIFPREISBLATT + typ: Annotated[Literal[Typ.TARIFPREISBLATT], Field(alias="_typ")] = Typ.TARIFPREISBLATT # type: ignore[assignment] # required attributes (additional to those of Tarifinfo) #: Gibt an, wann der Preis zuletzt angepasst wurde preisstand: Optional[pydantic.AwareDatetime] = None diff --git a/src/bo4e/bo/technischeressource.py b/src/bo4e/bo/technischeressource.py index 4a3257961..1d304967a 100644 --- a/src/bo4e/bo/technischeressource.py +++ b/src/bo4e/bo/technischeressource.py @@ -3,7 +3,7 @@ and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -38,7 +38,7 @@ class TechnischeRessource(Geschaeftsobjekt): """ - typ: Annotated[Optional[Typ], Field(alias="_typ")] = Typ.TECHNISCHERESSOURCE + typ: Annotated[Literal[Typ.TECHNISCHERESSOURCE], Field(alias="_typ")] = Typ.TECHNISCHERESSOURCE #: Identifikationsnummer einer technischen Ressource technische_ressource_id: Optional[str] = None diff --git a/src/bo4e/bo/vertrag.py b/src/bo4e/bo/vertrag.py index d2ae48f83..3407c72fd 100644 --- a/src/bo4e/bo/vertrag.py +++ b/src/bo4e/bo/vertrag.py @@ -3,7 +3,7 @@ and corresponding marshmallow schema for de-/serialization """ -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional import pydantic from pydantic import Field @@ -42,7 +42,7 @@ class Vertrag(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.VERTRAG + typ: Annotated[Literal[Typ.VERTRAG], Field(alias="_typ")] = Typ.VERTRAG # pylint: disable=duplicate-code #: Eine im Verwendungskontext eindeutige Nummer für den Vertrag vertragsnummer: Optional[str] = None diff --git a/src/bo4e/bo/zaehler.py b/src/bo4e/bo/zaehler.py index 9e0c28c76..ef82244e4 100644 --- a/src/bo4e/bo/zaehler.py +++ b/src/bo4e/bo/zaehler.py @@ -7,7 +7,7 @@ # pylint: disable=unused-argument # pylint: disable=no-name-in-module -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional import pydantic from pydantic import Field @@ -46,7 +46,7 @@ class Zaehler(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.ZAEHLER + typ: Annotated[Literal[Typ.ZAEHLER], Field(alias="_typ")] = Typ.ZAEHLER zaehlernummer: Optional[str] = None #: Nummerierung des Zählers,vergeben durch den Messstellenbetreiber sparte: Optional["Sparte"] = None #: Strom oder Gas zaehlerauspraegung: Optional["Zaehlerauspraegung"] = None #: Spezifikation die Richtung des Zählers betreffend diff --git a/src/bo4e/bo/zeitreihe.py b/src/bo4e/bo/zeitreihe.py index d994fb0ec..4b224e459 100644 --- a/src/bo4e/bo/zeitreihe.py +++ b/src/bo4e/bo/zeitreihe.py @@ -4,7 +4,7 @@ # pylint: disable=too-few-public-methods, too-many-instance-attributes # pylint: disable=no-name-in-module -from typing import TYPE_CHECKING, Annotated, Optional +from typing import TYPE_CHECKING, Annotated, Literal, Optional from pydantic import Field @@ -36,7 +36,7 @@ class Zeitreihe(Geschaeftsobjekt): """ - typ: Annotated[Optional["Typ"], Field(alias="_typ")] = Typ.ZEITREIHE + typ: Annotated[Literal[Typ.ZEITREIHE], Field(alias="_typ")] = Typ.ZEITREIHE #: Bezeichnung für die Zeitreihe bezeichnung: Optional[str] = None #: Beschreibt, was gemessen wurde (z.B. Strom, Spannung, Wirkleistung, Scheinleistung) diff --git a/src/bo4e/utils/__init__.py b/src/bo4e/utils/__init__.py index ac3735e40..014a08155 100644 --- a/src/bo4e/utils/__init__.py +++ b/src/bo4e/utils/__init__.py @@ -11,7 +11,7 @@ from ..version import __gh_version__ T = TypeVar("T", bound=BaseModel) -REGEX_CLASS_START = re.compile(r"class \w+\(.*\):\s+\"{3}(?:(?:\"{0,2}[^\"])*)\"{3}\n") +REGEX_CLASS_START = re.compile(r"class \w+\(.*\):(?:\s*#[^\n]*)?\n\s+\"{3}(?:\"{0,2}[^\"])*\"{3}\n") # https://regex101.com/r/dQPi06/1 diff --git a/tests/test_geschaeftsobjekt.py b/tests/test_geschaeftsobjekt.py deleted file mode 100644 index bd9aa0f49..000000000 --- a/tests/test_geschaeftsobjekt.py +++ /dev/null @@ -1,42 +0,0 @@ -import pytest -from pydantic import ValidationError - -from bo4e import Geschaeftsobjekt, Typ -from bo4e.zusatzattribut import ZusatzAttribut -from tests.serialization_helper import assert_serialization_roundtrip - - -class TestGeschaeftsobjekt: - @pytest.mark.parametrize( - "geschaeftsobjekt", - [ - Geschaeftsobjekt( - typ=Typ.ENERGIEMENGE, - version="2", - zusatz_attribute=[ - ZusatzAttribut(name="HOCHFREQUENZ_HFSAP_100", wert="12345"), - ZusatzAttribut(name="Schufa-ID", wert="aksdlakoeuhn"), - ], - ), - Geschaeftsobjekt( - typ=Typ.ENERGIEMENGE, - version="2", - zusatz_attribute=[], - ), - ], - ) - def test_serialization_roundtrip(self, geschaeftsobjekt: Geschaeftsobjekt) -> None: - """ - Test de-/serialisation of Geschaeftsobjekt - """ - assert_serialization_roundtrip(geschaeftsobjekt) - - def test_no_list_in_externen_referenzen(self) -> None: - with pytest.raises(ValidationError) as excinfo: - _ = Geschaeftsobjekt( - typ=Typ.ENERGIEMENGE, - zusatz_attribute=ZusatzAttribut(name="Schufa-ID", wert="aksdlakoeuhn"), # type: ignore[arg-type] - ) - # The error message is completely broken, but who cares - assert "2 validation error" in str(excinfo.value) - assert "type=model_type" in str(excinfo.value)