-
Notifications
You must be signed in to change notification settings - Fork 5
Implement BO Lastgang + BO LastgangKompakt #295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
cbb92ec
242476a
f425521
889cda9
acfca9e
b8ff18c
32ffc6c
dba05e2
5e84b08
3d8a3ef
07db897
245bc8d
5315657
8280818
4aec663
60bcff4
9674dcd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,131 @@ | ||||||
| """ | ||||||
| Contains Lastgang and LastgangKompakt class | ||||||
| and corresponding marshmallow schema for de-/serialization | ||||||
| """ | ||||||
| from typing import List, Optional | ||||||
|
|
||||||
| import attr | ||||||
| from marshmallow import fields | ||||||
| from marshmallow_enum import EnumField # type:ignore[import] | ||||||
|
|
||||||
| from bo4e.bo.geschaeftsobjekt import Geschaeftsobjekt, GeschaeftsobjektSchema | ||||||
| from bo4e.com.tagesvektor import Tagesvektor, TagesvektorSchema | ||||||
| from bo4e.com.zeitintervall import Zeitintervall, ZeitintervallSchema | ||||||
| from bo4e.com.zeitreihenwert import Zeitreihenwert, ZeitreihenwertSchema | ||||||
| from bo4e.enum.botyp import BoTyp | ||||||
| from bo4e.enum.lokationstyp import Lokationstyp | ||||||
| from bo4e.enum.mengeneinheit import Mengeneinheit | ||||||
| from bo4e.enum.sparte import Sparte | ||||||
| from bo4e.validators import check_list_length_at_least_one, obis_validator | ||||||
|
|
||||||
|
|
||||||
| # pylint: disable=too-few-public-methods | ||||||
| @attr.s(auto_attribs=True, kw_only=True) | ||||||
| class _LastgangBody: | ||||||
| """ | ||||||
| The LastgangBody is a mixin that contains the "body" of a Lastgang that is used in both the :class:`Lastgang` as | ||||||
| well as :class:`LastgangKompakt`. | ||||||
| """ | ||||||
|
|
||||||
| #: Angabe, ob es sich um einen Gas- oder Stromlastgang handelt | ||||||
| sparte: Sparte = attr.ib(validator=attr.validators.instance_of(Sparte)) | ||||||
|
|
||||||
| #: Eindeutige Nummer der Marktlokation bzw der Messlokation, zu der der Lastgang gehört | ||||||
| lokations_id: str = attr.ib(validator=attr.validators.instance_of(str)) | ||||||
|
|
||||||
| #: Marktlokation oder Messlokation | ||||||
| lokationstyp: str = attr.ib(validator=attr.validators.instance_of(Lokationstyp)) | ||||||
| # todo: implement a lokations-id + lokationstyp cross check (such that lokationstyp malo checks for valid malo id) | ||||||
| # https://github.com/Hochfrequenz/BO4E-python/issues/321 | ||||||
|
|
||||||
| #: Definition der gemessenen Größe anhand ihrer Einheit | ||||||
| messgroesse: Mengeneinheit = attr.ib(validator=attr.validators.instance_of(Mengeneinheit)) | ||||||
|
|
||||||
| # optional attributes | ||||||
| #: Versionsnummer des Lastgangs | ||||||
| version: Optional[str] = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of(str))) | ||||||
| #: Die OBIS-Kennzahl für den Wert, die festlegt, welche Größe mit dem Stand gemeldet wird, z.B. '1-0:1.8.1' | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Woher kommt denn dieser Docstring? :D
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. das hatte ich glaube ich aus dem anderen lastgang kopiert.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hab ich extra geschaut, das ist bei beiden Lastgängen der Kommentar. Aber vllt. einfach von woanders wo eine OBIS-Kennzahl genutzt wird. |
||||||
| obis_kennzahl: Optional[str] = attr.ib(default=None, validator=attr.validators.optional(obis_validator)) | ||||||
|
|
||||||
|
|
||||||
| # pylint: disable=too-many-instance-attributes, too-few-public-methods | ||||||
| @attr.s(auto_attribs=True, kw_only=True) | ||||||
| class LastgangKompakt(Geschaeftsobjekt, _LastgangBody): | ||||||
| """ | ||||||
| Modell zur Abbildung eines kompakten Lastganges. | ||||||
| In diesem Modell werden die Messwerte in Form von Tagesvektoren mit fester Anzahl von Werten übertragen. | ||||||
| Daher ist dieses BO nur zur Übertragung von äquidistanten Messwertverläufen geeignet. | ||||||
| """ | ||||||
|
|
||||||
| # required attributes | ||||||
| bo_typ: BoTyp = attr.ib(default=BoTyp.LASTGANG_KOMPAKT) | ||||||
|
|
||||||
| #: Angabe des Rasters innerhalb aller Tagesvektoren dieses Lastgangs | ||||||
| zeitintervall: Zeitintervall = attr.ib(validator=attr.validators.instance_of(Zeitintervall)) | ||||||
| # todo: implement a cross check that this zeitintervall is actually the one used in tagesvektoren | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ticket? ;)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||
| # https://github.com/Hochfrequenz/BO4E-python/issues/322 | ||||||
|
|
||||||
| #: Die im Lastgang enthaltenen Messwerte in Form von Tagesvektoren | ||||||
| tagesvektoren: List[Tagesvektor] = attr.ib( | ||||||
| validator=attr.validators.deep_iterable( | ||||||
| member_validator=attr.validators.instance_of(Tagesvektor), | ||||||
| iterable_validator=attr.validators.instance_of(list), | ||||||
| ) | ||||||
| ) | ||||||
|
|
||||||
|
|
||||||
| # pylint: disable=too-many-instance-attributes, too-few-public-methods | ||||||
| @attr.s(auto_attribs=True, kw_only=True) | ||||||
| class Lastgang(Geschaeftsobjekt, _LastgangBody): | ||||||
| """ | ||||||
| Modell zur Abbildung eines Lastganges; | ||||||
| In diesem Modell werden die Messwerte mit einem vollständigen Zeitintervall angegeben und es bietet daher eine hohe | ||||||
| Flexibilität in der Übertragung jeglicher zeitlich veränderlicher Messgrössen. | ||||||
| """ | ||||||
|
|
||||||
| # required attributes | ||||||
| bo_typ: BoTyp = attr.ib(default=BoTyp.LASTGANG) | ||||||
|
|
||||||
| #: Die im Lastgang enthaltenen Messwerte | ||||||
| werte: List[Zeitreihenwert] = attr.ib( | ||||||
| validator=attr.validators.deep_iterable( | ||||||
| member_validator=attr.validators.instance_of(Zeitreihenwert), | ||||||
| iterable_validator=check_list_length_at_least_one, | ||||||
| ) | ||||||
| ) | ||||||
|
|
||||||
|
|
||||||
| class _LastgangBodySchemaMixin: | ||||||
| """ | ||||||
| A mixin for schemas to deserialize Lastgang and LastgangKompakt objects. | ||||||
| """ | ||||||
|
|
||||||
| sparte = EnumField(Sparte) | ||||||
| lokations_id = fields.Str() | ||||||
| lokationstyp = EnumField(Lokationstyp) | ||||||
| messgroesse = EnumField(Mengeneinheit) | ||||||
|
|
||||||
| # optional attributes | ||||||
| obis_kennzahl = fields.Str(load_default=None) | ||||||
| version = fields.Str(allow_none=True) | ||||||
|
|
||||||
|
|
||||||
| class LastgangKompaktSchema(GeschaeftsobjektSchema, _LastgangBodySchemaMixin): | ||||||
| """ | ||||||
| Schema for de-/serialization of LastgangKompakt | ||||||
| """ | ||||||
|
|
||||||
| class_name = LastgangKompakt | ||||||
| # required attributes | ||||||
| zeitintervall = fields.Nested(ZeitintervallSchema) | ||||||
| tagesvektoren = fields.List(fields.Nested(TagesvektorSchema)) | ||||||
|
|
||||||
|
|
||||||
| class LastgangSchema(GeschaeftsobjektSchema, _LastgangBodySchemaMixin): | ||||||
| """ | ||||||
| Schema for de-/serialization of Lastgang | ||||||
| """ | ||||||
|
|
||||||
| class_name = Lastgang | ||||||
| # required attributes | ||||||
| werte = fields.List(fields.Nested(ZeitreihenwertSchema)) | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import pytest # type:ignore[import] | ||
|
|
||
| from bo4e.bo.lastgang import Lastgang, LastgangSchema | ||
| from bo4e.enum.lokationstyp import Lokationstyp | ||
| from bo4e.enum.mengeneinheit import Mengeneinheit | ||
| from bo4e.enum.sparte import Sparte | ||
| from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import] | ||
| from tests.test_zeitreihenwert import example_zeitreihenwert # type:ignore[import] | ||
|
|
||
|
|
||
| class TestLastgang: | ||
| @pytest.mark.parametrize( | ||
| "lastgang_kompakt", | ||
| [ | ||
| pytest.param( | ||
| Lastgang( | ||
| version="1.1", | ||
| sparte=Sparte.STROM, | ||
| lokations_id="DE0000011111222223333344444555556", | ||
| obis_kennzahl="1-0:1.8.1", | ||
| lokationstyp=Lokationstyp.MELO, | ||
| messgroesse=Mengeneinheit.KWH, | ||
| werte=[example_zeitreihenwert], | ||
| ), | ||
| ), | ||
| ], | ||
| ) | ||
| def test_serialization_roundtrip(self, lastgang_kompakt: Lastgang): | ||
| """ | ||
| Test de-/serialisation | ||
| """ | ||
| assert_serialization_roundtrip(lastgang_kompakt, LastgangSchema()) | ||
|
|
||
| def test_missing_required_attribute(self): | ||
| with pytest.raises(TypeError) as excinfo: | ||
| _ = Lastgang() | ||
|
|
||
| assert "missing 5 required" in str(excinfo.value) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| import pytest # type:ignore[import] | ||
|
|
||
| from bo4e.bo.lastgang import LastgangKompakt, LastgangKompaktSchema | ||
| from bo4e.com.zeitintervall import Zeitintervall | ||
| from bo4e.enum.lokationstyp import Lokationstyp | ||
| from bo4e.enum.mengeneinheit import Mengeneinheit | ||
| from bo4e.enum.sparte import Sparte | ||
| from bo4e.enum.zeiteinheit import Zeiteinheit | ||
| from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import] | ||
| from tests.test_tagesvektor import example_tagesvektor, example_tagesvektor_json # type:ignore[import] | ||
|
|
||
|
|
||
| class TestLastgangKompakt: | ||
| @pytest.mark.parametrize( | ||
| "lastgang_kompakt, expected_json_dict", | ||
| [ | ||
| pytest.param( | ||
| LastgangKompakt( | ||
| version="1.1", | ||
| sparte=Sparte.STROM, | ||
| lokations_id="DE0000011111222223333344444555556", | ||
| obis_kennzahl="1-0:1.8.1", | ||
| lokationstyp=Lokationstyp.MELO, | ||
| messgroesse=Mengeneinheit.KWH, | ||
| zeitintervall=Zeitintervall( | ||
| wert=1, | ||
| zeiteinheit=Zeiteinheit.VIERTEL_STUNDE, | ||
| ), | ||
| tagesvektoren=[example_tagesvektor], | ||
| ), | ||
| { | ||
| "version": "1.1", | ||
| "sparte": "STROM", | ||
| "lokationstyp": "MELO", | ||
| "messgroesse": "KWH", | ||
| "zeitintervall": {"zeiteinheit": "VIERTEL_STUNDE", "wert": 1}, | ||
| "tagesvektoren": [example_tagesvektor_json], | ||
| "versionstruktur": "2", | ||
| "externeReferenzen": [], | ||
| "lokationsId": "DE0000011111222223333344444555556", | ||
| "boTyp": "LASTGANG_KOMPAKT", | ||
| "obisKennzahl": "1-0:1.8.1", | ||
| }, | ||
| ), | ||
| ], | ||
| ) | ||
| def test_serialization_roundtrip(self, lastgang_kompakt: LastgangKompakt, expected_json_dict: dict): | ||
| """ | ||
| Test de-/serialisation of LastgangKompakt. | ||
| """ | ||
| assert_serialization_roundtrip(lastgang_kompakt, LastgangKompaktSchema(), expected_json_dict) | ||
|
|
||
| def test_missing_required_attribute(self): | ||
| with pytest.raises(TypeError) as excinfo: | ||
| _ = LastgangKompakt() | ||
|
|
||
| assert "missing 6 required" in str(excinfo.value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gibt es dafür schon ein Issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#321
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
9674dcd