python-plugins 1.0.2__py3-none-any.whl → 1.0.3__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/crypto/zip7mix.py +12 -2
- python_plugins/sqla/__init__.py +3 -0
- python_plugins/sqla/db.py +96 -0
- python_plugins/sqla/models/association_proxy.py +48 -0
- python_plugins/sqla/models/demo.py +114 -0
- python_plugins/sqla/models/message.py +19 -0
- python_plugins/sqla/models/model1.py +161 -0
- python_plugins/sqla/models/multpk.py +16 -0
- python_plugins/sqla/models/polymorphic.py +35 -0
- python_plugins/sqla/models/relations.py +74 -0
- python_plugins/sqla/models/tree_node.py +17 -0
- python_plugins/sqla/orm.py +40 -0
- python_plugins/sqla/utils/__init__.py +10 -0
- python_plugins/sqla/utils/attr.py +110 -0
- python_plugins/sqla/utils/expression.py +9 -0
- python_plugins/sqla/utils/instance.py +12 -0
- python_plugins/sqla/utils/model.py +31 -0
- python_plugins/sqla/utils/stmt.py +34 -0
- python_plugins/sqla/utils/update.py +23 -0
- {python_plugins-1.0.2.dist-info → python_plugins-1.0.3.dist-info}/METADATA +6 -12
- python_plugins-1.0.3.dist-info/RECORD +53 -0
- {python_plugins-1.0.2.dist-info → python_plugins-1.0.3.dist-info}/WHEEL +1 -1
- python_plugins/models/update.py +0 -33
- python_plugins-1.0.2.dist-info/RECORD +0 -36
- /python_plugins/{models → sqla}/mixins/__init__.py +0 -0
- /python_plugins/{models → sqla}/mixins/data_mixin.py +0 -0
- /python_plugins/{models → sqla}/mixins/primary_key_mixin.py +0 -0
- /python_plugins/{models → sqla}/mixins/timestamp_mixin.py +0 -0
- /python_plugins/{models → sqla}/mixins/token_minxin.py +0 -0
- /python_plugins/{models → sqla}/mixins/user_minxin.py +0 -0
- /python_plugins/{models → sqla/models}/__init__.py +0 -0
- {python_plugins-1.0.2.dist-info → python_plugins-1.0.3.dist-info}/licenses/LICENSE.rst +0 -0
python_plugins/__about__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.0.
|
|
1
|
+
__version__ = "1.0.3"
|
python_plugins/crypto/zip7mix.py
CHANGED
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from typing import Set
|
|
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
|
+
|
|
12
|
+
|
|
13
|
+
class OneToManyParent(db.Model):
|
|
14
|
+
__tablename__ = "one_to_many_parent"
|
|
15
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
16
|
+
children: Mapped[List["ManyToOneChild"]] = relationship()
|
|
17
|
+
children2: Mapped[List["ManyToOneChild2"]] = relationship(back_populates="parent2")
|
|
18
|
+
children3: Mapped[Set["ManyToOneChild3"]] = relationship(back_populates="parent3")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ManyToOneChild(db.Model):
|
|
22
|
+
__tablename__ = "many_to_one_child1"
|
|
23
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
24
|
+
parent_id: Mapped[int] = mapped_column(ForeignKey("one_to_many_parent.id"))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ManyToOneChild2(db.Model):
|
|
28
|
+
__tablename__ = "many_to_one_child2"
|
|
29
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
30
|
+
parent_id: Mapped[int] = mapped_column(ForeignKey("one_to_many_parent.id"))
|
|
31
|
+
parent2: Mapped["OneToManyParent"] = relationship(back_populates="children2")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ManyToOneChild3(db.Model):
|
|
35
|
+
__tablename__ = "many_to_one_child3"
|
|
36
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
37
|
+
parent_id: Mapped[int] = mapped_column(ForeignKey("one_to_many_parent.id"))
|
|
38
|
+
parent3: Mapped["OneToManyParent"] = relationship(back_populates="children3")
|
|
39
|
+
|
|
40
|
+
class OneToOneParent(db.Model):
|
|
41
|
+
__tablename__ = "one_to_one_parent"
|
|
42
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
43
|
+
child: Mapped["OneToOneChild"] = relationship(back_populates="parent")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class OneToOneChild(db.Model):
|
|
47
|
+
__tablename__ = "one_to_one_child"
|
|
48
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
49
|
+
parent_id: Mapped[int] = mapped_column(ForeignKey("one_to_one_parent.id"))
|
|
50
|
+
parent: Mapped["OneToOneParent"] = relationship(back_populates="child")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
association_table = Table(
|
|
54
|
+
"many_to_many_association",
|
|
55
|
+
db.Model.metadata,
|
|
56
|
+
Column("left_id", Integer, ForeignKey("many_to_many_left.id"), primary_key=True),
|
|
57
|
+
Column("right_id", Integer, ForeignKey("many_to_many_right.id"), primary_key=True),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ManyToManyLeft(db.Model):
|
|
62
|
+
__tablename__ = "many_to_many_left"
|
|
63
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
64
|
+
rights: Mapped[List["ManyToManyRight"]] = relationship(
|
|
65
|
+
secondary=association_table, back_populates="lefts"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class ManyToManyRight(db.Model):
|
|
70
|
+
__tablename__ = "many_to_many_right"
|
|
71
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
72
|
+
lefts: Mapped[List["ManyToManyLeft"]] = relationship(
|
|
73
|
+
secondary=association_table, back_populates="rights"
|
|
74
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from .. import db
|
|
2
|
+
from ..orm import ForeignKey
|
|
3
|
+
from ..orm import Mapped
|
|
4
|
+
from ..orm import mapped_column
|
|
5
|
+
from ..orm import relationship
|
|
6
|
+
|
|
7
|
+
# Adjacency List Relationships
|
|
8
|
+
# see https://docs.sqlalchemy.org/en/20/orm/self_referential.html
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TreeNode(db.Model):
|
|
12
|
+
__tablename__ = "tree_node"
|
|
13
|
+
id: Mapped[int] = mapped_column(primary_key=True)
|
|
14
|
+
parent_id = mapped_column(ForeignKey("tree_node.id"))
|
|
15
|
+
data: Mapped[str]
|
|
16
|
+
children = relationship("TreeNode", back_populates="parent")
|
|
17
|
+
parent = relationship("TreeNode", back_populates="children", remote_side=[id])
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from sqlalchemy.types import Integer
|
|
2
|
+
from sqlalchemy.types import Boolean
|
|
3
|
+
from sqlalchemy.types import String
|
|
4
|
+
from sqlalchemy.types import TEXT
|
|
5
|
+
from sqlalchemy.types import Float
|
|
6
|
+
from sqlalchemy.types import DateTime
|
|
7
|
+
from sqlalchemy.types import Date
|
|
8
|
+
from sqlalchemy.types import Time
|
|
9
|
+
from sqlalchemy.types import LargeBinary
|
|
10
|
+
from sqlalchemy.types import JSON
|
|
11
|
+
from sqlalchemy.types import Enum
|
|
12
|
+
|
|
13
|
+
from sqlalchemy.sql import select
|
|
14
|
+
from sqlalchemy.sql import delete
|
|
15
|
+
from sqlalchemy.sql import func
|
|
16
|
+
from sqlalchemy.sql import cast
|
|
17
|
+
from sqlalchemy.sql import text
|
|
18
|
+
from sqlalchemy.sql import and_
|
|
19
|
+
from sqlalchemy.sql import or_
|
|
20
|
+
from sqlalchemy.sql import not_
|
|
21
|
+
|
|
22
|
+
from sqlalchemy import Column
|
|
23
|
+
from sqlalchemy import Table
|
|
24
|
+
from sqlalchemy import ForeignKey
|
|
25
|
+
|
|
26
|
+
from sqlalchemy.orm import Mapped
|
|
27
|
+
from sqlalchemy.orm import mapped_column
|
|
28
|
+
from sqlalchemy.orm import relationship
|
|
29
|
+
from sqlalchemy.orm import composite
|
|
30
|
+
from sqlalchemy.orm import synonym
|
|
31
|
+
|
|
32
|
+
from sqlalchemy.orm import joinedload
|
|
33
|
+
from sqlalchemy.orm import selectinload
|
|
34
|
+
|
|
35
|
+
from sqlalchemy.ext.associationproxy import association_proxy
|
|
36
|
+
from sqlalchemy.ext.associationproxy import AssociationProxy
|
|
37
|
+
from sqlalchemy.ext.hybrid import hybrid_property
|
|
38
|
+
from sqlalchemy.ext.hybrid import hybrid_method
|
|
39
|
+
from sqlalchemy.ext.mutable import MutableDict
|
|
40
|
+
from sqlalchemy.ext.mutable import MutableList
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from .attr import is_column
|
|
2
|
+
from .attr import is_relationship
|
|
3
|
+
from .attr import is_hybrid
|
|
4
|
+
from .attr import is_association_proxy
|
|
5
|
+
from .attr import get_field_with_path
|
|
6
|
+
from .expression import parse_like_term
|
|
7
|
+
from .stmt import select_pk_values
|
|
8
|
+
from .stmt import clear
|
|
9
|
+
from .stmt import delete_by_pk_ids
|
|
10
|
+
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
from typing import Tuple, List
|
|
2
|
+
from sqlalchemy.orm import ColumnProperty
|
|
3
|
+
from sqlalchemy.orm import RelationshipProperty
|
|
4
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
|
5
|
+
from sqlalchemy.ext.hybrid import hybrid_property
|
|
6
|
+
from sqlalchemy.ext.associationproxy import AssociationProxy
|
|
7
|
+
|
|
8
|
+
def is_instrumented_attribute(attr):
|
|
9
|
+
return isinstance(attr, InstrumentedAttribute)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def is_column(attr):
|
|
13
|
+
return hasattr(attr, "property") and isinstance(attr.property, ColumnProperty)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def is_relationship(attr):
|
|
17
|
+
return hasattr(attr, "property") and isinstance(attr.property, RelationshipProperty)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def is_hybrid(attr):
|
|
21
|
+
return isinstance(attr, hybrid_property)
|
|
22
|
+
|
|
23
|
+
def is_association_proxy(attr):
|
|
24
|
+
return isinstance(attr, AssociationProxy)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_field_with_path(
|
|
28
|
+
model, path: str
|
|
29
|
+
) -> Tuple[InstrumentedAttribute, List[InstrumentedAttribute]]:
|
|
30
|
+
"""
|
|
31
|
+
Resolve a dot-separated field path (e.g., 'profile.contact.email')
|
|
32
|
+
starting from `model`, handling AssociationProxy and relationships.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
(final_attr, join_path)
|
|
36
|
+
- 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])
|
|
39
|
+
"""
|
|
40
|
+
print(model, path)
|
|
41
|
+
parts = path.split(".")
|
|
42
|
+
current_model = model
|
|
43
|
+
current_attr = None
|
|
44
|
+
join_path: List[InstrumentedAttribute] = []
|
|
45
|
+
|
|
46
|
+
for i, part in enumerate(parts):
|
|
47
|
+
attr = getattr(current_model, part)
|
|
48
|
+
# Case 1: Column (must be last)
|
|
49
|
+
if hasattr(attr, "property") and isinstance(attr.property, ColumnProperty):
|
|
50
|
+
if i != len(parts) - 1:
|
|
51
|
+
raise ValueError(
|
|
52
|
+
f"Column '{part}' cannot be followed by further path segments."
|
|
53
|
+
)
|
|
54
|
+
current_attr = attr
|
|
55
|
+
break
|
|
56
|
+
# Case 2: Relationship
|
|
57
|
+
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
|
+
join_path.append(attr)
|
|
64
|
+
current_model = attr.property.mapper.class_
|
|
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):
|
|
72
|
+
raise ValueError(
|
|
73
|
+
f"AssociationProxy '{part}' is not backed by a relationship "
|
|
74
|
+
f"(got {type(local_rel.property).__name__})."
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
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
|
+
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
|
|
101
|
+
break
|
|
102
|
+
else:
|
|
103
|
+
raise ValueError(
|
|
104
|
+
f"Unsupported attribute type for '{model}':'{part}': {type(attr)}"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
if current_attr is None:
|
|
108
|
+
raise RuntimeError("Failed to resolve path — no terminal attribute found.")
|
|
109
|
+
|
|
110
|
+
return current_attr, join_path
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from sqlalchemy import inspect
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_model_mapper(model):
|
|
5
|
+
"""
|
|
6
|
+
Return the mapper for a given model
|
|
7
|
+
"""
|
|
8
|
+
return inspect(model)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_primary_key(model):
|
|
12
|
+
"""
|
|
13
|
+
Return primary key name from a model. If the primary key consists of multiple columns,
|
|
14
|
+
return the corresponding tuple
|
|
15
|
+
"""
|
|
16
|
+
mapper = inspect(model)
|
|
17
|
+
pks = [col.name for col in mapper.primary_key]
|
|
18
|
+
if len(pks) == 1:
|
|
19
|
+
return pks[0]
|
|
20
|
+
elif len(pks) > 1:
|
|
21
|
+
return tuple(pks)
|
|
22
|
+
else:
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_model_tables(model):
|
|
27
|
+
"""
|
|
28
|
+
Return a set of table names that the model is mapped to
|
|
29
|
+
"""
|
|
30
|
+
mapper = inspect(model)
|
|
31
|
+
return mapper.tables
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from sqlalchemy import inspect
|
|
2
|
+
from sqlalchemy import select
|
|
3
|
+
from sqlalchemy import delete
|
|
4
|
+
from sqlalchemy import tuple_
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def select_pk_values(model):
|
|
8
|
+
"""
|
|
9
|
+
Return a select statement that selects all primary key values from a model
|
|
10
|
+
"""
|
|
11
|
+
mapper = inspect(model)
|
|
12
|
+
stmt = select(*mapper.primary_key)
|
|
13
|
+
return stmt
|
|
14
|
+
|
|
15
|
+
def clear(model):
|
|
16
|
+
"""
|
|
17
|
+
Return a delete statement that deletes all rows of the model
|
|
18
|
+
"""
|
|
19
|
+
stmt = delete(model)
|
|
20
|
+
return stmt
|
|
21
|
+
|
|
22
|
+
def delete_by_pk_ids(model, ids: list):
|
|
23
|
+
"""
|
|
24
|
+
Return a delete statement that deletes all rows with primary key in ids
|
|
25
|
+
"""
|
|
26
|
+
mapper = inspect(model)
|
|
27
|
+
primary_key = mapper.primary_key
|
|
28
|
+
if len(primary_key) == 1:
|
|
29
|
+
pk_col = primary_key[0]
|
|
30
|
+
stmt = delete(model).where(pk_col.in_(ids))
|
|
31
|
+
else:
|
|
32
|
+
stmt = delete(model).where(tuple_(*primary_key).in_(ids))
|
|
33
|
+
return stmt
|
|
34
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
def update_obj(session, Model, obj, data: dict):
|
|
2
|
+
"""insert or update object
|
|
3
|
+
|
|
4
|
+
:param session: sqlalchemy session
|
|
5
|
+
:param Model: object Model
|
|
6
|
+
:param obj: object of Model
|
|
7
|
+
:param data: data dict
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
if obj is None:
|
|
11
|
+
new_obj = Model()
|
|
12
|
+
for k in data:
|
|
13
|
+
if hasattr(new_obj, k):
|
|
14
|
+
setattr(new_obj, k, data.get(k))
|
|
15
|
+
session.add(new_obj)
|
|
16
|
+
session.commit()
|
|
17
|
+
print(f"{new_obj} inserted")
|
|
18
|
+
else:
|
|
19
|
+
for k in data:
|
|
20
|
+
if hasattr(obj, k):
|
|
21
|
+
setattr(obj, k, data.get(k))
|
|
22
|
+
session.commit()
|
|
23
|
+
print(f"{obj} updated")
|
|
@@ -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,53 @@
|
|
|
1
|
+
python_plugins/__about__.py,sha256=2plzdEEb24FLjE2I2XyBBcJEPYWHccNL4SgtLC_6erg,22
|
|
2
|
+
python_plugins/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
3
|
+
python_plugins/crypto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
python_plugins/crypto/aes_cipher.py,sha256=7lTvA01h3Z56riv7sB7CrZRh_OO66m21wVTVizU9PYg,1946
|
|
5
|
+
python_plugins/crypto/mixbyte.py,sha256=5re7W0-UuOjnnWW9HK50t6akLAbOtPmz9SQ3nq5w3hk,6649
|
|
6
|
+
python_plugins/crypto/pbkdf_fernet.py,sha256=8CGU4ddco6369NaoXodMKz_h8JMetHrZmMVt30XAICM,2049
|
|
7
|
+
python_plugins/crypto/simple_fernet.py,sha256=Yg5OXiXNcbyQ4EC31c58Vn00pbloGjJpscfbxn2L7YQ,1759
|
|
8
|
+
python_plugins/crypto/tarmix.py,sha256=DmTV-vNLTokUQJWn2H4QUSzfFjMQVrX2MiMpMd_BL0g,4874
|
|
9
|
+
python_plugins/crypto/txtfile_cipher.py,sha256=-mTkvQgtNYLUvrQLKTnepBBdkf-T0w-DnMfZ5wnbklU,4852
|
|
10
|
+
python_plugins/crypto/zip7mix.py,sha256=tQMmX_6ax99LXNfY8HBbu9EXSwQSgGOF3EwWEcrtdUo,5272
|
|
11
|
+
python_plugins/email/__init__.py,sha256=HubZT2h3m5WEjic3NZ0H7gYp-9tUgZaDkAE9O-Tm7hM,26
|
|
12
|
+
python_plugins/email/smtp.py,sha256=CY1fWxdBDqqGZ22R8yqEvFZvMeEsMnqTb4h5IZ8WAVU,1641
|
|
13
|
+
python_plugins/examples/datetime.py,sha256=bmC9d1W7XKA1ED9XO9reUiUyfQcM_BqGoGyOF21RW9A,282
|
|
14
|
+
python_plugins/examples/hashes.py,sha256=uSF3ohZRD7b2VAIvjjpTWC0SlY7QsFhsFZUejINrRGU,640
|
|
15
|
+
python_plugins/examples/higher_order_functions.py,sha256=vTfT3OEfuKkIW7UMD3JtreVDMeRbXHbjlz3G-j-J4x4,4574
|
|
16
|
+
python_plugins/examples/postgresql_dump.py,sha256=zN5aLYLxpon2y9_5gKizRjlrRUlkAO-dG-BuKpJ4F3U,1030
|
|
17
|
+
python_plugins/examples/pretty.py,sha256=igN4uq67AADcPOiy_h3_M-oEwgc1i3gJScbKtkf6d-k,211
|
|
18
|
+
python_plugins/examples/random_string.py,sha256=U7B-bAa4zEpewkd4_8KIPZ0XsPdbGlJ_FEj0FnTGdms,2210
|
|
19
|
+
python_plugins/examples/run_jwt.py,sha256=ZwjUXg5PKeophiXqwSaMlHrhwVKhHTsRb68HtkRLX8k,1485
|
|
20
|
+
python_plugins/examples/run_process.py,sha256=I_wjCqzWI6d39ebL-YArQ8LiXFQ3bwEoCnxJTZK1Zbc,780
|
|
21
|
+
python_plugins/examples/xml2dict.py,sha256=RUxqDt6NKzwbuodTxKVoiR4dP-vNbmL77dztLx_9UzY,164
|
|
22
|
+
python_plugins/examples/tkinter/calculate.py,sha256=M1b-w7-pVe-7FS3erBJxgFNfmm4lzP3zlK41glyhWx8,1142
|
|
23
|
+
python_plugins/ospath/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
python_plugins/ospath/walk_remove.py,sha256=rnDHr1wGSxufo2YV9_EXeVNEAnT4LGjG7-5dOI2gWY0,494
|
|
25
|
+
python_plugins/sqla/__init__.py,sha256=dJyZS1js_pdpAgLnsqfRFPQBFeZ8PdssdPfTzgie5c8,30
|
|
26
|
+
python_plugins/sqla/db.py,sha256=fA601WJ3QiUyXAQGwS72wa9S1b973T-HK1ZsE6OL0c0,3179
|
|
27
|
+
python_plugins/sqla/orm.py,sha256=7h0oY4TGfdrvAFKedVbKdWTvWHq_Sc-ycd2VvWiZJyo,1331
|
|
28
|
+
python_plugins/sqla/mixins/__init__.py,sha256=l4dJVgUFI7aISA7X-CcVBOp19rXBgqyyhHwtuQnSgR0,241
|
|
29
|
+
python_plugins/sqla/mixins/data_mixin.py,sha256=HCc1uvF6_O4yjK38uWAsqysEedLWgc7wtds3NjQTMZ8,366
|
|
30
|
+
python_plugins/sqla/mixins/primary_key_mixin.py,sha256=QUO-7ZmYtAMMi7ReRQDYV0uwQCnU9dvl6g6GHitYtlA,154
|
|
31
|
+
python_plugins/sqla/mixins/timestamp_mixin.py,sha256=u9rIu0IrzdCRRbnMk4IN4nTlNNiVPB8yPnTcHjQC1KU,547
|
|
32
|
+
python_plugins/sqla/mixins/token_minxin.py,sha256=SxNftZXS-hCwqxov7whF_tBtlayuoi3LUPtu-ofMmdg,276
|
|
33
|
+
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
|
|
45
|
+
python_plugins/sqla/utils/expression.py,sha256=_9P59Elc3jqdXFiXxkrRY9gsaUSum-chNMPbiqQcC58,202
|
|
46
|
+
python_plugins/sqla/utils/instance.py,sha256=EbcI3pQhsRj-mPW9ZHs0yQ4zMGVMHw-HtmmXHY15kK0,255
|
|
47
|
+
python_plugins/sqla/utils/model.py,sha256=R9ObqEMDOaYKLv8pcoDHoV7m4mxWHgEDiZ74NokMMjA,678
|
|
48
|
+
python_plugins/sqla/utils/stmt.py,sha256=3GzzEvi0RmvE3q-zBweol9LmsEQ0UPkn9G6P0epNwWw,876
|
|
49
|
+
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,,
|
python_plugins/models/update.py
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
def update_obj(db, old_obj, new_data: dict, NewClass, force=None):
|
|
2
|
-
"""insert or update object
|
|
3
|
-
|
|
4
|
-
:param db: sqlalchemy db
|
|
5
|
-
:param old_obj: old object
|
|
6
|
-
:param new_data: new dict
|
|
7
|
-
:param NewClass: object class
|
|
8
|
-
:param force: update= update old object with new attribute
|
|
9
|
-
"""
|
|
10
|
-
# 1. old is not exist
|
|
11
|
-
if old_obj is None:
|
|
12
|
-
new_obj = NewClass()
|
|
13
|
-
for k in new_data:
|
|
14
|
-
if hasattr(new_obj, k):
|
|
15
|
-
setattr(new_obj, k, new_data.get(k))
|
|
16
|
-
db.session.add(new_obj)
|
|
17
|
-
db.session.commit()
|
|
18
|
-
print(f"{new_obj} inserted")
|
|
19
|
-
return
|
|
20
|
-
|
|
21
|
-
# 2. old is exist
|
|
22
|
-
match force:
|
|
23
|
-
case None:
|
|
24
|
-
print(f"{old_obj} exists")
|
|
25
|
-
case "update":
|
|
26
|
-
# update old
|
|
27
|
-
for k in new_data:
|
|
28
|
-
if hasattr(old_obj, k):
|
|
29
|
-
setattr(old_obj, k, new_data.get(k))
|
|
30
|
-
db.session.commit()
|
|
31
|
-
print(f"{old_obj} updated")
|
|
32
|
-
case _:
|
|
33
|
-
raise Exception
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
python_plugins/__about__.py,sha256=Y3LSfRioSl2xch70pq_ULlvyECXyEtN3krVaWeGyaxk,22
|
|
2
|
-
python_plugins/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
3
|
-
python_plugins/crypto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
python_plugins/crypto/aes_cipher.py,sha256=7lTvA01h3Z56riv7sB7CrZRh_OO66m21wVTVizU9PYg,1946
|
|
5
|
-
python_plugins/crypto/mixbyte.py,sha256=5re7W0-UuOjnnWW9HK50t6akLAbOtPmz9SQ3nq5w3hk,6649
|
|
6
|
-
python_plugins/crypto/pbkdf_fernet.py,sha256=8CGU4ddco6369NaoXodMKz_h8JMetHrZmMVt30XAICM,2049
|
|
7
|
-
python_plugins/crypto/simple_fernet.py,sha256=Yg5OXiXNcbyQ4EC31c58Vn00pbloGjJpscfbxn2L7YQ,1759
|
|
8
|
-
python_plugins/crypto/tarmix.py,sha256=DmTV-vNLTokUQJWn2H4QUSzfFjMQVrX2MiMpMd_BL0g,4874
|
|
9
|
-
python_plugins/crypto/txtfile_cipher.py,sha256=-mTkvQgtNYLUvrQLKTnepBBdkf-T0w-DnMfZ5wnbklU,4852
|
|
10
|
-
python_plugins/crypto/zip7mix.py,sha256=x5_N3k6Wr-71Z3cqmPIWqVmzikR7O65xeSr-A42w_Y0,4933
|
|
11
|
-
python_plugins/email/__init__.py,sha256=HubZT2h3m5WEjic3NZ0H7gYp-9tUgZaDkAE9O-Tm7hM,26
|
|
12
|
-
python_plugins/email/smtp.py,sha256=CY1fWxdBDqqGZ22R8yqEvFZvMeEsMnqTb4h5IZ8WAVU,1641
|
|
13
|
-
python_plugins/examples/datetime.py,sha256=bmC9d1W7XKA1ED9XO9reUiUyfQcM_BqGoGyOF21RW9A,282
|
|
14
|
-
python_plugins/examples/hashes.py,sha256=uSF3ohZRD7b2VAIvjjpTWC0SlY7QsFhsFZUejINrRGU,640
|
|
15
|
-
python_plugins/examples/higher_order_functions.py,sha256=vTfT3OEfuKkIW7UMD3JtreVDMeRbXHbjlz3G-j-J4x4,4574
|
|
16
|
-
python_plugins/examples/postgresql_dump.py,sha256=zN5aLYLxpon2y9_5gKizRjlrRUlkAO-dG-BuKpJ4F3U,1030
|
|
17
|
-
python_plugins/examples/pretty.py,sha256=igN4uq67AADcPOiy_h3_M-oEwgc1i3gJScbKtkf6d-k,211
|
|
18
|
-
python_plugins/examples/random_string.py,sha256=U7B-bAa4zEpewkd4_8KIPZ0XsPdbGlJ_FEj0FnTGdms,2210
|
|
19
|
-
python_plugins/examples/run_jwt.py,sha256=ZwjUXg5PKeophiXqwSaMlHrhwVKhHTsRb68HtkRLX8k,1485
|
|
20
|
-
python_plugins/examples/run_process.py,sha256=I_wjCqzWI6d39ebL-YArQ8LiXFQ3bwEoCnxJTZK1Zbc,780
|
|
21
|
-
python_plugins/examples/xml2dict.py,sha256=RUxqDt6NKzwbuodTxKVoiR4dP-vNbmL77dztLx_9UzY,164
|
|
22
|
-
python_plugins/examples/tkinter/calculate.py,sha256=M1b-w7-pVe-7FS3erBJxgFNfmm4lzP3zlK41glyhWx8,1142
|
|
23
|
-
python_plugins/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
-
python_plugins/models/update.py,sha256=cIwhR0iKkB7cVx7km_oA9ya97MSkJlLPb8pZWaEePmE,991
|
|
25
|
-
python_plugins/models/mixins/__init__.py,sha256=l4dJVgUFI7aISA7X-CcVBOp19rXBgqyyhHwtuQnSgR0,241
|
|
26
|
-
python_plugins/models/mixins/data_mixin.py,sha256=HCc1uvF6_O4yjK38uWAsqysEedLWgc7wtds3NjQTMZ8,366
|
|
27
|
-
python_plugins/models/mixins/primary_key_mixin.py,sha256=QUO-7ZmYtAMMi7ReRQDYV0uwQCnU9dvl6g6GHitYtlA,154
|
|
28
|
-
python_plugins/models/mixins/timestamp_mixin.py,sha256=u9rIu0IrzdCRRbnMk4IN4nTlNNiVPB8yPnTcHjQC1KU,547
|
|
29
|
-
python_plugins/models/mixins/token_minxin.py,sha256=SxNftZXS-hCwqxov7whF_tBtlayuoi3LUPtu-ofMmdg,276
|
|
30
|
-
python_plugins/models/mixins/user_minxin.py,sha256=D-N45bunicBuuwKs--s_tyDxxLC3mkxV9Tva8JAhsko,579
|
|
31
|
-
python_plugins/ospath/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
|
-
python_plugins/ospath/walk_remove.py,sha256=rnDHr1wGSxufo2YV9_EXeVNEAnT4LGjG7-5dOI2gWY0,494
|
|
33
|
-
python_plugins-1.0.2.dist-info/METADATA,sha256=KusHRGLBBQ9p_y9Ttu9q9Y1p_8WM_kBuPc1bSP8QgQk,2840
|
|
34
|
-
python_plugins-1.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
35
|
-
python_plugins-1.0.2.dist-info/licenses/LICENSE.rst,sha256=X5eLIsAn1yAKd88LWTYkXUe0PmVK_Z5SD7_5NheGR-s,1104
|
|
36
|
-
python_plugins-1.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|