python-plugins 1.0.2__py3-none-any.whl → 1.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- python_plugins/__about__.py +1 -1
- python_plugins/crypto/zip7mix.py +12 -2
- python_plugins/examples/sphinx_google_style.py +311 -0
- python_plugins/examples/sphinx_numpy_style.py +351 -0
- python_plugins/ospath/walk.py +31 -0
- python_plugins/sqla/__init__.py +3 -0
- python_plugins/sqla/db.py +97 -0
- python_plugins/sqla/orm.py +40 -0
- python_plugins/sqla/utils/__init__.py +10 -0
- python_plugins/sqla/utils/attr.py +85 -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/paginate.py +74 -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.4.dist-info}/METADATA +6 -12
- python_plugins-1.0.4.dist-info/RECORD +48 -0
- {python_plugins-1.0.2.dist-info → python_plugins-1.0.4.dist-info}/WHEEL +1 -1
- python_plugins/models/update.py +0 -33
- python_plugins/ospath/walk_remove.py +0 -19
- python_plugins-1.0.2.dist-info/RECORD +0 -36
- /python_plugins/{models → examples}/__init__.py +0 -0
- /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-1.0.2.dist-info → python_plugins-1.0.4.dist-info}/licenses/LICENSE.rst +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def remove(dir, dirname):
|
|
6
|
+
for root, dirs, files in os.walk(dir):
|
|
7
|
+
if "venv" in root or "git" in root:
|
|
8
|
+
continue
|
|
9
|
+
for dir in dirs:
|
|
10
|
+
if dir == dirname:
|
|
11
|
+
rm_path = os.path.join(root, dir)
|
|
12
|
+
print(f"Removing {rm_path}")
|
|
13
|
+
shutil.rmtree(rm_path)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def remove_pycache(dir="."):
|
|
17
|
+
remove(dir, "__pycache__")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def remove_ipynb_checkpoints(dir="."):
|
|
21
|
+
remove(dir, ".ipynb_checkpoints")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def find_empty_dirs(dir="."):
|
|
25
|
+
for root, dirs, files in os.walk(dir):
|
|
26
|
+
if "venv" in root or "git" in root:
|
|
27
|
+
continue
|
|
28
|
+
for dir in dirs:
|
|
29
|
+
dir_path = os.path.join(root, dir)
|
|
30
|
+
if not os.listdir(dir_path):
|
|
31
|
+
print(f"Empty dir: {dir_path}")
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from flask import Flask
|
|
2
|
+
from flask import current_app
|
|
3
|
+
from flask import has_request_context
|
|
4
|
+
from flask import g
|
|
5
|
+
from sqlalchemy import create_engine
|
|
6
|
+
from sqlalchemy.orm import sessionmaker
|
|
7
|
+
from sqlalchemy.orm import scoped_session
|
|
8
|
+
from sqlalchemy.orm import DeclarativeBase
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Db:
|
|
12
|
+
Model = None
|
|
13
|
+
engine = None
|
|
14
|
+
session = None
|
|
15
|
+
Session = None
|
|
16
|
+
|
|
17
|
+
def __init__(self, app: Flask | None = None):
|
|
18
|
+
self.Model = self._make_declarative_base()
|
|
19
|
+
if app is not None:
|
|
20
|
+
self.init_app(app)
|
|
21
|
+
|
|
22
|
+
def _make_declarative_base(self):
|
|
23
|
+
class Base(DeclarativeBase):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
return Base
|
|
27
|
+
|
|
28
|
+
def init_session(self, url=None, echo=False):
|
|
29
|
+
"""Initialize the database engine and session factory.
|
|
30
|
+
This method is used in non-Flask environments.
|
|
31
|
+
Examples:
|
|
32
|
+
db = Db()
|
|
33
|
+
db.init_session(url="sqlite:///mydb.sqlite", echo=True)
|
|
34
|
+
db.create_all()
|
|
35
|
+
with db.Session() as session:
|
|
36
|
+
# use the session here
|
|
37
|
+
session.add(some_object)
|
|
38
|
+
session.commit()
|
|
39
|
+
"""
|
|
40
|
+
options = {"url": url or "sqlite:///:memory:"}
|
|
41
|
+
if echo:
|
|
42
|
+
options["echo"] = True
|
|
43
|
+
self.engine = create_engine(**options)
|
|
44
|
+
self.Session = sessionmaker(self.engine)
|
|
45
|
+
|
|
46
|
+
def init_app(self, app: Flask) -> None:
|
|
47
|
+
if "sqlalchemy" in app.extensions:
|
|
48
|
+
raise RuntimeError("A 'SQLAlchemy' instance has already been registered.")
|
|
49
|
+
app.extensions["sqlalchemy"] = self
|
|
50
|
+
|
|
51
|
+
# engine
|
|
52
|
+
engine_options = {
|
|
53
|
+
"url": app.config.get("SQLALCHEMY_DATABASE_URI", "sqlite:///:memory:")
|
|
54
|
+
}
|
|
55
|
+
if app.config.get("SQLALCHEMY_ECHO"):
|
|
56
|
+
engine_options["echo"] = True
|
|
57
|
+
self.engine = self._make_engine(engine_options)
|
|
58
|
+
|
|
59
|
+
# session
|
|
60
|
+
session_options = {"bind": self.engine}
|
|
61
|
+
self.session = self._make_scoped_session(session_options)
|
|
62
|
+
app.teardown_appcontext(self._remove_session)
|
|
63
|
+
|
|
64
|
+
# cli
|
|
65
|
+
app.shell_context_processor(self._add_models_to_shell)
|
|
66
|
+
|
|
67
|
+
def _make_engine(self, options: dict):
|
|
68
|
+
return create_engine(**options)
|
|
69
|
+
|
|
70
|
+
def _make_scoped_session(self, options):
|
|
71
|
+
session_factory = sessionmaker(**options)
|
|
72
|
+
return scoped_session(session_factory, scopefunc=self._get_scope_id)
|
|
73
|
+
|
|
74
|
+
def _get_scope_id(self) -> int:
|
|
75
|
+
return id(g._get_current_object())
|
|
76
|
+
|
|
77
|
+
def _remove_session(self, exception=None):
|
|
78
|
+
"""Remove the current session at the end of the request."""
|
|
79
|
+
self.session.remove()
|
|
80
|
+
|
|
81
|
+
def _add_models_to_shell(self):
|
|
82
|
+
"""Registered with :meth:`~flask.Flask.shell_context_processor`.
|
|
83
|
+
Adds the ``db`` instance and all model classes to ``flask shell``.
|
|
84
|
+
"""
|
|
85
|
+
db = current_app.extensions["sqlalchemy"]
|
|
86
|
+
out = {m.class_.__name__: m.class_ for m in db.Model.registry.mappers}
|
|
87
|
+
out["db"] = db
|
|
88
|
+
return out
|
|
89
|
+
|
|
90
|
+
def create_all(self, **kwargs):
|
|
91
|
+
if "bind" not in kwargs:
|
|
92
|
+
kwargs["bind"] = self.engine
|
|
93
|
+
self.Model.metadata.create_all(**kwargs)
|
|
94
|
+
|
|
95
|
+
def reset_models(self):
|
|
96
|
+
self.Model.metadata.drop_all(self.engine)
|
|
97
|
+
self.Model.metadata.create_all(self.engine)
|
|
@@ -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_property
|
|
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,85 @@
|
|
|
1
|
+
from typing import Tuple, List
|
|
2
|
+
from sqlalchemy import inspect
|
|
3
|
+
from sqlalchemy.orm import ColumnProperty
|
|
4
|
+
from sqlalchemy.orm import RelationshipProperty
|
|
5
|
+
from sqlalchemy.orm.attributes import InstrumentedAttribute
|
|
6
|
+
from sqlalchemy.ext.hybrid import hybrid_property
|
|
7
|
+
from sqlalchemy.ext.associationproxy import AssociationProxy
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def is_instrumented_attribute(attr):
|
|
11
|
+
return isinstance(attr, InstrumentedAttribute)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def is_column(attr):
|
|
15
|
+
return hasattr(attr, "property") and isinstance(attr.property, ColumnProperty)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def is_relationship(attr):
|
|
19
|
+
return hasattr(attr, "property") and isinstance(attr.property, RelationshipProperty)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def is_hybrid_property(model, attr_name):
|
|
23
|
+
mapper = inspect(model)
|
|
24
|
+
descriptor = mapper.all_orm_descriptors.get(attr_name)
|
|
25
|
+
return isinstance(descriptor, hybrid_property)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def is_association_proxy(model, attr_name):
|
|
29
|
+
mapper = inspect(model)
|
|
30
|
+
descriptor = mapper.all_orm_descriptors.get(attr_name)
|
|
31
|
+
return isinstance(descriptor, AssociationProxy)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_field_with_path(
|
|
35
|
+
model, name: str
|
|
36
|
+
) -> Tuple[InstrumentedAttribute, List[InstrumentedAttribute]]:
|
|
37
|
+
"""
|
|
38
|
+
Resolve a dot-separated field path (e.g., 'profile.contact.email')
|
|
39
|
+
starting from `model`, handling columns and relationships.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
(final_attr, join_path)
|
|
43
|
+
- final_attr: The terminal InstrumentedAttribute (e.g., Contact.email)
|
|
44
|
+
- join_path: List of relationship attributes for explicit joins (e.g., [User.profile, Profile.contact])
|
|
45
|
+
"""
|
|
46
|
+
final_attr = None
|
|
47
|
+
join_path: List[InstrumentedAttribute] = []
|
|
48
|
+
|
|
49
|
+
parts = name.split(".")
|
|
50
|
+
current_model = model
|
|
51
|
+
for i, part in enumerate(parts):
|
|
52
|
+
attr = getattr(current_model, part)
|
|
53
|
+
# Case 1: Column (must be last)
|
|
54
|
+
if is_column(attr):
|
|
55
|
+
if i != len(parts) - 1:
|
|
56
|
+
raise ValueError(
|
|
57
|
+
f"Column '{part}' cannot be followed by further path segments."
|
|
58
|
+
)
|
|
59
|
+
final_attr = attr
|
|
60
|
+
break
|
|
61
|
+
# Case 2: Relationship
|
|
62
|
+
elif is_relationship(attr):
|
|
63
|
+
join_path.append(attr)
|
|
64
|
+
current_model = attr.property.mapper.class_
|
|
65
|
+
# Case 3: AssociationProxy
|
|
66
|
+
elif is_association_proxy(current_model, part):
|
|
67
|
+
if i != len(parts) - 1:
|
|
68
|
+
raise ValueError(
|
|
69
|
+
f"AssociationProxy '{part}' cannot be followed by further path segments."
|
|
70
|
+
)
|
|
71
|
+
# Step into the underlying relationship
|
|
72
|
+
local_rel = attr.local_attr
|
|
73
|
+
join_path.append(local_rel)
|
|
74
|
+
remote_attr = attr.remote_attr
|
|
75
|
+
final_attr = remote_attr
|
|
76
|
+
break
|
|
77
|
+
else:
|
|
78
|
+
raise ValueError(
|
|
79
|
+
f"Unsupported attribute type for '{model}':'{part}': {type(attr)}"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
if final_attr is None:
|
|
83
|
+
raise RuntimeError("Failed to resolve path — no terminal attribute found.")
|
|
84
|
+
|
|
85
|
+
return final_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,74 @@
|
|
|
1
|
+
from math import ceil
|
|
2
|
+
from typing import Any, Optional, Generic, TypeVar, Iterator
|
|
3
|
+
from sqlalchemy.sql import Select
|
|
4
|
+
from sqlalchemy.sql import select,func
|
|
5
|
+
from sqlalchemy.orm import Session
|
|
6
|
+
|
|
7
|
+
T = TypeVar("T")
|
|
8
|
+
|
|
9
|
+
class Pagination(Generic[T]):
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
items: list[T],
|
|
13
|
+
total: int,
|
|
14
|
+
page: int,
|
|
15
|
+
per_page: int,
|
|
16
|
+
):
|
|
17
|
+
self.items = items
|
|
18
|
+
self.total = total
|
|
19
|
+
self.page = page
|
|
20
|
+
self.per_page = per_page
|
|
21
|
+
self.pages = ceil(total / per_page) if per_page > 0 else 0
|
|
22
|
+
self.has_prev = page > 1
|
|
23
|
+
self.has_next = page < self.pages
|
|
24
|
+
self.prev_num = page - 1 if self.has_prev else None
|
|
25
|
+
self.next_num = page + 1 if self.has_next else None
|
|
26
|
+
|
|
27
|
+
def iter_pages(self) -> Iterator[int]:
|
|
28
|
+
"""Iterate over page numbers for pagination controls."""
|
|
29
|
+
return iter(range(1, self.pages + 1))
|
|
30
|
+
|
|
31
|
+
def __repr__(self):
|
|
32
|
+
return f"<Pagination page={self.page} of {self.pages}>"
|
|
33
|
+
|
|
34
|
+
def paginate(
|
|
35
|
+
session: Session,
|
|
36
|
+
stmt: Select,
|
|
37
|
+
*,
|
|
38
|
+
page: int = 1,
|
|
39
|
+
per_page: int = 20,
|
|
40
|
+
) -> Pagination:
|
|
41
|
+
"""
|
|
42
|
+
Paginate a SQLAlchemy 2.0 select statement.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
session: SQLAlchemy Session instance
|
|
46
|
+
stmt: A SQLAlchemy Select statement (e.g., select(User))
|
|
47
|
+
page: Current page number (1-indexed)
|
|
48
|
+
per_page: Number of items per page
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Pagination object with .items, .total, .has_next, etc.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
# Count total rows
|
|
55
|
+
count_stmt = select(func.count()).select_from(stmt.subquery())
|
|
56
|
+
total = session.execute(count_stmt).scalar_one()
|
|
57
|
+
|
|
58
|
+
if total == 0:
|
|
59
|
+
return Pagination(items=[], total=0, page=page, per_page=per_page)
|
|
60
|
+
|
|
61
|
+
if page < 1:
|
|
62
|
+
# raise ValueError("Page must be >= 1")
|
|
63
|
+
page = 1
|
|
64
|
+
|
|
65
|
+
pages = ceil(total / per_page)
|
|
66
|
+
if page > pages:
|
|
67
|
+
# raise ValueError(f"Page {page} is out of range (total pages: {pages})")
|
|
68
|
+
page = pages
|
|
69
|
+
|
|
70
|
+
# Apply limit/offset
|
|
71
|
+
paginated_stmt = stmt.offset((page - 1) * per_page).limit(per_page)
|
|
72
|
+
items = session.execute(paginated_stmt).scalars().all()
|
|
73
|
+
|
|
74
|
+
return Pagination(items=items, total=total, page=page, per_page=per_page)
|
|
@@ -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.4
|
|
4
4
|
Summary: A collection of Python functions and classes.
|
|
5
5
|
Project-URL: Documentation, https://python-plugins.readthedocs.io
|
|
6
6
|
Project-URL: Source, https://github.com/ojso/python-plugins
|
|
@@ -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,48 @@
|
|
|
1
|
+
python_plugins/__about__.py,sha256=acuR_XSJzp4OrQ5T8-Ac5gYe48mUwObuwjRmisFmZ7k,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/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
python_plugins/examples/datetime.py,sha256=bmC9d1W7XKA1ED9XO9reUiUyfQcM_BqGoGyOF21RW9A,282
|
|
15
|
+
python_plugins/examples/hashes.py,sha256=uSF3ohZRD7b2VAIvjjpTWC0SlY7QsFhsFZUejINrRGU,640
|
|
16
|
+
python_plugins/examples/higher_order_functions.py,sha256=vTfT3OEfuKkIW7UMD3JtreVDMeRbXHbjlz3G-j-J4x4,4574
|
|
17
|
+
python_plugins/examples/postgresql_dump.py,sha256=zN5aLYLxpon2y9_5gKizRjlrRUlkAO-dG-BuKpJ4F3U,1030
|
|
18
|
+
python_plugins/examples/pretty.py,sha256=igN4uq67AADcPOiy_h3_M-oEwgc1i3gJScbKtkf6d-k,211
|
|
19
|
+
python_plugins/examples/random_string.py,sha256=U7B-bAa4zEpewkd4_8KIPZ0XsPdbGlJ_FEj0FnTGdms,2210
|
|
20
|
+
python_plugins/examples/run_jwt.py,sha256=ZwjUXg5PKeophiXqwSaMlHrhwVKhHTsRb68HtkRLX8k,1485
|
|
21
|
+
python_plugins/examples/run_process.py,sha256=I_wjCqzWI6d39ebL-YArQ8LiXFQ3bwEoCnxJTZK1Zbc,780
|
|
22
|
+
python_plugins/examples/sphinx_google_style.py,sha256=TJuxBqXG3OtZHmlbLlCRD07ADs1QImOhZu33HksSgKM,9688
|
|
23
|
+
python_plugins/examples/sphinx_numpy_style.py,sha256=jhtOp7fiQcbtj-dUufloPQlV4vAKwlAlRgw8r6rxVgw,9735
|
|
24
|
+
python_plugins/examples/xml2dict.py,sha256=RUxqDt6NKzwbuodTxKVoiR4dP-vNbmL77dztLx_9UzY,164
|
|
25
|
+
python_plugins/examples/tkinter/calculate.py,sha256=M1b-w7-pVe-7FS3erBJxgFNfmm4lzP3zlK41glyhWx8,1142
|
|
26
|
+
python_plugins/ospath/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
+
python_plugins/ospath/walk.py,sha256=zj8616KtK4bduJyuyw2b7bg6udV_-ssEAGPLJblhPlM,792
|
|
28
|
+
python_plugins/sqla/__init__.py,sha256=dJyZS1js_pdpAgLnsqfRFPQBFeZ8PdssdPfTzgie5c8,30
|
|
29
|
+
python_plugins/sqla/db.py,sha256=rW0x7U0d3oqhZSL2GbxTEtyy83neGogt5VUNTnJadnA,3217
|
|
30
|
+
python_plugins/sqla/orm.py,sha256=7h0oY4TGfdrvAFKedVbKdWTvWHq_Sc-ycd2VvWiZJyo,1331
|
|
31
|
+
python_plugins/sqla/mixins/__init__.py,sha256=l4dJVgUFI7aISA7X-CcVBOp19rXBgqyyhHwtuQnSgR0,241
|
|
32
|
+
python_plugins/sqla/mixins/data_mixin.py,sha256=HCc1uvF6_O4yjK38uWAsqysEedLWgc7wtds3NjQTMZ8,366
|
|
33
|
+
python_plugins/sqla/mixins/primary_key_mixin.py,sha256=QUO-7ZmYtAMMi7ReRQDYV0uwQCnU9dvl6g6GHitYtlA,154
|
|
34
|
+
python_plugins/sqla/mixins/timestamp_mixin.py,sha256=u9rIu0IrzdCRRbnMk4IN4nTlNNiVPB8yPnTcHjQC1KU,547
|
|
35
|
+
python_plugins/sqla/mixins/token_minxin.py,sha256=SxNftZXS-hCwqxov7whF_tBtlayuoi3LUPtu-ofMmdg,276
|
|
36
|
+
python_plugins/sqla/mixins/user_minxin.py,sha256=D-N45bunicBuuwKs--s_tyDxxLC3mkxV9Tva8JAhsko,579
|
|
37
|
+
python_plugins/sqla/utils/__init__.py,sha256=sHrgAp1TJ3k02gbhMIf2or9IzI7in1P70PqqhFNhBUY,311
|
|
38
|
+
python_plugins/sqla/utils/attr.py,sha256=R6ehESBt3G-ukfczmqoKb9BiWdS0AC9uz2y0OZgzjQE,2947
|
|
39
|
+
python_plugins/sqla/utils/expression.py,sha256=_9P59Elc3jqdXFiXxkrRY9gsaUSum-chNMPbiqQcC58,202
|
|
40
|
+
python_plugins/sqla/utils/instance.py,sha256=EbcI3pQhsRj-mPW9ZHs0yQ4zMGVMHw-HtmmXHY15kK0,255
|
|
41
|
+
python_plugins/sqla/utils/model.py,sha256=R9ObqEMDOaYKLv8pcoDHoV7m4mxWHgEDiZ74NokMMjA,678
|
|
42
|
+
python_plugins/sqla/utils/paginate.py,sha256=Fqqb3N6HAdSD4OXvu62XgmIQp1eUAY0ODS4e3e_gtWQ,2186
|
|
43
|
+
python_plugins/sqla/utils/stmt.py,sha256=3GzzEvi0RmvE3q-zBweol9LmsEQ0UPkn9G6P0epNwWw,876
|
|
44
|
+
python_plugins/sqla/utils/update.py,sha256=jsTgivwzIeFSpbpFwb48_pTUNT-KM6TYnGv3wKH98HM,631
|
|
45
|
+
python_plugins-1.0.4.dist-info/METADATA,sha256=Cxs-TUoFEfTwbCNeYCtWxiH08_xQZVER8zz8g-5PH_c,2624
|
|
46
|
+
python_plugins-1.0.4.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
47
|
+
python_plugins-1.0.4.dist-info/licenses/LICENSE.rst,sha256=X5eLIsAn1yAKd88LWTYkXUe0PmVK_Z5SD7_5NheGR-s,1104
|
|
48
|
+
python_plugins-1.0.4.dist-info/RECORD,,
|
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,19 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import shutil
|
|
3
|
-
|
|
4
|
-
def remove(dir,rm_dir_name):
|
|
5
|
-
for root, dirs, files in os.walk(dir):
|
|
6
|
-
if "venv" in root or "git" in root:
|
|
7
|
-
continue
|
|
8
|
-
for dir in dirs:
|
|
9
|
-
if dir == rm_dir_name:
|
|
10
|
-
rm_path = os.path.join(root, dir)
|
|
11
|
-
print(f"Removing {rm_path}")
|
|
12
|
-
shutil.rmtree(rm_path)
|
|
13
|
-
|
|
14
|
-
def remove_pycache(dir="."):
|
|
15
|
-
remove(dir,"__pycache__")
|
|
16
|
-
|
|
17
|
-
def remove_ipynb_checkpoints(dir="."):
|
|
18
|
-
remove(dir,".ipynb_checkpoints")
|
|
19
|
-
|
|
@@ -1,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
|