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.
- {python_plugins-1.0.2 → python_plugins-1.0.3}/CHANGES.rst +6 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/PKG-INFO +6 -12
- {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/api/crypto.rst +0 -3
- python_plugins-1.0.3/docs/api/sqlalchemy.rst +13 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/pyproject.toml +5 -8
- python_plugins-1.0.3/requirements/develop.in +2 -0
- python_plugins-1.0.3/requirements/example.in +1 -0
- python_plugins-1.0.3/src/python_plugins/__about__.py +1 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/zip7mix.py +12 -2
- python_plugins-1.0.3/src/python_plugins/sqla/__init__.py +3 -0
- python_plugins-1.0.3/src/python_plugins/sqla/db.py +96 -0
- python_plugins-1.0.3/src/python_plugins/sqla/models/association_proxy.py +48 -0
- python_plugins-1.0.3/src/python_plugins/sqla/models/demo.py +114 -0
- python_plugins-1.0.3/src/python_plugins/sqla/models/message.py +19 -0
- python_plugins-1.0.3/src/python_plugins/sqla/models/model1.py +161 -0
- python_plugins-1.0.3/src/python_plugins/sqla/models/multpk.py +16 -0
- python_plugins-1.0.3/src/python_plugins/sqla/models/polymorphic.py +35 -0
- python_plugins-1.0.3/src/python_plugins/sqla/models/relations.py +74 -0
- python_plugins-1.0.3/src/python_plugins/sqla/models/tree_node.py +17 -0
- python_plugins-1.0.3/src/python_plugins/sqla/orm.py +40 -0
- python_plugins-1.0.3/src/python_plugins/sqla/utils/__init__.py +10 -0
- python_plugins-1.0.3/src/python_plugins/sqla/utils/attr.py +110 -0
- python_plugins-1.0.3/src/python_plugins/sqla/utils/expression.py +9 -0
- python_plugins-1.0.3/src/python_plugins/sqla/utils/instance.py +12 -0
- python_plugins-1.0.3/src/python_plugins/sqla/utils/model.py +31 -0
- python_plugins-1.0.3/src/python_plugins/sqla/utils/stmt.py +34 -0
- python_plugins-1.0.3/src/python_plugins/sqla/utils/update.py +23 -0
- python_plugins-1.0.3/tests/sqla/__init__.py +9 -0
- python_plugins-1.0.3/tests/sqla/test_association_proxy.py +33 -0
- python_plugins-1.0.3/tests/sqla/test_db.py +39 -0
- python_plugins-1.0.3/tests/sqla/test_docs.py +9 -0
- python_plugins-1.0.3/tests/sqla/test_flask_db.py +58 -0
- python_plugins-1.0.3/tests/sqla/test_mult_pk.py +31 -0
- python_plugins-1.0.3/tests/sqla/test_polymorphic.py +37 -0
- python_plugins-1.0.3/tests/sqla/test_registry_mappers.py +5 -0
- python_plugins-1.0.3/tests/sqla/test_relation.py +44 -0
- python_plugins-1.0.3/tests/sqla/test_tree_node.py +26 -0
- python_plugins-1.0.3/tests/sqla/utils/__init__.py +0 -0
- python_plugins-1.0.3/tests/sqla/utils/test_create_table.py +36 -0
- python_plugins-1.0.3/tests/sqla/utils/test_inspect_mapper.py +188 -0
- python_plugins-1.0.3/tests/sqla/utils/test_primary_key.py +53 -0
- python_plugins-1.0.3/tests/sqla/utils/test_stmt_delete.py +84 -0
- python_plugins-1.0.2/docs/api/sqlalchemy.rst +0 -21
- python_plugins-1.0.2/requirements/develop.in +0 -6
- python_plugins-1.0.2/src/python_plugins/__about__.py +0 -1
- python_plugins-1.0.2/src/python_plugins/models/update.py +0 -33
- python_plugins-1.0.2/tests/test_sqlalchemy.py +0 -30
- {python_plugins-1.0.2 → python_plugins-1.0.3}/.github/workflows/release.yml +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/.gitignore +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/.readthedocs.yaml +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/LICENSE.rst +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/README.rst +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/Makefile +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/_static/style.css +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/api/email.rst +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/api/index.rst +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/api/ospath.rst +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/changes.rst +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/conf.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/index.rst +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/install.rst +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/make.bat +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/docs/requirements.txt +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/requirements/build.in +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/__init__.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/__init__.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/aes_cipher.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/mixbyte.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/pbkdf_fernet.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/simple_fernet.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/tarmix.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/crypto/txtfile_cipher.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/email/__init__.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/email/smtp.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/datetime.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/hashes.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/higher_order_functions.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/postgresql_dump.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/pretty.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/random_string.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/run_jwt.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/run_process.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/tkinter/calculate.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/examples/xml2dict.py +0 -0
- {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/ospath}/__init__.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/src/python_plugins/ospath/walk_remove.py +0 -0
- {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/sqla}/mixins/__init__.py +0 -0
- {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/sqla}/mixins/data_mixin.py +0 -0
- {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
- {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/sqla}/mixins/timestamp_mixin.py +0 -0
- {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/sqla}/mixins/token_minxin.py +0 -0
- {python_plugins-1.0.2/src/python_plugins/models → python_plugins-1.0.3/src/python_plugins/sqla}/mixins/user_minxin.py +0 -0
- {python_plugins-1.0.2/src/python_plugins/ospath → python_plugins-1.0.3/src/python_plugins/sqla/models}/__init__.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/__init__.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/conftest.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_aes_cipher.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_crypt_file.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_mixbyte.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_pbkdf_fernet.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_simple_fernet.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_tarmix.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/crypto/test_zip7mix.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/test_email.py +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/tmp/a.png +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/tmp/a.txt +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/tmp/test/test.txt +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/tmp/test.archive.mix +0 -0
- {python_plugins-1.0.2 → python_plugins-1.0.3}/tests/tmp/test.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-plugins
|
|
3
|
-
Version: 1.0.
|
|
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>=
|
|
42
|
-
|
|
43
|
-
Requires-Dist:
|
|
44
|
-
|
|
45
|
-
Requires-Dist:
|
|
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
|
|
@@ -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
|
-
"
|
|
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 @@
|
|
|
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,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
|
+
}
|