xn-model 1.0.13__tar.gz → 1.0.15__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {xn_model-1.0.13/xn_model.egg-info → xn_model-1.0.15}/PKG-INFO +1 -1
- xn_model-1.0.15/x_model/models.py +90 -0
- xn_model-1.0.15/x_model/types.py +11 -0
- {xn_model-1.0.13 → xn_model-1.0.15/xn_model.egg-info}/PKG-INFO +1 -1
- xn_model-1.0.13/x_model/models.py +0 -78
- xn_model-1.0.13/x_model/types.py +0 -16
- {xn_model-1.0.13 → xn_model-1.0.15}/.env.sample +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/.gitignore +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/.pre-commit-config.yaml +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/README.md +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/makefile +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/pyproject.toml +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/setup.cfg +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/tests/__init__.py +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/tests/test_db.py +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/x_model/__init__.py +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/x_model/field.py +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/x_model/func.py +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/xn_model.egg-info/SOURCES.txt +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/xn_model.egg-info/dependency_links.txt +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/xn_model.egg-info/requires.txt +0 -0
- {xn_model-1.0.13 → xn_model-1.0.15}/xn_model.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from dataclasses import make_dataclass, field, fields
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Self
|
|
4
|
+
|
|
5
|
+
from pydantic import ConfigDict
|
|
6
|
+
from tortoise import Model as TortModel
|
|
7
|
+
from tortoise.fields import IntField
|
|
8
|
+
|
|
9
|
+
from x_model.field import DatetimeSecField
|
|
10
|
+
from x_model.types import BaseUpd
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TsTrait:
|
|
14
|
+
created_at: datetime | None = DatetimeSecField(auto_now_add=True)
|
|
15
|
+
updated_at: datetime | None = DatetimeSecField(auto_now=True)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Model(TortModel):
|
|
19
|
+
id: int = IntField(True)
|
|
20
|
+
|
|
21
|
+
_in_type: type[BaseUpd] = None # overridable
|
|
22
|
+
_name: tuple[str] = ("name",)
|
|
23
|
+
_sorts: tuple[str] = ("-id",)
|
|
24
|
+
|
|
25
|
+
def __repr__(self, sep: str = " ") -> str:
|
|
26
|
+
return sep.join(getattr(self, name_fragment) for name_fragment in self._name)
|
|
27
|
+
|
|
28
|
+
# @classmethod
|
|
29
|
+
# def out_type(cls) -> type[BaseModel]:
|
|
30
|
+
# if not cls._out_type:
|
|
31
|
+
# cls._out_type = pydantic_model_creator(cls, name=cls.__name__ + "Out")
|
|
32
|
+
# return cls._out_type
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def in_type(cls, with_pk: bool = False) -> type[BaseUpd]:
|
|
36
|
+
if not getattr(cls, cn := "Upd" if with_pk else "New", None):
|
|
37
|
+
fields: list[tuple[str, type] | tuple[str, type, field]] = []
|
|
38
|
+
for fn in cls._meta.db_fields:
|
|
39
|
+
if (f := cls._meta.fields_map[fn]).pk and not with_pk:
|
|
40
|
+
continue
|
|
41
|
+
if getattr(f, "auto_now", None) or getattr(f, "auto_now_add", None):
|
|
42
|
+
continue
|
|
43
|
+
fld = fn, getattr(f, "enum_type", f.field_type)
|
|
44
|
+
if f.default or f.null or (f.allows_generated and not f.pk) or not f.required:
|
|
45
|
+
fld += (field(default_factory=dict) if f.default == {} else field(default=f.default),)
|
|
46
|
+
fields.append(fld)
|
|
47
|
+
# for fn in cls._meta.fk_fields:
|
|
48
|
+
# f = cls._meta.fields_map[fn]
|
|
49
|
+
# fld = fn+"_id", int
|
|
50
|
+
# if f.default or f.allows_generated or f.null or not f.required:
|
|
51
|
+
# fld += (field(default=f.default),)
|
|
52
|
+
# fields.append(fld)
|
|
53
|
+
|
|
54
|
+
dcl = make_dataclass(cls.__name__ + cn, fields, bases=(BaseUpd,), kw_only=True)
|
|
55
|
+
dcl._unq = set((cls._meta.unique_together or ((),))[0])
|
|
56
|
+
if with_pk:
|
|
57
|
+
dcl._unq |= {"id"}
|
|
58
|
+
setattr(cls, cn, dcl)
|
|
59
|
+
|
|
60
|
+
return getattr(cls, cn)
|
|
61
|
+
|
|
62
|
+
# # # CRUD Methods # # #
|
|
63
|
+
@classmethod
|
|
64
|
+
def validate(cls, dct: dict, with_pk: bool = None) -> BaseUpd:
|
|
65
|
+
dcl = cls.in_type("id" in dct if with_pk is None else with_pk)
|
|
66
|
+
field_names = [n.name for n in fields(dcl)]
|
|
67
|
+
return dcl(**{k: v for k, v in dct.items() if k in field_names})
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
async def get_or_create_by_name(cls, name: str, attr_name: str = None, def_dict: dict = None) -> Self:
|
|
71
|
+
attr_name = attr_name or list(cls._name)[0]
|
|
72
|
+
if not (obj := await cls.get_or_none(**{attr_name: name})):
|
|
73
|
+
next_id = (await cls.all().order_by("-id").first()).id + 1
|
|
74
|
+
obj = await cls.create(id=next_id, **{attr_name: name}, **(def_dict or {}))
|
|
75
|
+
return obj
|
|
76
|
+
|
|
77
|
+
class PydanticMeta:
|
|
78
|
+
model_config = ConfigDict(use_enum_values=True)
|
|
79
|
+
# include: tuple[str, ...] = ()
|
|
80
|
+
# exclude: tuple[str, ...] = ("Meta",)
|
|
81
|
+
# computed: tuple[str, ...] = ()
|
|
82
|
+
backward_relations: bool = False # True
|
|
83
|
+
max_recursion: int = 1 # default: 3
|
|
84
|
+
# allow_cycles: bool = False
|
|
85
|
+
# exclude_raw_fields: bool = False # True
|
|
86
|
+
# sort_alphabetically: bool = False
|
|
87
|
+
# model_config: ConfigDict | None = None
|
|
88
|
+
|
|
89
|
+
class Meta:
|
|
90
|
+
abstract = True
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from dataclasses import dataclass, asdict
|
|
2
|
+
from typing import ClassVar
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class BaseUpd:
|
|
7
|
+
_unq: ClassVar[set[str]]
|
|
8
|
+
|
|
9
|
+
def df_unq(self) -> dict:
|
|
10
|
+
d = {k: v for k, v in asdict(self).items() if v is not None or k in self._unq}
|
|
11
|
+
return {**{k: d.pop(k, None) for k in self._unq}, "defaults": d}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from typing import Self
|
|
3
|
-
|
|
4
|
-
from pydantic import ConfigDict, BaseModel
|
|
5
|
-
from tortoise import Model as TortModel
|
|
6
|
-
from tortoise.contrib.pydantic import pydantic_model_creator, PydanticModel
|
|
7
|
-
from tortoise.fields import IntField
|
|
8
|
-
|
|
9
|
-
from x_model.field import DatetimeSecField
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class TsTrait:
|
|
13
|
-
created_at: datetime | None = DatetimeSecField(auto_now_add=True)
|
|
14
|
-
updated_at: datetime | None = DatetimeSecField(auto_now=True)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class Model(TortModel):
|
|
18
|
-
id: int = IntField(True)
|
|
19
|
-
|
|
20
|
-
_out_type: type[BaseModel] = None # overridable
|
|
21
|
-
_in_type: type[BaseModel] = None # overridable
|
|
22
|
-
_name: tuple[str] = ("name",)
|
|
23
|
-
_sorts: tuple[str] = ("-id",)
|
|
24
|
-
|
|
25
|
-
def __repr__(self, sep: str = " ") -> str:
|
|
26
|
-
return sep.join(getattr(self, name_fragment) for name_fragment in self._name)
|
|
27
|
-
|
|
28
|
-
@classmethod
|
|
29
|
-
def out_type(cls):
|
|
30
|
-
if not cls._out_type:
|
|
31
|
-
cls._out_type = pydantic_model_creator(cls, name=cls.__name__ + "Out")
|
|
32
|
-
return cls._out_type
|
|
33
|
-
|
|
34
|
-
@classmethod
|
|
35
|
-
def in_type(cls):
|
|
36
|
-
if not cls._in_type:
|
|
37
|
-
cls._in_type = pydantic_model_creator(
|
|
38
|
-
cls, name=cls.__name__ + "In", exclude_readonly=True, meta_override=cls.PydanticMetaIn
|
|
39
|
-
)
|
|
40
|
-
return cls._in_type
|
|
41
|
-
|
|
42
|
-
# # # CRUD Methods # # #
|
|
43
|
-
@classmethod
|
|
44
|
-
async def get_one(cls, id_: int) -> PydanticModel:
|
|
45
|
-
if obj := await cls.get_or_none(id=id_):
|
|
46
|
-
return await cls.out_type().from_tortoise_orm(obj)
|
|
47
|
-
raise LookupError(f"{cls.__name__}#{id_} not found")
|
|
48
|
-
|
|
49
|
-
async def one(self) -> PydanticModel:
|
|
50
|
-
return await self.out_type().from_tortoise_orm(self)
|
|
51
|
-
|
|
52
|
-
@classmethod
|
|
53
|
-
async def get_or_create_by_name(cls, name: str, attr_name: str = None, def_dict: dict = None) -> Self:
|
|
54
|
-
attr_name = attr_name or list(cls._name)[0]
|
|
55
|
-
if not (obj := await cls.get_or_none(**{attr_name: name})):
|
|
56
|
-
next_id = (await cls.all().order_by("-id").first()).id + 1
|
|
57
|
-
obj = await cls.create(id=next_id, **{attr_name: name}, **(def_dict or {}))
|
|
58
|
-
return obj
|
|
59
|
-
|
|
60
|
-
class PydanticMeta:
|
|
61
|
-
model_config = ConfigDict(use_enum_values=True)
|
|
62
|
-
# include: tuple[str, ...] = ()
|
|
63
|
-
# exclude: tuple[str, ...] = ("Meta",)
|
|
64
|
-
# computed: tuple[str, ...] = ()
|
|
65
|
-
# backward_relations: bool = True
|
|
66
|
-
max_recursion: int = 1 # default: 3
|
|
67
|
-
# allow_cycles: bool = False
|
|
68
|
-
# exclude_raw_fields: bool = True
|
|
69
|
-
# sort_alphabetically: bool = False
|
|
70
|
-
# model_config: ConfigDict | None = None
|
|
71
|
-
|
|
72
|
-
class PydanticMetaIn:
|
|
73
|
-
backward_relations: bool = False
|
|
74
|
-
max_recursion: int = 0
|
|
75
|
-
exclude_raw_fields: bool = False
|
|
76
|
-
|
|
77
|
-
class Meta:
|
|
78
|
-
abstract = True
|
xn_model-1.0.13/x_model/types.py
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
from typing import ClassVar
|
|
2
|
-
from pydantic import BaseModel
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class New(BaseModel):
|
|
6
|
-
_unq: ClassVar[tuple[str]] = ()
|
|
7
|
-
|
|
8
|
-
def df_unq(self) -> dict:
|
|
9
|
-
d = {k: v for k, v in self.model_dump(exclude_none=True).items()}
|
|
10
|
-
return {**{k: d.pop(k, None) for k in set(self._unq)}, "defaults": d}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class Upd(New):
|
|
14
|
-
_unq = ("id",)
|
|
15
|
-
|
|
16
|
-
id: int
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|