#!/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()