defl/tests.old/test_pydantic.py

201 lines
4.0 KiB
Python
Raw Permalink Normal View History

2025-03-09 09:17:53 -04:00
#!/usr/bin/env python
from dataclasses import dataclass, field
from collections import Counter
import sys, re, os, enum, itertools
from functools import partial, partialmethod
from time import sleep
from subprocess import Popen, PIPE, DEVNULL
from operator import itemgetter
from defl import (
log,
cl,
Dath,
Undefined,
Null,
Assert,
Time,
Obj,
IterableType,
isIterableType,
Run,
checkType,
richReprAuto,
quoteSh,
CliError,
)
from defl._typing_ import *
from defl._typing_ import T, F, N, U
from defl._rich_ import *
from defl._pydantic_ import *
import defl
from defl.testing_ import Tester, testFail
from datetime import datetime
defl.log.setLevel('i')
tester = Tester(name=__file__)
@tester.add()
def test():
from pydantic import BaseModel, PositiveInt
from pydantic.dataclasses import dataclass as danticlass, Field as DantiField
from pydantic import Field, TypeAdapter
class User(BaseModel):
idd: int
name: str = 'John Doe'
signup_ts: datetime | None
tastes: dict[str, PositiveInt]
external_data = {
'idd': 123,
'signup_ts': '2019-06-01 12:22',
'tastes': {
'wine': 9,
b'cheese': 7,
'cabbage': '1',
},
}
user = User(**external_data)
print(user.idd)
print(user.model_dump())
@tester.add()
def test():
from pydantic import BaseModel, PositiveInt
from pydantic.dataclasses import dataclass as danticlass, Field as DantiField
from pydantic import Field, TypeAdapter
from typing_extensions import Self
@danticlass(slots=T, kw_only=T)
class A:
y: list = DantiField([]) # | okay for pydantic. it'll copy
z: float
na: float | N = N
Count: ClassVar[int] = 0
def __post_init__(_: Self) -> N:
_.y.append(A.Count)
A.Count += 1
a1 = A(z=2)
a2 = A(z=2.1)
print(a1)
print(a2)
assert id(a1.y) != id(a2.y)
assert a1.y != a2.y
print(TypeAdapter(A).json_schema())
print(TypeAdapter(A).dump_json(a1))
print(TypeAdapter(A).dump_python(a1))
@tester.add()
def test():
@dantDC()
class A:
y: list[int] = DantField([]) # | okay for pydantic. it'll copy
z: float
na: float | N = N
Count: ClassVar[int] = 0
def __post_init__(_) -> N:
_.y.append(A.Count)
A.Count += 1
a1 = A(z=2)
a2 = A(z=2.1)
print(a1)
print(a2)
assert id(a1.y) != id(a2.y)
assert a1.y != a2.y
with testFail(DantValidationError):
a1.y = 1
with testFail(DantValidationError):
a1.y = ['a']
a1.y = [3]
print(DantTypeAdapter(A).json_schema())
print(DantTypeAdapter(A).dump_json(a1))
print(DantTypeAdapter(A).dump_python(a1))
assert not hasattr(a1, '__dict__')
assert hasattr(a1, '__slots__')
@tester.add()
def test():
@dantClass()
class A:
y: list[tuple[list[dict[float, str]]]] = DantField(kw_only=F)
a1 = A([[[{1: b'cat'}]]])
with testFail(DantValidationError):
a1 = A([[[{'x': b'cat'}]]])
@tester.add()
def test():
@dantClass()
class A:
y: int
@dantClass()
class B:
y: list[A]
a1 = B(y=[A(y=1), A(y=2)])
print(a1)
@tester.add()
def test():
@dantCall
def cat(a: int, b: list[float], c: str) -> tuple[int, list[float], str]:
return (a, b, c)
r = cat(a=1, b=[1], c='cat')
print(r)
with testFail(DantValidationError):
cat(a=1, b=[1], c=1)
@dantCall
def cat() -> float:
return 1
r = cat()
print(r)
@dantCall
def cat() -> str:
return 1.1
with testFail(DantValidationError):
cat()
@tester.add()
def test():
from pydantic import ConfigDict
from pydantic.dataclasses import dataclass
class MyClass:
pass
@dataclass(config=ConfigDict(arbitrary_types_allowed=True))
class MyPydanticDataclass:
a: MyClass
log.info(tester.run())
tester.exitWithStatus()