python-plugins 1.0.3__py3-none-any.whl → 1.0.4__py3-none-any.whl
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.
- python_plugins/__about__.py +1 -1
- python_plugins/examples/sphinx_google_style.py +311 -0
- python_plugins/examples/sphinx_numpy_style.py +351 -0
- python_plugins/ospath/walk.py +31 -0
- python_plugins/sqla/db.py +3 -2
- python_plugins/sqla/utils/__init__.py +1 -1
- python_plugins/sqla/utils/attr.py +27 -52
- python_plugins/sqla/utils/paginate.py +74 -0
- {python_plugins-1.0.3.dist-info → python_plugins-1.0.4.dist-info}/METADATA +1 -1
- {python_plugins-1.0.3.dist-info → python_plugins-1.0.4.dist-info}/RECORD +13 -18
- {python_plugins-1.0.3.dist-info → python_plugins-1.0.4.dist-info}/WHEEL +1 -1
- python_plugins/ospath/walk_remove.py +0 -19
- python_plugins/sqla/models/association_proxy.py +0 -48
- python_plugins/sqla/models/demo.py +0 -114
- python_plugins/sqla/models/message.py +0 -19
- python_plugins/sqla/models/model1.py +0 -161
- python_plugins/sqla/models/multpk.py +0 -16
- python_plugins/sqla/models/polymorphic.py +0 -35
- python_plugins/sqla/models/relations.py +0 -74
- python_plugins/sqla/models/tree_node.py +0 -17
- /python_plugins/{sqla/models → examples}/__init__.py +0 -0
- {python_plugins-1.0.3.dist-info → python_plugins-1.0.4.dist-info}/licenses/LICENSE.rst +0 -0
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
from typing import Tuple, List
|
|
2
|
+
from sqlalchemy import inspect
|
|
2
3
|
from sqlalchemy.orm import ColumnProperty
|
|
3
4
|
from sqlalchemy.orm import RelationshipProperty
|
|
4
5
|
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
|
5
6
|
from sqlalchemy.ext.hybrid import hybrid_property
|
|
6
7
|
from sqlalchemy.ext.associationproxy import AssociationProxy
|
|
7
8
|
|
|
9
|
+
|
|
8
10
|
def is_instrumented_attribute(attr):
|
|
9
11
|
return isinstance(attr, InstrumentedAttribute)
|
|
10
12
|
|
|
@@ -17,94 +19,67 @@ def is_relationship(attr):
|
|
|
17
19
|
return hasattr(attr, "property") and isinstance(attr.property, RelationshipProperty)
|
|
18
20
|
|
|
19
21
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
+
def is_hybrid_property(model, attr_name):
|
|
23
|
+
mapper = inspect(model)
|
|
24
|
+
descriptor = mapper.all_orm_descriptors.get(attr_name)
|
|
25
|
+
return isinstance(descriptor, hybrid_property)
|
|
26
|
+
|
|
22
27
|
|
|
23
|
-
def is_association_proxy(
|
|
24
|
-
|
|
28
|
+
def is_association_proxy(model, attr_name):
|
|
29
|
+
mapper = inspect(model)
|
|
30
|
+
descriptor = mapper.all_orm_descriptors.get(attr_name)
|
|
31
|
+
return isinstance(descriptor, AssociationProxy)
|
|
25
32
|
|
|
26
33
|
|
|
27
34
|
def get_field_with_path(
|
|
28
|
-
model,
|
|
35
|
+
model, name: str
|
|
29
36
|
) -> Tuple[InstrumentedAttribute, List[InstrumentedAttribute]]:
|
|
30
37
|
"""
|
|
31
38
|
Resolve a dot-separated field path (e.g., 'profile.contact.email')
|
|
32
|
-
starting from `model`, handling
|
|
39
|
+
starting from `model`, handling columns and relationships.
|
|
33
40
|
|
|
34
41
|
Returns:
|
|
35
42
|
(final_attr, join_path)
|
|
36
43
|
- final_attr: The terminal InstrumentedAttribute (e.g., Contact.email)
|
|
37
|
-
- join_path: List of relationship attributes for explicit joins
|
|
38
|
-
(e.g., [User.profile, Profile.contact])
|
|
44
|
+
- join_path: List of relationship attributes for explicit joins (e.g., [User.profile, Profile.contact])
|
|
39
45
|
"""
|
|
40
|
-
|
|
41
|
-
parts = path.split(".")
|
|
42
|
-
current_model = model
|
|
43
|
-
current_attr = None
|
|
46
|
+
final_attr = None
|
|
44
47
|
join_path: List[InstrumentedAttribute] = []
|
|
45
48
|
|
|
49
|
+
parts = name.split(".")
|
|
50
|
+
current_model = model
|
|
46
51
|
for i, part in enumerate(parts):
|
|
47
52
|
attr = getattr(current_model, part)
|
|
48
53
|
# Case 1: Column (must be last)
|
|
49
|
-
if
|
|
54
|
+
if is_column(attr):
|
|
50
55
|
if i != len(parts) - 1:
|
|
51
56
|
raise ValueError(
|
|
52
57
|
f"Column '{part}' cannot be followed by further path segments."
|
|
53
58
|
)
|
|
54
|
-
|
|
59
|
+
final_attr = attr
|
|
55
60
|
break
|
|
56
61
|
# Case 2: Relationship
|
|
57
62
|
elif is_relationship(attr):
|
|
58
|
-
if i == len(parts) - 1:
|
|
59
|
-
raise ValueError(
|
|
60
|
-
f"Cannot sort/filter on relationship '{path}' directly. "
|
|
61
|
-
"Specify a column (e.g., '{path}.id')."
|
|
62
|
-
)
|
|
63
63
|
join_path.append(attr)
|
|
64
64
|
current_model = attr.property.mapper.class_
|
|
65
65
|
# Case 3: AssociationProxy
|
|
66
|
-
elif
|
|
67
|
-
|
|
68
|
-
local_rel_name = attr.local_attr # str, e.g., 'profile'
|
|
69
|
-
local_rel = getattr(current_model, local_rel_name)
|
|
70
|
-
|
|
71
|
-
if not is_relationship(local_rel):
|
|
66
|
+
elif is_association_proxy(current_model, part):
|
|
67
|
+
if i != len(parts) - 1:
|
|
72
68
|
raise ValueError(
|
|
73
|
-
f"AssociationProxy '{part}'
|
|
74
|
-
f"(got {type(local_rel.property).__name__})."
|
|
69
|
+
f"AssociationProxy '{part}' cannot be followed by further path segments."
|
|
75
70
|
)
|
|
76
|
-
|
|
71
|
+
# Step into the underlying relationship
|
|
72
|
+
local_rel = attr.local_attr
|
|
77
73
|
join_path.append(local_rel)
|
|
78
|
-
target_model = local_rel.property.mapper.class_
|
|
79
|
-
|
|
80
|
-
# Get the remote attribute (should be InstrumentedAttribute in SA 2.0)
|
|
81
74
|
remote_attr = attr.remote_attr
|
|
82
|
-
|
|
83
|
-
# If there are more parts after this proxy, recurse
|
|
84
|
-
if i < len(parts) - 1:
|
|
85
|
-
remaining = ".".join(parts[i + 1 :])
|
|
86
|
-
final_attr, extra_joins = get_field_with_path(target_model, remaining)
|
|
87
|
-
join_path.extend(extra_joins)
|
|
88
|
-
return final_attr, join_path
|
|
89
|
-
|
|
90
|
-
# This is the last part — ensure remote_attr is usable
|
|
91
|
-
if isinstance(remote_attr, str):
|
|
92
|
-
# Fallback for older versions (not needed in SA 2.0+, but safe)
|
|
93
|
-
remote_attr = getattr(target_model, remote_attr)
|
|
94
|
-
|
|
95
|
-
if not hasattr(remote_attr, "property"):
|
|
96
|
-
raise ValueError(
|
|
97
|
-
f"Remote attribute {remote_attr} is not a mapped ORM attribute."
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
current_attr = remote_attr
|
|
75
|
+
final_attr = remote_attr
|
|
101
76
|
break
|
|
102
77
|
else:
|
|
103
78
|
raise ValueError(
|
|
104
79
|
f"Unsupported attribute type for '{model}':'{part}': {type(attr)}"
|
|
105
80
|
)
|
|
106
81
|
|
|
107
|
-
if
|
|
82
|
+
if final_attr is None:
|
|
108
83
|
raise RuntimeError("Failed to resolve path — no terminal attribute found.")
|
|
109
84
|
|
|
110
|
-
return
|
|
85
|
+
return final_attr, join_path
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from math import ceil
|
|
2
|
+
from typing import Any, Optional, Generic, TypeVar, Iterator
|
|
3
|
+
from sqlalchemy.sql import Select
|
|
4
|
+
from sqlalchemy.sql import select,func
|
|
5
|
+
from sqlalchemy.orm import Session
|
|
6
|
+
|
|
7
|
+
T = TypeVar("T")
|
|
8
|
+
|
|
9
|
+
class Pagination(Generic[T]):
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
items: list[T],
|
|
13
|
+
total: int,
|
|
14
|
+
page: int,
|
|
15
|
+
per_page: int,
|
|
16
|
+
):
|
|
17
|
+
self.items = items
|
|
18
|
+
self.total = total
|
|
19
|
+
self.page = page
|
|
20
|
+
self.per_page = per_page
|
|
21
|
+
self.pages = ceil(total / per_page) if per_page > 0 else 0
|
|
22
|
+
self.has_prev = page > 1
|
|
23
|
+
self.has_next = page < self.pages
|
|
24
|
+
self.prev_num = page - 1 if self.has_prev else None
|
|
25
|
+
self.next_num = page + 1 if self.has_next else None
|
|
26
|
+
|
|
27
|
+
def iter_pages(self) -> Iterator[int]:
|
|
28
|
+
"""Iterate over page numbers for pagination controls."""
|
|
29
|
+
return iter(range(1, self.pages + 1))
|
|
30
|
+
|
|
31
|
+
def __repr__(self):
|
|
32
|
+
return f"<Pagination page={self.page} of {self.pages}>"
|
|
33
|
+
|
|
34
|
+
def paginate(
|
|
35
|
+
session: Session,
|
|
36
|
+
stmt: Select,
|
|
37
|
+
*,
|
|
38
|
+
page: int = 1,
|
|
39
|
+
per_page: int = 20,
|
|
40
|
+
) -> Pagination:
|
|
41
|
+
"""
|
|
42
|
+
Paginate a SQLAlchemy 2.0 select statement.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
session: SQLAlchemy Session instance
|
|
46
|
+
stmt: A SQLAlchemy Select statement (e.g., select(User))
|
|
47
|
+
page: Current page number (1-indexed)
|
|
48
|
+
per_page: Number of items per page
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Pagination object with .items, .total, .has_next, etc.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
# Count total rows
|
|
55
|
+
count_stmt = select(func.count()).select_from(stmt.subquery())
|
|
56
|
+
total = session.execute(count_stmt).scalar_one()
|
|
57
|
+
|
|
58
|
+
if total == 0:
|
|
59
|
+
return Pagination(items=[], total=0, page=page, per_page=per_page)
|
|
60
|
+
|
|
61
|
+
if page < 1:
|
|
62
|
+
# raise ValueError("Page must be >= 1")
|
|
63
|
+
page = 1
|
|
64
|
+
|
|
65
|
+
pages = ceil(total / per_page)
|
|
66
|
+
if page > pages:
|
|
67
|
+
# raise ValueError(f"Page {page} is out of range (total pages: {pages})")
|
|
68
|
+
page = pages
|
|
69
|
+
|
|
70
|
+
# Apply limit/offset
|
|
71
|
+
paginated_stmt = stmt.offset((page - 1) * per_page).limit(per_page)
|
|
72
|
+
items = session.execute(paginated_stmt).scalars().all()
|
|
73
|
+
|
|
74
|
+
return Pagination(items=items, total=total, page=page, per_page=per_page)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
python_plugins/__about__.py,sha256=
|
|
1
|
+
python_plugins/__about__.py,sha256=acuR_XSJzp4OrQ5T8-Ac5gYe48mUwObuwjRmisFmZ7k,22
|
|
2
2
|
python_plugins/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
3
3
|
python_plugins/crypto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
python_plugins/crypto/aes_cipher.py,sha256=7lTvA01h3Z56riv7sB7CrZRh_OO66m21wVTVizU9PYg,1946
|
|
@@ -10,6 +10,7 @@ python_plugins/crypto/txtfile_cipher.py,sha256=-mTkvQgtNYLUvrQLKTnepBBdkf-T0w-Dn
|
|
|
10
10
|
python_plugins/crypto/zip7mix.py,sha256=tQMmX_6ax99LXNfY8HBbu9EXSwQSgGOF3EwWEcrtdUo,5272
|
|
11
11
|
python_plugins/email/__init__.py,sha256=HubZT2h3m5WEjic3NZ0H7gYp-9tUgZaDkAE9O-Tm7hM,26
|
|
12
12
|
python_plugins/email/smtp.py,sha256=CY1fWxdBDqqGZ22R8yqEvFZvMeEsMnqTb4h5IZ8WAVU,1641
|
|
13
|
+
python_plugins/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
14
|
python_plugins/examples/datetime.py,sha256=bmC9d1W7XKA1ED9XO9reUiUyfQcM_BqGoGyOF21RW9A,282
|
|
14
15
|
python_plugins/examples/hashes.py,sha256=uSF3ohZRD7b2VAIvjjpTWC0SlY7QsFhsFZUejINrRGU,640
|
|
15
16
|
python_plugins/examples/higher_order_functions.py,sha256=vTfT3OEfuKkIW7UMD3JtreVDMeRbXHbjlz3G-j-J4x4,4574
|
|
@@ -18,12 +19,14 @@ python_plugins/examples/pretty.py,sha256=igN4uq67AADcPOiy_h3_M-oEwgc1i3gJScbKtkf
|
|
|
18
19
|
python_plugins/examples/random_string.py,sha256=U7B-bAa4zEpewkd4_8KIPZ0XsPdbGlJ_FEj0FnTGdms,2210
|
|
19
20
|
python_plugins/examples/run_jwt.py,sha256=ZwjUXg5PKeophiXqwSaMlHrhwVKhHTsRb68HtkRLX8k,1485
|
|
20
21
|
python_plugins/examples/run_process.py,sha256=I_wjCqzWI6d39ebL-YArQ8LiXFQ3bwEoCnxJTZK1Zbc,780
|
|
22
|
+
python_plugins/examples/sphinx_google_style.py,sha256=TJuxBqXG3OtZHmlbLlCRD07ADs1QImOhZu33HksSgKM,9688
|
|
23
|
+
python_plugins/examples/sphinx_numpy_style.py,sha256=jhtOp7fiQcbtj-dUufloPQlV4vAKwlAlRgw8r6rxVgw,9735
|
|
21
24
|
python_plugins/examples/xml2dict.py,sha256=RUxqDt6NKzwbuodTxKVoiR4dP-vNbmL77dztLx_9UzY,164
|
|
22
25
|
python_plugins/examples/tkinter/calculate.py,sha256=M1b-w7-pVe-7FS3erBJxgFNfmm4lzP3zlK41glyhWx8,1142
|
|
23
26
|
python_plugins/ospath/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
-
python_plugins/ospath/
|
|
27
|
+
python_plugins/ospath/walk.py,sha256=zj8616KtK4bduJyuyw2b7bg6udV_-ssEAGPLJblhPlM,792
|
|
25
28
|
python_plugins/sqla/__init__.py,sha256=dJyZS1js_pdpAgLnsqfRFPQBFeZ8PdssdPfTzgie5c8,30
|
|
26
|
-
python_plugins/sqla/db.py,sha256=
|
|
29
|
+
python_plugins/sqla/db.py,sha256=rW0x7U0d3oqhZSL2GbxTEtyy83neGogt5VUNTnJadnA,3217
|
|
27
30
|
python_plugins/sqla/orm.py,sha256=7h0oY4TGfdrvAFKedVbKdWTvWHq_Sc-ycd2VvWiZJyo,1331
|
|
28
31
|
python_plugins/sqla/mixins/__init__.py,sha256=l4dJVgUFI7aISA7X-CcVBOp19rXBgqyyhHwtuQnSgR0,241
|
|
29
32
|
python_plugins/sqla/mixins/data_mixin.py,sha256=HCc1uvF6_O4yjK38uWAsqysEedLWgc7wtds3NjQTMZ8,366
|
|
@@ -31,23 +34,15 @@ python_plugins/sqla/mixins/primary_key_mixin.py,sha256=QUO-7ZmYtAMMi7ReRQDYV0uwQ
|
|
|
31
34
|
python_plugins/sqla/mixins/timestamp_mixin.py,sha256=u9rIu0IrzdCRRbnMk4IN4nTlNNiVPB8yPnTcHjQC1KU,547
|
|
32
35
|
python_plugins/sqla/mixins/token_minxin.py,sha256=SxNftZXS-hCwqxov7whF_tBtlayuoi3LUPtu-ofMmdg,276
|
|
33
36
|
python_plugins/sqla/mixins/user_minxin.py,sha256=D-N45bunicBuuwKs--s_tyDxxLC3mkxV9Tva8JAhsko,579
|
|
34
|
-
python_plugins/sqla/
|
|
35
|
-
python_plugins/sqla/
|
|
36
|
-
python_plugins/sqla/models/demo.py,sha256=UbibjsBvm542Gyx8t8qf8Izqs47K88v9BN0Pc2RPAJc,3218
|
|
37
|
-
python_plugins/sqla/models/message.py,sha256=NDxcN8mWnWFTTunf5dz-Tb5FmHv8HHzppsZ8IVHmpAw,435
|
|
38
|
-
python_plugins/sqla/models/model1.py,sha256=NxOsygCCt9q1hpt2QmGsuCs6yl1Kn5tv5HGuhHaPCRQ,4596
|
|
39
|
-
python_plugins/sqla/models/multpk.py,sha256=pexTSm7CzXpf0pD_ECfHraM0QlZcMAYf9Qv_KPijvUA,396
|
|
40
|
-
python_plugins/sqla/models/polymorphic.py,sha256=-nwEoKkAZL97mnykisZ1VkntyeqNLmfEbd7tXxAYnuY,938
|
|
41
|
-
python_plugins/sqla/models/relations.py,sha256=zjbZrhW9pv8Tpnu6zApdO-rhwjbFF3Vv1r_xp5DCKWc,2669
|
|
42
|
-
python_plugins/sqla/models/tree_node.py,sha256=VGGdIGhfDe_0BUp3UpxEjexMSirwezOUXGv-fKiBXvk,575
|
|
43
|
-
python_plugins/sqla/utils/__init__.py,sha256=lq6KaQfwmnobgas87D26ijnaCfDau3H7ZkmozBYWzk0,302
|
|
44
|
-
python_plugins/sqla/utils/attr.py,sha256=IdWj17GXKk4tk-dQROWZh7ZyPPlO4--YaoeZp0EWgUQ,4119
|
|
37
|
+
python_plugins/sqla/utils/__init__.py,sha256=sHrgAp1TJ3k02gbhMIf2or9IzI7in1P70PqqhFNhBUY,311
|
|
38
|
+
python_plugins/sqla/utils/attr.py,sha256=R6ehESBt3G-ukfczmqoKb9BiWdS0AC9uz2y0OZgzjQE,2947
|
|
45
39
|
python_plugins/sqla/utils/expression.py,sha256=_9P59Elc3jqdXFiXxkrRY9gsaUSum-chNMPbiqQcC58,202
|
|
46
40
|
python_plugins/sqla/utils/instance.py,sha256=EbcI3pQhsRj-mPW9ZHs0yQ4zMGVMHw-HtmmXHY15kK0,255
|
|
47
41
|
python_plugins/sqla/utils/model.py,sha256=R9ObqEMDOaYKLv8pcoDHoV7m4mxWHgEDiZ74NokMMjA,678
|
|
42
|
+
python_plugins/sqla/utils/paginate.py,sha256=Fqqb3N6HAdSD4OXvu62XgmIQp1eUAY0ODS4e3e_gtWQ,2186
|
|
48
43
|
python_plugins/sqla/utils/stmt.py,sha256=3GzzEvi0RmvE3q-zBweol9LmsEQ0UPkn9G6P0epNwWw,876
|
|
49
44
|
python_plugins/sqla/utils/update.py,sha256=jsTgivwzIeFSpbpFwb48_pTUNT-KM6TYnGv3wKH98HM,631
|
|
50
|
-
python_plugins-1.0.
|
|
51
|
-
python_plugins-1.0.
|
|
52
|
-
python_plugins-1.0.
|
|
53
|
-
python_plugins-1.0.
|
|
45
|
+
python_plugins-1.0.4.dist-info/METADATA,sha256=Cxs-TUoFEfTwbCNeYCtWxiH08_xQZVER8zz8g-5PH_c,2624
|
|
46
|
+
python_plugins-1.0.4.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
47
|
+
python_plugins-1.0.4.dist-info/licenses/LICENSE.rst,sha256=X5eLIsAn1yAKd88LWTYkXUe0PmVK_Z5SD7_5NheGR-s,1104
|
|
48
|
+
python_plugins-1.0.4.dist-info/RECORD,,
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import shutil
|
|
3
|
-
|
|
4
|
-
def remove(dir,rm_dir_name):
|
|
5
|
-
for root, dirs, files in os.walk(dir):
|
|
6
|
-
if "venv" in root or "git" in root:
|
|
7
|
-
continue
|
|
8
|
-
for dir in dirs:
|
|
9
|
-
if dir == rm_dir_name:
|
|
10
|
-
rm_path = os.path.join(root, dir)
|
|
11
|
-
print(f"Removing {rm_path}")
|
|
12
|
-
shutil.rmtree(rm_path)
|
|
13
|
-
|
|
14
|
-
def remove_pycache(dir="."):
|
|
15
|
-
remove(dir,"__pycache__")
|
|
16
|
-
|
|
17
|
-
def remove_ipynb_checkpoints(dir="."):
|
|
18
|
-
remove(dir,".ipynb_checkpoints")
|
|
19
|
-
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
from typing import Final
|
|
2
|
-
from typing import List
|
|
3
|
-
from .. import db
|
|
4
|
-
from ..orm import Mapped
|
|
5
|
-
from ..orm import mapped_column
|
|
6
|
-
from ..orm import ForeignKey
|
|
7
|
-
from ..orm import relationship
|
|
8
|
-
from ..orm import Table
|
|
9
|
-
from ..orm import Column
|
|
10
|
-
from ..orm import Integer
|
|
11
|
-
from ..orm import String
|
|
12
|
-
from ..orm import association_proxy
|
|
13
|
-
from ..orm import AssociationProxy
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class AssociationProxyChild(db.Model):
|
|
17
|
-
__tablename__ = "association_proxy_child"
|
|
18
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
19
|
-
name: Mapped[str] = mapped_column(String(64))
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class AssociationProxyParent(db.Model):
|
|
23
|
-
__tablename__ = "association_proxy_parent"
|
|
24
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
25
|
-
name: Mapped[str] = mapped_column(String(64))
|
|
26
|
-
children: Mapped[List[AssociationProxyChild]] = relationship(
|
|
27
|
-
secondary=lambda: association_proxy_parent_child_table
|
|
28
|
-
)
|
|
29
|
-
# proxy the 'name' attribute from the 'children' relationship
|
|
30
|
-
childrennames: AssociationProxy[List[str]] = association_proxy("children", "name")
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
association_proxy_parent_child_table: Final[Table] = Table(
|
|
34
|
-
"association_proxy_parent_child",
|
|
35
|
-
db.Model.metadata,
|
|
36
|
-
Column(
|
|
37
|
-
"association_proxy_parent_id",
|
|
38
|
-
Integer,
|
|
39
|
-
ForeignKey("association_proxy_parent.id"),
|
|
40
|
-
primary_key=True,
|
|
41
|
-
),
|
|
42
|
-
Column(
|
|
43
|
-
"association_proxy_child_id",
|
|
44
|
-
Integer,
|
|
45
|
-
ForeignKey("association_proxy_child.id"),
|
|
46
|
-
primary_key=True,
|
|
47
|
-
),
|
|
48
|
-
)
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
from typing import Optional, List
|
|
2
|
-
from datetime import datetime
|
|
3
|
-
from datetime import date
|
|
4
|
-
from datetime import time
|
|
5
|
-
import enum
|
|
6
|
-
|
|
7
|
-
from .. import db
|
|
8
|
-
from ..orm import Integer
|
|
9
|
-
from ..orm import Boolean
|
|
10
|
-
from ..orm import String
|
|
11
|
-
from ..orm import Float
|
|
12
|
-
from ..orm import DateTime
|
|
13
|
-
from ..orm import Date
|
|
14
|
-
from ..orm import Time
|
|
15
|
-
from ..orm import LargeBinary
|
|
16
|
-
from ..orm import Enum
|
|
17
|
-
from ..orm import JSON
|
|
18
|
-
from ..orm import Mapped
|
|
19
|
-
from ..orm import mapped_column
|
|
20
|
-
from ..orm import relationship
|
|
21
|
-
from ..orm import composite
|
|
22
|
-
from ..orm import synonym
|
|
23
|
-
from ..orm import Table
|
|
24
|
-
from ..orm import Column
|
|
25
|
-
from ..orm import ForeignKey
|
|
26
|
-
from ..orm import hybrid_property
|
|
27
|
-
from ..orm import hybrid_method
|
|
28
|
-
from ..orm import association_proxy
|
|
29
|
-
from ..orm import AssociationProxy
|
|
30
|
-
|
|
31
|
-
# see https://docs.sqlalchemy.org/en/20/orm/extensions/associationproxy.html
|
|
32
|
-
|
|
33
|
-
class Point:
|
|
34
|
-
x: int
|
|
35
|
-
y: int
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
# Status = Literal["pending", "received", "completed"]
|
|
39
|
-
class Status(enum.Enum):
|
|
40
|
-
PENDING = "pending"
|
|
41
|
-
RECEIVED = "received"
|
|
42
|
-
COMPLETED = "completed"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class Demo(db.Model):
|
|
46
|
-
__tablename__ = "demo"
|
|
47
|
-
|
|
48
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
49
|
-
name: Mapped[str] = mapped_column(unique=True)
|
|
50
|
-
first_name: Mapped[str]
|
|
51
|
-
last_name: Mapped[str]
|
|
52
|
-
data: Mapped[dict] = mapped_column(JSON)
|
|
53
|
-
bool_field: Mapped[bool] = mapped_column(Boolean, nullable=True)
|
|
54
|
-
date_field: Mapped[date] = mapped_column(Date, nullable=True)
|
|
55
|
-
time_field: Mapped[time] = mapped_column(Time, nullable=True)
|
|
56
|
-
datetime_field: Mapped[datetime] = mapped_column(DateTime, nullable=True)
|
|
57
|
-
x: Mapped[int]
|
|
58
|
-
y: Mapped[int]
|
|
59
|
-
start: Mapped[int]
|
|
60
|
-
end: Mapped[int]
|
|
61
|
-
status: Mapped[Status]
|
|
62
|
-
created_at: Mapped[datetime] = mapped_column(default=datetime.now)
|
|
63
|
-
updated_at: Mapped[datetime] = mapped_column(
|
|
64
|
-
default=datetime.now, onupdate=datetime.now
|
|
65
|
-
)
|
|
66
|
-
point: Mapped[Point] = composite("x", "y")
|
|
67
|
-
|
|
68
|
-
syn_status = synonym("status")
|
|
69
|
-
|
|
70
|
-
@hybrid_property
|
|
71
|
-
def full_name(self) -> str:
|
|
72
|
-
return f"{self.first_name} {self.last_name}"
|
|
73
|
-
|
|
74
|
-
@hybrid_method
|
|
75
|
-
def contains(self, point: int) -> bool:
|
|
76
|
-
return (self.start <= point) & (point <= self.end)
|
|
77
|
-
|
|
78
|
-
tg: Mapped[List["Tag"]] = relationship(secondary=lambda: demo_tag_table)
|
|
79
|
-
# proxy the 'keyword' attribute from the 'kw' relationship
|
|
80
|
-
tags: AssociationProxy[List[str]] = association_proxy("tg", "tag")
|
|
81
|
-
|
|
82
|
-
addresses: Mapped[List["Address"]] = relationship(back_populates="demo")
|
|
83
|
-
|
|
84
|
-
def __init__(self, name: str):
|
|
85
|
-
self.name = name
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
class Address(db.Model):
|
|
89
|
-
__tablename__ = "address"
|
|
90
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
91
|
-
street: Mapped[str]
|
|
92
|
-
demo_id = mapped_column(ForeignKey("demo.id"))
|
|
93
|
-
demo: Mapped["Demo"] = relationship(back_populates="addresses")
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
class Tag(db.Model):
|
|
97
|
-
__tablename__ = "tag"
|
|
98
|
-
|
|
99
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
100
|
-
tag: Mapped[str]
|
|
101
|
-
|
|
102
|
-
def __init__(self, tag: str):
|
|
103
|
-
self.tag = tag
|
|
104
|
-
|
|
105
|
-
def __repr__(self) -> str:
|
|
106
|
-
return f"Tag({self.tag!r})"
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
demo_tag_table = Table(
|
|
110
|
-
"demo_tag",
|
|
111
|
-
db.Model.metadata,
|
|
112
|
-
Column("demo_id", ForeignKey("demo.id"), primary_key=True),
|
|
113
|
-
Column("tag_id", ForeignKey("tag.id"), primary_key=True),
|
|
114
|
-
)
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import enum
|
|
2
|
-
from .. import db
|
|
3
|
-
from ..orm import Mapped
|
|
4
|
-
from ..orm import mapped_column
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class MyCat(enum.Enum):
|
|
8
|
-
CAT1 = "Category A"
|
|
9
|
-
CAT2 = "Category B"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class Message(db.Model):
|
|
13
|
-
__table__tablename__ = "message"
|
|
14
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
15
|
-
text: Mapped[str]
|
|
16
|
-
sender: Mapped[str]
|
|
17
|
-
recipient: Mapped[str]
|
|
18
|
-
category:Mapped[MyCat] = mapped_column(default=MyCat.CAT1,nullable=False)
|
|
19
|
-
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import enum
|
|
2
|
-
from datetime import datetime, date, time
|
|
3
|
-
from .. import db
|
|
4
|
-
from ..orm import Mapped
|
|
5
|
-
from ..orm import mapped_column
|
|
6
|
-
from ..orm import Enum
|
|
7
|
-
from ..orm import hybrid_property
|
|
8
|
-
from ..orm import cast
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class EnumChoices(enum.Enum):
|
|
12
|
-
first = 1
|
|
13
|
-
second = 2
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class Model1(db.Model):
|
|
17
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
18
|
-
test1:Mapped[str]
|
|
19
|
-
test2:Mapped[str]
|
|
20
|
-
test3:Mapped[str]
|
|
21
|
-
test4:Mapped[str]
|
|
22
|
-
bool_field: Mapped[bool]
|
|
23
|
-
date_field: Mapped[date]
|
|
24
|
-
time_field: Mapped[time]
|
|
25
|
-
datetime_field: Mapped[datetime]
|
|
26
|
-
email_field:Mapped[str]
|
|
27
|
-
enum_field: Mapped[str] = mapped_column(Enum("model1_v1", "model1_v2"), nullable=True)
|
|
28
|
-
enum_type_field = mapped_column(Enum(EnumChoices), nullable=True)
|
|
29
|
-
choice_field:Mapped[str]
|
|
30
|
-
|
|
31
|
-
def __init__(
|
|
32
|
-
self,
|
|
33
|
-
test1=None,
|
|
34
|
-
test2=None,
|
|
35
|
-
test3=None,
|
|
36
|
-
test4=None,
|
|
37
|
-
bool_field=False,
|
|
38
|
-
date_field=None,
|
|
39
|
-
time_field=None,
|
|
40
|
-
datetime_field=None,
|
|
41
|
-
choice_field=None,
|
|
42
|
-
enum_field=None,
|
|
43
|
-
enum_type_field=None,
|
|
44
|
-
):
|
|
45
|
-
self.test1 = test1
|
|
46
|
-
self.test2 = test2
|
|
47
|
-
self.test3 = test3
|
|
48
|
-
self.test4 = test4
|
|
49
|
-
self.bool_field = bool_field
|
|
50
|
-
self.date_field = date_field
|
|
51
|
-
self.time_field = time_field
|
|
52
|
-
self.datetime_field = datetime_field
|
|
53
|
-
self.choice_field = choice_field
|
|
54
|
-
self.enum_field = enum_field
|
|
55
|
-
self.enum_type_field = enum_type_field
|
|
56
|
-
|
|
57
|
-
def __str__(self):
|
|
58
|
-
return str(self.test1)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class Model2(db.Model):
|
|
62
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
63
|
-
string_field:Mapped[str]
|
|
64
|
-
string_field_default = db.Column(db.Text, nullable=False, default="")
|
|
65
|
-
string_field_empty_default = db.Column(db.Text, nullable=False, default="")
|
|
66
|
-
int_field = db.Column(db.Integer)
|
|
67
|
-
bool_field = db.Column(db.Boolean)
|
|
68
|
-
enum_field = db.Column(db.Enum("model2_v1", "model2_v2"), nullable=True)
|
|
69
|
-
float_field = db.Column(db.Float)
|
|
70
|
-
|
|
71
|
-
# Relation
|
|
72
|
-
model1_id = db.Column(db.Integer, db.ForeignKey(Model1.id))
|
|
73
|
-
model1 = db.relationship(lambda: Model1, backref="model2")
|
|
74
|
-
|
|
75
|
-
def __init__(
|
|
76
|
-
self,
|
|
77
|
-
string_field=None,
|
|
78
|
-
int_field=None,
|
|
79
|
-
bool_field=None,
|
|
80
|
-
model1=None,
|
|
81
|
-
float_field=None,
|
|
82
|
-
string_field_default=None,
|
|
83
|
-
string_field_empty_default=None,
|
|
84
|
-
):
|
|
85
|
-
self.string_field = string_field
|
|
86
|
-
self.int_field = int_field
|
|
87
|
-
self.bool_field = bool_field
|
|
88
|
-
self.model1 = model1
|
|
89
|
-
self.float_field = float_field
|
|
90
|
-
self.string_field_default = string_field_default
|
|
91
|
-
self.string_field_empty_default = string_field_empty_default
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
class Model3(db.Model):
|
|
95
|
-
def __init__(self, id=None, val1=None):
|
|
96
|
-
self.id = id
|
|
97
|
-
self.val1 = val1
|
|
98
|
-
|
|
99
|
-
id = db.Column(db.String(20), primary_key=True)
|
|
100
|
-
val1 = db.Column(db.String(20))
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
class ModelHybrid(db.Model):
|
|
104
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
105
|
-
name = db.Column(db.String)
|
|
106
|
-
width = db.Column(db.Integer)
|
|
107
|
-
height = db.Column(db.Integer)
|
|
108
|
-
|
|
109
|
-
firstname = db.Column(db.String)
|
|
110
|
-
lastname = db.Column(db.String)
|
|
111
|
-
|
|
112
|
-
@hybrid_property
|
|
113
|
-
def fullname(self):
|
|
114
|
-
return "{} {}".format(self.firstname, self.lastname)
|
|
115
|
-
|
|
116
|
-
@hybrid_property
|
|
117
|
-
def number_of_pixels(self):
|
|
118
|
-
return self.width * self.height
|
|
119
|
-
|
|
120
|
-
@hybrid_property
|
|
121
|
-
def number_of_pixels_str(self):
|
|
122
|
-
return str(self.number_of_pixels())
|
|
123
|
-
|
|
124
|
-
@number_of_pixels_str.expression
|
|
125
|
-
def number_of_pixels_str(cls):
|
|
126
|
-
return cast(cls.width * cls.height, db.String)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
class ModelHybrid2(db.Model):
|
|
130
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
131
|
-
name = db.Column(db.String)
|
|
132
|
-
owner_id = db.Column(
|
|
133
|
-
db.Integer, db.ForeignKey("model_hybrid.id", ondelete="CASCADE")
|
|
134
|
-
)
|
|
135
|
-
owner = db.relationship("ModelHybrid", backref=db.backref("tiles"), uselist=False)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
class ModelNoint(db.Model):
|
|
139
|
-
id: Mapped[str] = mapped_column(primary_key=True)
|
|
140
|
-
test = db.Column(db.String)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
class ModelForm(db.Model):
|
|
144
|
-
id: Mapped[str] = mapped_column(primary_key=True)
|
|
145
|
-
int_field = db.Column(db.Integer)
|
|
146
|
-
datetime_field = db.Column(db.DateTime)
|
|
147
|
-
text_field = db.Column(db.UnicodeText)
|
|
148
|
-
excluded_column = db.Column(db.String)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
class ModelChild(db.Model):
|
|
152
|
-
id: Mapped[str] = mapped_column(primary_key=True)
|
|
153
|
-
model_id = db.Column(db.Integer, db.ForeignKey(ModelForm.id))
|
|
154
|
-
model = db.relationship(ModelForm, backref="backref")
|
|
155
|
-
enum_field = db.Column(db.Enum("model1_v1", "model1_v2"), nullable=True)
|
|
156
|
-
choice_field = db.Column(db.String, nullable=True)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
from .. import db
|
|
2
|
-
from ..orm import Mapped
|
|
3
|
-
from ..orm import mapped_column
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Singlepk(db.Model):
|
|
7
|
-
__tablename__ = "singlepk"
|
|
8
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
9
|
-
data: Mapped[str]
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class Multpk(db.Model):
|
|
13
|
-
__tablename__ = "multpk"
|
|
14
|
-
id: Mapped[int] = mapped_column(primary_key=True)
|
|
15
|
-
id2: Mapped[int] = mapped_column(primary_key=True)
|
|
16
|
-
data: Mapped[str]
|