Skip to content

Commit

Permalink
missing generics
Browse files Browse the repository at this point in the history
  • Loading branch information
sanderegg committed Oct 17, 2021
1 parent 713b74a commit d90cc70
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 0 deletions.
62 changes: 62 additions & 0 deletions packages/models-library/src/models_library/generics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from typing import (
Any,
Dict,
Generic,
ItemsView,
Iterator,
KeysView,
Optional,
TypeVar,
ValuesView,
)

from pydantic import validator
from pydantic.generics import GenericModel

DictKey = TypeVar("DictKey")
DictValue = TypeVar("DictValue")


class DictBaseModel(GenericModel, Generic[DictKey, DictValue]):
__root__: Dict[DictKey, DictValue]

def __getitem__(self, k: DictKey) -> DictValue:
return self.__root__.__getitem__(k)

def __setitem__(self, k: DictKey, v: DictValue) -> None:
self.__root__.__setitem__(k, v)

def items(self) -> ItemsView[DictKey, DictValue]:
return self.__root__.items()

def keys(self) -> KeysView[DictKey]:
return self.__root__.keys()

def values(self) -> ValuesView[DictValue]:
return self.__root__.values()

def __iter__(self) -> Iterator[DictKey]:
return self.__root__.__iter__()

def get(self, key: DictKey, default: Optional[DictValue] = None):
return self.__root__.get(key, default)

def __len__(self) -> int:
return self.__root__.__len__()


DataT = TypeVar("DataT")


class DataEnveloped(GenericModel, Generic[DataT]):
data: Optional[DataT]
error: Optional[Any]

@validator("error")
@classmethod
def data_and_error_cannot_be_populated_together(cls, v, values):
if v is not None and values.get("data") is not None:
raise ValueError(
"both data and error cannot contain values at the same time"
)
return v
58 changes: 58 additions & 0 deletions packages/models-library/tests/test_generics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from pathlib import Path
from typing import Any

import pytest
from models_library.generics import DataEnveloped, DictBaseModel


def test_dict_base_model():
some_dict = {
"a key": 123,
"another key": "a string value",
"yet another key": Path("some_path"),
}
some_instance = DictBaseModel[str, Any].parse_obj(some_dict)
assert some_instance

# test some typical dict methods
assert len(some_instance) == 3
for k, k2 in zip(some_dict, some_instance):
assert k == k2

for k, k2 in zip(some_dict.keys(), some_instance.keys()):
assert k == k2

for v, v2 in zip(some_dict.values(), some_instance.values()):
assert v == v2

for i, i2 in zip(some_dict.items(), some_instance.items()):
assert i == i2

assert some_instance.get("a key") == 123
assert some_instance.get("a non existing key") is None

assert some_instance["a key"] == 123
with pytest.raises(KeyError):
some_instance["a non existing key"] # pylint: disable=pointless-statement
some_instance["a new key"] = 23
assert some_instance["a new key"] == 23


def test_data_enveloped():
some_enveloped_string = DataEnveloped[str]()
assert some_enveloped_string
assert not some_enveloped_string.data
assert not some_enveloped_string.error

some_enveloped_float = DataEnveloped[float](data=232.44)
assert some_enveloped_float
assert some_enveloped_float.data == 232.44
assert not some_enveloped_float.error

some_enveloped_bool = DataEnveloped[bool](error="some error happened")
assert some_enveloped_bool
assert not some_enveloped_bool.data
assert some_enveloped_bool.error == "some error happened"

with pytest.raises(ValueError):
DataEnveloped[int](data=213, error="some error message")

0 comments on commit d90cc70

Please sign in to comment.