Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions src/bo4e/com/tagesvektor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""
Contains Tagesvektor class and corresponding marshmallow schema for de-/serialization
"""
import datetime
from typing import List

import attr
from marshmallow import fields, post_load

from bo4e.com.com import COM, COMSchema
from bo4e.com.zeitreihenwertkompakt import Zeitreihenwertkompakt, ZeitreihenwertkompaktSchema


# pylint: disable=too-few-public-methods
from bo4e.validators import check_list_length_at_least_one


@attr.s(auto_attribs=True, kw_only=True)
class Tagesvektor(COM):
"""
Abbildung eines Tagesvektors eines beliebigen äquidistanten Zeitrasters
"""

# required attributes
# for the validator see https://github.com/Hochfrequenz/BO4E-python/issues/261
tag: datetime.datetime = attr.ib(validator=attr.validators.instance_of(datetime.datetime))
"""
Der Zeitpunkt ab dem die Werte ermittelt wurden.
Es kann entweder der Beginn des Strom- oder Gastages verwendet werden.
Der Zeitpunkt sollte eindeutig sein, d.h. sowohl Datum+Uhrzeit als auch den UTC-Offset spezifizieren.
"""
# for the validator see also https://github.com/Hochfrequenz/BO4E-python/issues/262
# https://www.attrs.org/en/stable/api.html#attr.validators.deep_iterable
werte: List[Zeitreihenwertkompakt] = attr.ib(
validator=[
attr.validators.deep_iterable(
member_validator=attr.validators.instance_of(Zeitreihenwertkompakt),
iterable_validator=attr.validators.instance_of(list),
),
check_list_length_at_least_one,
]
)
"""
Die Werte am angegebenen Tag;
In Kombination aus Zeitintervall und Tag lassen sich die Zeiten der Werte eindeutig konstruieren.
"""


class TagesvektorSchema(COMSchema):
"""
Schema for de-/serialization of Tagesvektor
"""

# required attributes
tag = fields.DateTime()
werte = fields.List(fields.Nested(ZeitreihenwertkompaktSchema))

# pylint: disable=no-self-use, unused-argument
@post_load
def deserialize(self, data, **kwargs) -> Tagesvektor:
"""Deserialize JSON to Preisstaffel object"""
return Tagesvektor(**data)
56 changes: 56 additions & 0 deletions tests/test_tagesvektor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from datetime import datetime, timezone
from decimal import Decimal

import pytest # type:ignore[import]

from bo4e.com.tagesvektor import Tagesvektor, TagesvektorSchema
from bo4e.com.zeitreihenwertkompakt import Zeitreihenwertkompakt
from tests.serialization_helper import assert_serialization_roundtrip # type:ignore[import]
from tests.test_sigmoidparameter import example_sigmoidparameter # type:ignore[import]


class TestTagesvektor:
@pytest.mark.parametrize(
"tagesvektor, expected_json_dict",
[
pytest.param(
Tagesvektor(
tag=datetime(2021, 12, 15, 5, 0, tzinfo=timezone.utc),
werte=[
Zeitreihenwertkompakt(
wert=Decimal(40),
),
Zeitreihenwertkompakt(
wert=Decimal(50),
),
],
),
{
"tag": "2021-12-15T05:00:00+00:00",
"werte": [
{"wert": "40", "statuszusatz": None, "status": None},
{"wert": "50", "statuszusatz": None, "status": None},
],
},
),
],
)
def test_serialization_roundtrip(self, tagesvektor: Tagesvektor, expected_json_dict: dict):
"""
Test de-/serialisation of Preisstaffel.
"""
assert_serialization_roundtrip(tagesvektor, TagesvektorSchema(), expected_json_dict)

def test_missing_required_attribute(self):
with pytest.raises(TypeError) as excinfo:
_ = Tagesvektor()

assert "missing 2 required" in str(excinfo.value)

def test_list_not_long_enough_attribute(self):
with pytest.raises(ValueError) as excinfo:
_ = Tagesvektor(tag=datetime(2021, 12, 15, 5, 0, tzinfo=timezone.utc), werte=[])

assert "List werte must not be empty" in str(excinfo.value)

# add tests for issues 261 and 262 here