python-plugins 1.0.2__tar.gz → 1.0.3__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.
Files changed (108) hide show
  1. {python_plugins-1.0.2 → python_plugins-1.0.3}/CHANGES.rst +6 -0
  2. {python_plugins-1.0.2 → python_plugins-1.0.3}/PKG-INFO +6 -12
  3. {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/api/crypto.rst +0 -3
  4. python_plugins-1.0.3/docs/api/sqlalchemy.rst +13 -0
  5. {python_plugins-1.0.2 → python_plugins-1.0.3}/pyproject.toml +5 -8
  6. python_plugins-1.0.3/requirements/develop.in +2 -0
  7. python_plugins-1.0.3/requirements/example.in +1 -0
  8. python_plugins-1.0.3/src/python_plugins/__about__.py +1 -0
  9. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/zip7mix.py +12 -2
  10. python_plugins-1.0.3/src/python_plugins/sqla/__init__.py +3 -0
  11. python_plugins-1.0.3/src/python_plugins/sqla/db.py +96 -0
  12. python_plugins-1.0.3/src/python_plugins/sqla/models/association_proxy.py +48 -0
  13. python_plugins-1.0.3/src/python_plugins/sqla/models/demo.py +114 -0
  14. python_plugins-1.0.3/src/python_plugins/sqla/models/message.py +19 -0
  15. python_plugins-1.0.3/src/python_plugins/sqla/models/model1.py +161 -0
  16. python_plugins-1.0.3/src/python_plugins/sqla/models/multpk.py +16 -0
  17. python_plugins-1.0.3/src/python_plugins/sqla/models/polymorphic.py +35 -0
  18. python_plugins-1.0.3/src/python_plugins/sqla/models/relations.py +74 -0
  19. python_plugins-1.0.3/src/python_plugins/sqla/models/tree_node.py +17 -0
  20. python_plugins-1.0.3/src/python_plugins/sqla/orm.py +40 -0
  21. python_plugins-1.0.3/src/python_plugins/sqla/utils/__init__.py +10 -0
  22. python_plugins-1.0.3/src/python_plugins/sqla/utils/attr.py +110 -0
  23. python_plugins-1.0.3/src/python_plugins/sqla/utils/expression.py +9 -0
  24. python_plugins-1.0.3/src/python_plugins/sqla/utils/instance.py +12 -0
  25. python_plugins-1.0.3/src/python_plugins/sqla/utils/model.py +31 -0
  26. python_plugins-1.0.3/src/python_plugins/sqla/utils/stmt.py +34 -0
  27. python_plugins-1.0.3/src/python_plugins/sqla/utils/update.py +23 -0
  28. python_plugins-1.0.3/tests/sqla/__init__.py +9 -0
  29. python_plugins-1.0.3/tests/sqla/test_association_proxy.py +33 -0
  30. python_plugins-1.0.3/tests/sqla/test_db.py +39 -0
  31. python_plugins-1.0.3/tests/sqla/test_docs.py +9 -0
  32. python_plugins-1.0.3/tests/sqla/test_flask_db.py +58 -0
  33. python_plugins-1.0.3/tests/sqla/test_mult_pk.py +31 -0
  34. python_plugins-1.0.3/tests/sqla/test_polymorphic.py +37 -0
  35. python_plugins-1.0.3/tests/sqla/test_registry_mappers.py +5 -0
  36. python_plugins-1.0.3/tests/sqla/test_relation.py +44 -0
  37. python_plugins-1.0.3/tests/sqla/test_tree_node.py +26 -0
  38. python_plugins-1.0.3/tests/sqla/utils/__init__.py +0 -0
  39. python_plugins-1.0.3/tests/sqla/utils/test_create_table.py +36 -0
  40. python_plugins-1.0.3/tests/sqla/utils/test_inspect_mapper.py +188 -0
  41. python_plugins-1.0.3/tests/sqla/utils/test_primary_key.py +53 -0
  42. python_plugins-1.0.3/tests/sqla/utils/test_stmt_delete.py +84 -0
  43. python_plugins-1.0.2/docs/api/sqlalchemy.rst +0 -21
  44. python_plugins-1.0.2/requirements/develop.in +0 -6
  45. python_plugins-1.0.2/src/python_plugins/__about__.py +0 -1
  46. python_plugins-1.0.2/src/python_plugins/models/update.py +0 -33
  47. python_plugins-1.0.2/tests/test_sqlalchemy.py +0 -30
  48. {python_plugins-1.0.2 → python_plugins-1.0.3}/.github/workflows/release.yml +0 -0
  49. {python_plugins-1.0.2 → python_plugins-1.0.3}/.gitignore +0 -0
  50. {python_plugins-1.0.2 → python_plugins-1.0.3}/.readthedocs.yaml +0 -0
  51. {python_plugins-1.0.2 → python_plugins-1.0.3}/LICENSE.rst +0 -0
  52. {python_plugins-1.0.2 → python_plugins-1.0.3}/README.rst +0 -0
  53. {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/Makefile +0 -0
  54. {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/_static/style.css +0 -0
  55. {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/api/email.rst +0 -0
  56. {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/api/index.rst +0 -0
  57. {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/api/ospath.rst +0 -0
  58. {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/changes.rst +0 -0
  59. {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/conf.py +0 -0
  60. {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/index.rst +0 -0
  61. {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/install.rst +0 -0
  62. {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/make.bat +0 -0
  63. {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/requirements.txt +0 -0
  64. {python_plugins-1.0.2 → python_plugins-1.0.3}/requirements/build.in +0 -0
  65. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/__init__.py +0 -0
  66. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/__init__.py +0 -0
  67. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/aes_cipher.py +0 -0
  68. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/mixbyte.py +0 -0
  69. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/pbkdf_fernet.py +0 -0
  70. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/simple_fernet.py +0 -0
  71. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/tarmix.py +0 -0
  72. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/txtfile_cipher.py +0 -0
  73. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/email/__init__.py +0 -0
  74. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/email/smtp.py +0 -0
  75. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/datetime.py +0 -0
  76. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/hashes.py +0 -0
  77. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/higher_order_functions.py +0 -0
  78. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/postgresql_dump.py +0 -0
  79. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/pretty.py +0 -0
  80. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/random_string.py +0 -0
  81. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/run_jwt.py +0 -0
  82. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/run_process.py +0 -0
  83. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/tkinter/calculate.py +0 -0
  84. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/xml2dict.py +0 -0
  85. {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/ospath}/__init__.py +0 -0
  86. {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/ospath/walk_remove.py +0 -0
  87. {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/sqla}/mixins/__init__.py +0 -0
  88. {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/sqla}/mixins/data_mixin.py +0 -0
  89. {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/sqla}/mixins/primary_key_mixin.py +0 -0
  90. {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/sqla}/mixins/timestamp_mixin.py +0 -0
  91. {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/sqla}/mixins/token_minxin.py +0 -0
  92. {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/sqla}/mixins/user_minxin.py +0 -0
  93. {python_plugins-1.0.2/src/python_plugins/ospath → python_plugins-1.0.3/src/python_plugins/sqla/models}/__init__.py +0 -0
  94. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/__init__.py +0 -0
  95. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/conftest.py +0 -0
  96. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_aes_cipher.py +0 -0
  97. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_crypt_file.py +0 -0
  98. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_mixbyte.py +0 -0
  99. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_pbkdf_fernet.py +0 -0
  100. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_simple_fernet.py +0 -0
  101. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_tarmix.py +0 -0
  102. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_zip7mix.py +0 -0
  103. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/test_email.py +0 -0
  104. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/tmp/a.png +0 -0
  105. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/tmp/a.txt +0 -0
  106. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/tmp/test/test.txt +0 -0
  107. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/tmp/test.archive.mix +0 -0
  108. {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/tmp/test.txt +0 -0
@@ -1,3 +1,9 @@
1
+ v1.0.3
2
+ ------
3
+ Released 2026-02-08
4
+
5
+ - sqlalchemy inspect model
6
+
1
7
  v1.0.2
2
8
  ------
3
9
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-plugins
3
- Version: 1.0.2
3
+ Version: 1.0.3
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
@@ -38,17 +38,11 @@ Classifier: Programming Language :: Python :: 3.10
38
38
  Classifier: Programming Language :: Python :: 3.11
39
39
  Classifier: Topic :: Software Development :: Build Tools
40
40
  Requires-Python: >=3.10
41
- Requires-Dist: cryptography>=44.0
42
- Provides-Extra: jwt
43
- Requires-Dist: pyjwt; extra == 'jwt'
44
- Provides-Extra: pillow
45
- Requires-Dist: pillow; extra == 'pillow'
46
- Provides-Extra: qrcode
47
- Requires-Dist: qrcode; extra == 'qrcode'
48
- Provides-Extra: requests
49
- Requires-Dist: requests; extra == 'requests'
50
- Provides-Extra: sqlalchemy
51
- Requires-Dist: sqlalchemy; extra == 'sqlalchemy'
41
+ Requires-Dist: cryptography>=46.0
42
+ Requires-Dist: flask>=3.1
43
+ Requires-Dist: requests>=2.32
44
+ Requires-Dist: sqlalchemy>=2.0
45
+ Requires-Dist: wtforms>=3.2
52
46
  Description-Content-Type: text/x-rst
53
47
 
54
48
  python-plugins
@@ -11,8 +11,5 @@ crypto
11
11
  .. autoclass:: python_plugins.crypto.txtfile_cipher.TxtFileCipher
12
12
  :members:
13
13
 
14
- .. autoclass:: python_plugins.crypto.zip7mix.Zip7Mix
15
- :members:
16
-
17
14
  .. autoclass:: python_plugins.crypto.tarmix.TarMix
18
15
  :members:
@@ -0,0 +1,13 @@
1
+ ============
2
+ sqlalchemy
3
+ ============
4
+
5
+ .. code-block:: python
6
+
7
+ from python_plugins.sqla import db
8
+ from python_plugins.sqla.mixins import PrimaryKeyMixin
9
+ from python_plugins.sqla.mixins import DataMixin
10
+ from python_plugins.sqla.mixins import TimestampMixin
11
+
12
+ class MyModel(db.Model,PrimaryKeyMixin, DataMixin, TimestampMixin):
13
+ __tablename__ = "my_model"
@@ -24,16 +24,13 @@ classifiers = [
24
24
  ]
25
25
  requires-python = ">=3.10"
26
26
  dependencies = [
27
- "cryptography>=44.0",
27
+ "Flask>=3.1",
28
+ "WTForms>=3.2",
29
+ "SQLAlchemy>=2.0",
30
+ "requests>=2.32",
31
+ "cryptography>=46.0",
28
32
  ]
29
33
 
30
- [project.optional-dependencies]
31
- requests = ["requests"]
32
- sqlalchemy = ["SQLAlchemy"]
33
- pillow = ["pillow"]
34
- qrcode = ["qrcode"]
35
- jwt = ["PyJWT"]
36
-
37
34
  [project.urls]
38
35
  Documentation = "https://python-plugins.readthedocs.io"
39
36
  Source = "https://github.com/ojso/python-plugins"
@@ -0,0 +1,2 @@
1
+ pytest
2
+ Faker
@@ -0,0 +1 @@
1
+ PyJWT
@@ -0,0 +1 @@
1
+ __version__ = "1.0.3"
@@ -21,7 +21,7 @@ class Zip7Mix(MixByte):
21
21
  def compress(self, file_or_dir, archive_path=None, pwd=None, silent=True):
22
22
  """
23
23
  examples::
24
-
24
+
25
25
  compress("myfile.txt") # output to myfile.txt.7z
26
26
  compress("myfolder") # output to myfolder.7z
27
27
  compress("myfile.txt", "archive.7z", pwd="mypassword")
@@ -70,7 +70,7 @@ class Zip7Mix(MixByte):
70
70
  ):
71
71
  """
72
72
  Examples::
73
-
73
+
74
74
  uncompress("archive.7z") # output to folder archive_extracted
75
75
  uncompress("archive.7z", "output_folder") # output to output_folder
76
76
  uncompress("archive.7z", pwd="mypassword")
@@ -152,3 +152,13 @@ class Zip7Mix(MixByte):
152
152
  archive_path=archive_path, output_path=output_path, pwd=pwd
153
153
  )
154
154
  return result
155
+
156
+ def unpwd(self, archive_path):
157
+ file_size = op.getsize(archive_path)
158
+ with open(archive_path, "rb") as f:
159
+ if file_size > 1000:
160
+ f.seek(-1000, os.SEEK_END)
161
+ data = f.read()
162
+ parse_result = self.parse_tail_link_blocks(data)
163
+ pwd = parse_result["pwd"].decode("utf-8")
164
+ return pwd
@@ -0,0 +1,3 @@
1
+ from .db import Db
2
+
3
+ db = Db()
@@ -0,0 +1,96 @@
1
+ from flask import Flask
2
+ from flask import current_app
3
+ from flask import g
4
+ from sqlalchemy import create_engine
5
+ from sqlalchemy.orm import sessionmaker
6
+ from sqlalchemy.orm import scoped_session
7
+ from sqlalchemy.orm import DeclarativeBase
8
+
9
+
10
+ class Db:
11
+ Model = None
12
+ engine = None
13
+ session = None
14
+ Session = None
15
+
16
+ def __init__(self, app: Flask | None = None):
17
+ self.Model = self._make_declarative_base()
18
+ if app is not None:
19
+ self.init_app(app)
20
+
21
+ def _make_declarative_base(self):
22
+ class Base(DeclarativeBase):
23
+ pass
24
+
25
+ return Base
26
+
27
+ def init_session(self, url=None, echo=False):
28
+ """Initialize the database engine and session factory.
29
+ This method is used in non-Flask environments.
30
+ Examples:
31
+ db = Db()
32
+ db.init_session(url="sqlite:///mydb.sqlite", echo=True)
33
+ db.create_all()
34
+ with db.Session() as session:
35
+ # use the session here
36
+ session.add(some_object)
37
+ session.commit()
38
+ """
39
+ options = {"url": url or "sqlite:///:memory:"}
40
+ if echo:
41
+ options["echo"] = True
42
+ self.engine = create_engine(**options)
43
+ self.Session = sessionmaker(self.engine)
44
+
45
+ def init_app(self, app: Flask) -> None:
46
+ if "sqlalchemy" in app.extensions:
47
+ raise RuntimeError("A 'SQLAlchemy' instance has already been registered.")
48
+ app.extensions["sqlalchemy"] = self
49
+
50
+ # engine
51
+ engine_options = {
52
+ "url": app.config.get("SQLALCHEMY_DATABASE_URI", "sqlite:///:memory:")
53
+ }
54
+ if app.config.get("SQLALCHEMY_ECHO"):
55
+ engine_options["echo"] = True
56
+ self.engine = self._make_engine(engine_options)
57
+
58
+ # session
59
+ session_options = {"bind": self.engine}
60
+ self.session = self._make_scoped_session(session_options)
61
+ app.teardown_appcontext(self._remove_session)
62
+
63
+ # cli
64
+ app.shell_context_processor(self._add_models_to_shell)
65
+
66
+ def _make_engine(self, options: dict):
67
+ return create_engine(**options)
68
+
69
+ def _make_scoped_session(self, options):
70
+ session_factory = sessionmaker(**options)
71
+ return scoped_session(session_factory, scopefunc=self._get_app_g_id)
72
+
73
+ def _get_app_g_id(self) -> int:
74
+ return id(g._get_current_object())
75
+
76
+ def _remove_session(self, exception=None):
77
+ """Remove the current session at the end of the request."""
78
+ self.session.remove()
79
+
80
+ def _add_models_to_shell(self):
81
+ """Registered with :meth:`~flask.Flask.shell_context_processor`.
82
+ Adds the ``db`` instance and all model classes to ``flask shell``.
83
+ """
84
+ db = current_app.extensions["sqlalchemy"]
85
+ out = {m.class_.__name__: m.class_ for m in db.Model.registry.mappers}
86
+ out["db"] = db
87
+ return out
88
+
89
+ def create_all(self, **kwargs):
90
+ if "bind" not in kwargs:
91
+ kwargs["bind"] = self.engine
92
+ self.Model.metadata.create_all(**kwargs)
93
+
94
+ def reset_models(self):
95
+ self.Model.metadata.drop_all(self.engine)
96
+ self.Model.metadata.create_all(self.engine)
@@ -0,0 +1,48 @@
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
+ )
@@ -0,0 +1,114 @@
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
+ )
@@ -0,0 +1,19 @@
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
+
@@ -0,0 +1,161 @@
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
+
@@ -0,0 +1,16 @@
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]
@@ -0,0 +1,35 @@
1
+ from typing import Optional
2
+ from .. import db
3
+ from ..orm import Mapped
4
+ from ..orm import mapped_column
5
+
6
+ # see https://docs.sqlalchemy.org/en/20/orm/inheritance.html#single-inheritance
7
+ # see https://docs.sqlalchemy.org/en/20/orm/queryguide/_single_inheritance.html
8
+
9
+ class Employee(db.Model):
10
+ __tablename__ = "employee"
11
+ id: Mapped[int] = mapped_column(primary_key=True)
12
+ name: Mapped[str]
13
+ type: Mapped[str]
14
+
15
+ def __repr__(self):
16
+ return f"{self.__class__.__name__}({self.name!r})"
17
+
18
+ __mapper_args__ = {
19
+ "polymorphic_identity": "employee",
20
+ "polymorphic_on": "type",
21
+ }
22
+
23
+
24
+ class Manager(Employee):
25
+ manager_name: Mapped[str] = mapped_column(nullable=True)
26
+ __mapper_args__ = {
27
+ "polymorphic_identity": "manager",
28
+ }
29
+
30
+
31
+ class Engineer(Employee):
32
+ engineer_info: Mapped[str] = mapped_column(nullable=True)
33
+ __mapper_args__ = {
34
+ "polymorphic_identity": "engineer",
35
+ }