defl/tests/test_dataclass.py
2024-09-11 11:14:03 -04:00

294 lines
7.7 KiB
Python
Executable File

#!/usr/bin/env python3
import defl
from defl import log, cl, Assert
from defl.testing_ import Tester, Test, TestState, testFail
import dataclasses, contextlib
import itertools
import inspect
from typing import *
from types import *
import typing
from defl._typeCheck_ import *
from defl._dataclass_ import *
tester = Tester(name=__file__)
# log.setLevel('debug')
@tester.add()
def isSetup():
unpatchDataClassWithRunTimeValidator()
assert not hasattr(dataclasses, '_process_class_hidden'), dataclasses._process_class_hidden
assert dataclasses._process_class.__name__ == '_process_class'
patchDataClassWithRunTimeValidator()
assert hasattr(dataclasses, '_process_class_hidden')
assert dataclasses._process_class_hidden
assert dataclasses._process_class.__name__ == '_dataclassWrap'
unpatchDataClassWithRunTimeValidator()
assert not hasattr(dataclasses, '_process_class_hidden')
assert dataclasses._process_class.__name__ == '_process_class'
@tester.add()
def test():
patchDataClassWithRunTimeValidator()
# == validated after __post_init__
@dataclasses.dataclass(slots=True, kw_only=True, frozen=False)
class Test:
a: list
def __post_init__(_) -> None:
if _.a is None:
_.a = []
Test(a=None)
Test(a=[])
with testFail(expt=ObjectTypeValidationError):
Test(a=1)
@tester.add()
def test():
patchDataClassWithRunTimeValidator()
# == unions
@dataclasses.dataclass(slots=True, kw_only=True, frozen=False)
class Test:
a: list | dict
Test(a=[])
Test(a={})
with testFail(expt=ObjectTypeValidationError):
Test(a=1)
@tester.add()
def test():
patchDataClassWithRunTimeValidator()
# == genericAlias
def genericAliasTests():
Test(a=[])
Test(a=[{}, {}])
Test(a=[{}, {'t': 1, 't': 2}])
with testFail(expt=ObjectTypeValidationError):
Test(a={})
with testFail(expt=ObjectTypeValidationError):
Test(a=[{}, {}, 1])
with testFail(expt=ObjectTypeValidationError):
Test(a=[{}, {'t': 1, 't': 2, 't': 'fail'}])
with testFail(expt=ObjectTypeValidationError):
Test(a=[None])
@dataclasses.dataclass(slots=True, kw_only=True, frozen=False)
class Test:
a: list[dict[str, int]]
genericAliasTests()
@dataclasses.dataclass(slots=True, kw_only=True, frozen=False)
class Test:
a: List[Dict[str, int]]
genericAliasTests()
@tester.add()
def test():
patchDataClassWithRunTimeValidator()
# unpatchDataClassWithRunTimeValidator()
# print(dataclasses._process_class_hidden)
# == custom class
@dataclasses.dataclass(slots=True, kw_only=True, frozen=False)
class A:
a: int
def __hash__(_) -> None:
return _.a
class Tup(tuple):
...
tuple([1, 2, 3])
Tup([1, 2, 3])
@dataclasses.dataclass(slots=True, kw_only=True, frozen=False)
class B:
b: list[dict[A, Tup[Dict[int | str, int | str | A]]]]
# _TYPECHECK_Debug: bool = True
B(b=[{A(a=1): Tup([{1: 't'}, {'t': 1}, {'t': A(a=2)}])}])
B(b=[{A(a=1): Tup([])}])
B(b=[{}])
B(b=[])
with testFail(expt=ObjectTypeValidationError):
B(b=None)
with testFail(expt=ObjectTypeValidationError):
B(b=[{A(a=1): Tup([{'t': B(b=2)}])}])
@tester.add()
def test():
assert typeMap(1, mp={int: True}) is True
assert typeMap(1, mp={}, default=True) is True
assert typeMap([1], mp={list[int]: True}) is True
assert typeMap([None, 1], mp={list[int | None]: True}) is True
assert typeMap([None, 1], mp={list: True}) is True
with testFail(expt=ValueError):
typeMap(None, mp={int: True})
with testFail(expt=ValueError):
typeMap([None], mp={list[int]: True})
@tester.add()
def test():
return True if 'OOO is trash' else False
#| class hierarchy is trash
@dataclass(slots=True, kw_only=True, frozen=False)
class A:
a: list = field(default_factory=list, kw_only=True)
def __post_init__(_):
_.a.append(1)
a = A()
Assert(a.a) == [1]
@dataclass(slots=True, kw_only=True, frozen=False)
class B(A):
b: list = field(default_factory=list, kw_only=True)
def __post_init__(_):
sup = inspect.getmro(type(_))
print(sup)
sup[1].__post_init__(_)
_.a.append(2)
b = B()
Assert(b.a) == [1, 2]
@dataclass(slots=True, kw_only=True, frozen=False)
class C(B):
c: list = field(default_factory=list, kw_only=True)
def __post_init__(_):
type(_).__bases__
# sup = inspect.getmro(type(_))
# print(sup)
# sup[1].__post_init__(_)
# _.a.append(3)
c = C()
Assert(c.a) == [1, 2, 3]
@tester.add()
def test():
@dataclass(slots=True, kw_only=True, frozen=False)
class A:
base: list = field(default_factory=list, kw_only=True)
@dataclass(slots=True, kw_only=True, frozen=False)
class B:
a: A = field(default_factory=A, kw_only=True)
@dataclass(slots=True, kw_only=True, frozen=False)
class C:
myLongField: B = field(default_factory=B, kw_only=True)
@property
def b(_) -> B:
return _.myLongField
c = C()
Assert(c.b.a.base) == []
@tester.add()
def test():
patchDataClassWithRunTimeValidator()
#/ ---------------------------------------------------------------
@dataclasses.dataclass(slots=True, kw_only=True, frozen=False)
class Test:
a: ClassVar = 1
test = Test()
#/ ---------------------------------------------------------------
@dataclasses.dataclass(slots=True, kw_only=True, frozen=False)
class Test:
a: ClassVar[str] = 1
try:
test = Test()
raise ValueError()
except ObjectTypeValidationError:
...
#/ ---------------------------------------------------------------
@dataclasses.dataclass(slots=True, kw_only=True, frozen=False)
class Test:
_TYPECHECK_Debug: ClassVar[int] = 1
test = Test()
#/ ---------------------------------------------------------------
@dataclasses.dataclass(slots=True, kw_only=True, frozen=False)
class Test:
a: ClassVar[dict[int, int] | list[int]] = {1: 2, 3: 4}
b: ClassVar[dict[int] | list[int]] = [1, 2, 3]
test = Test()
@tester.add()
def factory():
# https://www.geeksforgeeks.org/class-factories-a-powerful-pattern-in-python/
# https://www.geeksforgeeks.org/python-class-members/
C = dataclasses.make_dataclass(
'C', [('x', int), 'y', ('z', int, field(default=5))], namespace={'add_one': lambda self: self.x + 1}
)
@dataclass(slots=T, kw_only=T, frozen=F)
class A:
a: str = field(kw_only=T, repr=T)
print(type(A.a), A.a)
f = {'a': 1, 'b': 2}
C = dataclasses.make_dataclass('C', [(x, int) for x in f.keys()])
c = C(**f)
Assert(c.a) == 1
Assert(c.b) == 2
try:
f = {'fail': "not an int"}
C = dataclasses.make_dataclass('C', [(x, int) for x in f.keys()])
c = C(**f)
raise ValueError()
except ObjectTypeValidationError:
...
@tester.add()
def descriptors():
# https://realpython.com/python-descriptors/
class Verbose_attribute():
def __get__(self, obj, type=None) -> object:
print("accessing the attribute to get the value")
return 42
def __set__(self, obj, value) -> None:
print("accessing the attribute to set the value")
raise AttributeError("Cannot change the value")
class Foo():
attribute1 = Verbose_attribute()
my_foo_object = Foo()
x = my_foo_object.attribute1
Assert(x) == 42
log.info(tester.run())
tester.exitWithStatus()