Skip to content

Commit

Permalink
Use literal type instead of enum type for _typ (#905)
Browse files Browse the repository at this point in the history
* Use literal type instead of enum type for `_typ`

* 🔥

* 🩹mypy

* 🩹pylint

* 🩹coverage

* 🩹tests

* 🩹docs

* 🩹pylint
  • Loading branch information
lord-haffi authored Oct 10, 2024
1 parent c4c6d12 commit b29fc2e
Show file tree
Hide file tree
Showing 39 changed files with 111 additions and 129 deletions.
1 change: 1 addition & 0 deletions docs/compatibility/change_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
39 changes: 28 additions & 11 deletions docs/compatibility/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

import itertools
import logging
import re
from pathlib import Path
from typing import Iterable, Sequence
Expand All @@ -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+)?")


Expand All @@ -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__}"
Expand Down Expand Up @@ -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.
Expand All @@ -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)}#",
)


Expand All @@ -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(
Expand Down
4 changes: 2 additions & 2 deletions src/bo4e/bo/angebot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/bo4e/bo/ausschreibung.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/bo4e/bo/buendelvertrag.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/bo4e/bo/energiemenge.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/bo4e/bo/fremdkosten.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/bo4e/bo/geraet.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
6 changes: 1 addition & 5 deletions src/bo4e/bo/geschaeftsobjekt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/bo4e/bo/geschaeftspartner.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/bo4e/bo/kosten.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions src/bo4e/bo/lastgang.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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"]
4 changes: 2 additions & 2 deletions src/bo4e/bo/lokationszuordnung.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -33,7 +33,7 @@ class Lokationszuordnung(Geschaeftsobjekt):
`Lokationszuordnung JSON Schema <https://json-schema.app/view/%23?url=https://raw.githubusercontent.com/BO4E/BO4E-Schemas/{__gh_version__}/src/bo4e_schemas/bo/Lokationszuordnung.json>`_
"""

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
Expand Down
4 changes: 2 additions & 2 deletions src/bo4e/bo/marktlokation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/bo4e/bo/marktteilnehmer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/bo4e/bo/messlokation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/bo4e/bo/netzlokation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit b29fc2e

Please sign in to comment.