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.
@@ -1,6 +1,6 @@
1
1
  from .attr import is_column
2
2
  from .attr import is_relationship
3
- from .attr import is_hybrid
3
+ from .attr import is_hybrid_property
4
4
  from .attr import is_association_proxy
5
5
  from .attr import get_field_with_path
6
6
  from .expression import parse_like_term
@@ -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 is_hybrid(attr):
21
- return isinstance(attr, hybrid_property)
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(attr):
24
- return isinstance(attr, AssociationProxy)
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, path: str
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 AssociationProxy and relationships.
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
- print(model, path)
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 hasattr(attr, "property") and isinstance(attr.property, ColumnProperty):
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
- current_attr = attr
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 isinstance(attr, AssociationProxy):
67
- # Step into the underlying relationship
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}' is not backed by a relationship "
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 current_attr is None:
82
+ if final_attr is None:
108
83
  raise RuntimeError("Failed to resolve path — no terminal attribute found.")
109
84
 
110
- return current_attr, join_path
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-plugins
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: A collection of Python functions and classes.
5
5
  Project-URL: Documentation, https://python-plugins.readthedocs.io
6
6
  Project-URL: Source, https://github.com/ojso/python-plugins
@@ -1,4 +1,4 @@
1
- python_plugins/__about__.py,sha256=2plzdEEb24FLjE2I2XyBBcJEPYWHccNL4SgtLC_6erg,22
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/walk_remove.py,sha256=rnDHr1wGSxufo2YV9_EXeVNEAnT4LGjG7-5dOI2gWY0,494
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=fA601WJ3QiUyXAQGwS72wa9S1b973T-HK1ZsE6OL0c0,3179
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/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
- python_plugins/sqla/models/association_proxy.py,sha256=a3_ffi4gyXMuDV9NtlCo2POoBxwFCKCA2fSJlfft1Ow,1454
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.3.dist-info/METADATA,sha256=1ImRtLGKGW7nNd06mtiLso56_D3ZxVPBy4soald9ghs,2624
51
- python_plugins-1.0.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
52
- python_plugins-1.0.3.dist-info/licenses/LICENSE.rst,sha256=X5eLIsAn1yAKd88LWTYkXUe0PmVK_Z5SD7_5NheGR-s,1104
53
- python_plugins-1.0.3.dist-info/RECORD,,
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,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.28.0
2
+ Generator: hatchling 1.29.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -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]