Repository: bo4e/BO4E-python (language: python)

Issue:
Implement COM Tarifpreis
https://www.bo4e.de/dokumentation/komponenten/com-tarifpreis
requires
- #145 
- #134 


Discussion / hints:

Fix patch:
diff --git a/src/bo4e/com/tarifpreis.py b/src/bo4e/com/tarifpreis.py
new file mode 100644
index 000000000..a6e215ee8
--- /dev/null
+++ b/src/bo4e/com/tarifpreis.py
@@ -0,0 +1,47 @@
+"""
+Contains Tarifpreis class
+and corresponding marshmallow schema for de-/serialization
+"""
+
+from typing import Optional
+
+import attr
+from marshmallow import fields, post_load
+from marshmallow_enum import EnumField  # type:ignore[import]
+
+from bo4e.com.preis import Preis, PreisSchema
+from bo4e.enum.preistyp import Preistyp
+
+
+# pylint: disable=too-few-public-methods
+@attr.s(auto_attribs=True, kw_only=True)
+class Tarifpreis(Preis):
+    """
+    Abbildung eines Tarifpreises mit Preistyp und Beschreibung abgeleitet von COM Preis.
+    """
+
+    # required attributes
+    #:  Angabe des Preistypes (z.B. Grundpreis)
+    preistyp: Preistyp = attr.ib(validator=attr.validators.in_(Preistyp))
+
+    # optional attributes
+    #:  Beschreibung des Preises. Hier können z.B. Preisdetails angegeben sein, beispielsweise "Drehstromzähler".
+    beschreibung: Optional[str] = attr.ib(default=None)
+
+
+class TarifpreisSchema(PreisSchema):
+    """
+    Schema for de-/serialization of Tarifpreis.
+    """
+
+    # required attributes
+    preistyp = EnumField(Preistyp)
+
+    # optional attributes
+    beschreibung = fields.Str(load_default=None)
+
+    # pylint: disable=no-self-use, unused-argument
+    @post_load
+    def deserialize(self, data, **kwargs) -> Tarifpreis:
+        """Deserialize JSON to Tarifpreis object"""
+        return Tarifpreis(**data)
diff --git a/src/bo4e/com/zeitreihenwertkompakt.py b/src/bo4e/com/zeitreihenwertkompakt.py
index 55ba6751f..95fdeee83 100644
--- a/src/bo4e/com/zeitreihenwertkompakt.py
+++ b/src/bo4e/com/zeitreihenwertkompakt.py
@@ -5,7 +5,6 @@
 from decimal import Decimal
 
 import attr
-
 from marshmallow import fields, post_load
 from marshmallow_enum import EnumField  # type:ignore[import]
 


Test patch:
diff --git a/tests/test_tarifpreis.py b/tests/test_tarifpreis.py
new file mode 100644
index 000000000..7e7c838a7
--- /dev/null
+++ b/tests/test_tarifpreis.py
@@ -0,0 +1,77 @@
+from decimal import Decimal
+
+import pytest  # type:ignore[import]
+
+from bo4e.com.tarifpreis import Tarifpreis, TarifpreisSchema
+from bo4e.enum.mengeneinheit import Mengeneinheit
+from bo4e.enum.preisstatus import Preisstatus
+from bo4e.enum.preistyp import Preistyp
+from bo4e.enum.waehrungseinheit import Waehrungseinheit
+
+
+class TestPreis:
+    def test_tarifpreis_only_required(self):
+        """
+        Test de-/serialisation of Tarifpreis (only has required attributes).
+        """
+        tarifpreis = Tarifpreis(
+            wert=Decimal(3.78),
+            einheit=Waehrungseinheit.EUR,
+            bezugswert=Mengeneinheit.KWH,
+            preistyp=Preistyp.ARBEITSPREIS_HT,
+        )
+
+        schema = TarifpreisSchema()
+        json_string = schema.dumps(tarifpreis, ensure_ascii=False)
+
+        assert "ARBEITSPREIS_HT" in json_string
+        assert "null" in json_string
+
+        tarifpreis_deserialized = schema.loads(json_string)
+
+        assert isinstance(tarifpreis_deserialized.wert, Decimal)
+        assert isinstance(tarifpreis_deserialized.einheit, Waehrungseinheit)
+        assert isinstance(tarifpreis_deserialized.bezugswert, Mengeneinheit)
+        assert isinstance(tarifpreis_deserialized.preistyp, Preistyp)
+        assert tarifpreis_deserialized.beschreibung is None
+        assert tarifpreis == tarifpreis_deserialized
+
+    def test_wrong_datatype(self):
+        with pytest.raises(TypeError) as excinfo:
+            _ = Tarifpreis(
+                wert=3.50, einheit=Waehrungseinheit.EUR, bezugswert=Mengeneinheit.KWH, preistyp=Preistyp.ARBEITSPREIS_HT
+            )
+
+        assert "'wert' must be <class 'decimal.Decimal'>" in str(excinfo.value)
+
+    def test_missing_required_attribute(self):
+        with pytest.raises(TypeError) as excinfo:
+            _ = Tarifpreis(
+                wert=Decimal(3.50),
+                einheit=Waehrungseinheit.EUR,
+                status=Preisstatus.ENDGUELTIG,
+                bezugswert=Mengeneinheit.KWH,
+            )
+
+        assert "missing 1 required" in str(excinfo.value)
+
+    def test_optional_attribute(self):
+        tarifpreis = Tarifpreis(
+            wert=Decimal(3.50),
+            einheit=Waehrungseinheit.EUR,
+            bezugswert=Mengeneinheit.KWH,
+            status=Preisstatus.ENDGUELTIG,
+            preistyp=Preistyp.ARBEITSPREIS_HT,
+            beschreibung="Das ist ein HT Arbeitspreis",
+        )
+
+        schema = TarifpreisSchema()
+        json_string = schema.dumps(tarifpreis, ensure_ascii=False)
+
+        assert "Das ist ein HT Arbeitspreis" in json_string
+
+        tarifpreis_deserialized = schema.loads(json_string)
+
+        assert isinstance(tarifpreis_deserialized.beschreibung, str)
+        assert tarifpreis_deserialized.beschreibung == "Das ist ein HT Arbeitspreis"
+        assert tarifpreis_deserialized == tarifpreis