python-general-be-lib 0.11.1__py3-none-any.whl → 0.11.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.
@@ -17,7 +17,6 @@ __all__ = [
17
17
  "InternalServerException",
18
18
  ]
19
19
 
20
- from sqlalchemy.exc import DataError, IntegrityError, NoResultFound, OperationalError
21
20
 
22
21
  from .exception_interface import ExceptionInterface
23
22
 
@@ -111,6 +110,8 @@ def raise_http_exception(e: Exception):
111
110
  BadRequestException: On ``DataError`` or ``IntegrityError``.
112
111
  Exception: The original exception, for every other type.
113
112
  """
113
+ from sqlalchemy.exc import DataError, IntegrityError, NoResultFound, OperationalError
114
+
114
115
  match e:
115
116
  case OperationalError():
116
117
  raise ServiceUnavailableException()
@@ -1,7 +1,12 @@
1
- """SQLAlchemy declarative base class and preconfigured Pydantic models."""
1
+ """SQLAlchemy declarative base class and preconfigured Pydantic models.
2
2
 
3
- from .base_model import *
4
- from .declarative_base import *
3
+ The public symbols are resolved lazily (PEP 562): importing this package does not import
4
+ the modules behind them, so reaching one of them does not pay for the heavier siblings.
5
+ The ``TYPE_CHECKING`` block is what keeps the static types — without it a type checker
6
+ would see every symbol as ``Any``, silently, and the ``py.typed`` marker would promise
7
+ types the consumer does not get.
8
+ """
9
+ from typing import TYPE_CHECKING
5
10
 
6
11
  __all__ = [
7
12
  "Base",
@@ -10,3 +15,45 @@ __all__ = [
10
15
  "ExtBaseModel",
11
16
  "CamelExtBaseModel",
12
17
  ]
18
+
19
+ if TYPE_CHECKING: # i type checker leggono da qui, il runtime no
20
+ from .base_model import CamelExtBaseModel, ExtBaseModel
21
+ from .declarative_base import Base, retrieve_mapper_entity, retrieve_mapper_from_table
22
+
23
+ _MODULES = {
24
+ "Base": ".declarative_base",
25
+ "retrieve_mapper_entity": ".declarative_base",
26
+ "retrieve_mapper_from_table": ".declarative_base",
27
+ "ExtBaseModel": ".base_model",
28
+ "CamelExtBaseModel": ".base_model",
29
+ }
30
+
31
+
32
+ def __getattr__(name: str):
33
+ """Resolve a public symbol, importing its module on first access.
34
+
35
+ Args:
36
+ name (str): Name of the attribute being read.
37
+
38
+ Returns:
39
+ Any: The requested symbol.
40
+
41
+ Raises:
42
+ AttributeError: If the name is not part of the public surface.
43
+ """
44
+ module = _MODULES.get(name)
45
+ if module is None:
46
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
47
+
48
+ from importlib import import_module
49
+
50
+ return getattr(import_module(module, __name__), name)
51
+
52
+
53
+ def __dir__() -> list[str]:
54
+ """List the public surface without importing anything.
55
+
56
+ Returns:
57
+ list[str]: The names in ``__all__``.
58
+ """
59
+ return list(__all__)
@@ -3,7 +3,6 @@ __all__ = ["Base", "retrieve_mapper_entity", "retrieve_mapper_from_table"]
3
3
  from functools import lru_cache
4
4
  from typing import Optional, Any, Sequence
5
5
 
6
- from geoalchemy2 import Geometry, WKBElement
7
6
  from pydantic import create_model, ConfigDict
8
7
  from sqlalchemy.inspection import inspect
9
8
  from sqlalchemy.orm import Mapper, as_declarative
@@ -31,6 +30,11 @@ class Base:
31
30
  or nothing: passing ``__config__`` puts the whole configuration in the hands of the
32
31
  caller, and passing ``__base__`` lets the base carry its own.
33
32
 
33
+ The generated class is stamped with the module of the entity, unless the caller
34
+ passes ``__module__``: ``create_model`` reads the calling frame otherwise, so every
35
+ generated model would claim to live in this module and a ``repr`` would point at
36
+ the library instead of the entity.
37
+
34
38
  Args:
35
39
  model_name (str, optional): Name of the generated model. When not given,
36
40
  ``{ClassName}Model`` is used.
@@ -49,6 +53,10 @@ class Base:
49
53
  Returns:
50
54
  Type[BaseModel]: Dynamically generated Pydantic class.
51
55
  """
56
+ from geoalchemy2 import Geometry, WKBElement
57
+
58
+ create_model_kwargs.setdefault("__module__", cls.__module__)
59
+
52
60
  if "__config__" not in create_model_kwargs.keys() and "__base__" not in create_model_kwargs.keys():
53
61
  create_model_kwargs["__config__"] = ConfigDict(from_attributes=True, populate_by_name=True, arbitrary_types_allowed=True, validate_default=True)
54
62
 
@@ -1,12 +1,58 @@
1
1
  """CRUD and spatial layer over reflected ``Table`` objects, without the ORM.
2
2
 
3
- Alternative to the repositories to operate on tables having no ORM model: the schema
4
- is reflected at runtime and the tables are resolved by name. Unlike the
5
- repositories, this layer does **not** use the handler pipeline and does **not** map
6
- the SQLAlchemy exceptions onto HTTP exceptions.
3
+ Alternative to the repositories to operate on tables having no ORM model: the schema is
4
+ reflected at runtime and the tables are resolved by name. It goes through the **same**
5
+ handler pipeline as the ORM layer, built per table from the reflected ``Table.c``, and maps
6
+ the SQLAlchemy exceptions onto the same HTTP exceptions.
7
+
8
+ The public symbols are resolved lazily (PEP 562): importing this package does not import
9
+ the modules behind them, so reaching one of them does not pay for the heavier siblings.
10
+ The ``TYPE_CHECKING`` block is what keeps the static types — without it a type checker
11
+ would see every symbol as ``Any``, silently, and the ``py.typed`` marker would promise
12
+ types the consumer does not get.
7
13
  """
14
+ from typing import TYPE_CHECKING
15
+
16
+ __all__ = [
17
+ "CrudMetadata",
18
+ "GeomMetadata",
19
+ ]
20
+
21
+ if TYPE_CHECKING: # i type checker leggono da qui, il runtime no
22
+ from .crud_metadata import CrudMetadata
23
+ from .geom_metadata import GeomMetadata
24
+
25
+ _MODULES = {
26
+ "CrudMetadata": ".crud_metadata",
27
+ "GeomMetadata": ".geom_metadata",
28
+ }
29
+
30
+
31
+ def __getattr__(name: str):
32
+ """Resolve a public symbol, importing its module on first access.
33
+
34
+ Args:
35
+ name (str): Name of the attribute being read.
36
+
37
+ Returns:
38
+ Any: The requested symbol.
39
+
40
+ Raises:
41
+ AttributeError: If the name is not part of the public surface.
42
+ """
43
+ module = _MODULES.get(name)
44
+ if module is None:
45
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
46
+
47
+ from importlib import import_module
48
+
49
+ return getattr(import_module(module, __name__), name)
50
+
8
51
 
9
- from .crud_metadata import *
10
- from .geom_metadata import *
52
+ def __dir__() -> list[str]:
53
+ """List the public surface without importing anything.
11
54
 
12
- __all__ = ["CrudMetadata", "GeomMetadata"]
55
+ Returns:
56
+ list[str]: The names in ``__all__``.
57
+ """
58
+ return list(__all__)
@@ -342,7 +342,7 @@ class CrudMetadata:
342
342
  if rows:
343
343
  return rows[0]
344
344
  if strict:
345
- raise EntityNotFoundException()
345
+ raise EntityNotFoundException(custom_message=table.name)
346
346
  return None
347
347
 
348
348
  def _get(self, table: Table, connection: Connection, pk: Any, columns: list[str] = None, **kwhere):
@@ -429,7 +429,7 @@ class CrudMetadata:
429
429
  if rows:
430
430
  return rows[0]
431
431
  if strict:
432
- raise EntityNotFoundException()
432
+ raise EntityNotFoundException(custom_message=table.name)
433
433
  return None
434
434
 
435
435
  def insert(self, from_table: str, connection: Connection = None, models: list[Type[BaseModel] | BaseModel] = None, values: list[dict[str, Any]] = None, returning: bool = True,
@@ -1,9 +1,12 @@
1
- """ORM repositories: generic CRUD, spatial, many-to-many and views."""
1
+ """ORM repositories: generic CRUD, spatial, many-to-many and views.
2
2
 
3
- from .crud_repository import *
4
- from .geometry_repository import *
5
- from .many_to_many_repository import *
6
- from .view_repository import *
3
+ The public symbols are resolved lazily (PEP 562): importing this package does not import
4
+ the modules behind them, so reaching one of them does not pay for the heavier siblings.
5
+ The ``TYPE_CHECKING`` block is what keeps the static types — without it a type checker
6
+ would see every symbol as ``Any``, silently, and the ``py.typed`` marker would promise
7
+ types the consumer does not get.
8
+ """
9
+ from typing import TYPE_CHECKING
7
10
 
8
11
  __all__ = [
9
12
  "CrudRepository",
@@ -11,3 +14,46 @@ __all__ = [
11
14
  "ManyToManyRepository",
12
15
  "ViewRepository",
13
16
  ]
17
+
18
+ if TYPE_CHECKING: # i type checker leggono da qui, il runtime no
19
+ from .crud_repository import CrudRepository
20
+ from .geometry_repository import GeometryRepository
21
+ from .many_to_many_repository import ManyToManyRepository
22
+ from .view_repository import ViewRepository
23
+
24
+ _MODULES = {
25
+ "CrudRepository": ".crud_repository",
26
+ "GeometryRepository": ".geometry_repository",
27
+ "ManyToManyRepository": ".many_to_many_repository",
28
+ "ViewRepository": ".view_repository",
29
+ }
30
+
31
+
32
+ def __getattr__(name: str):
33
+ """Resolve a public symbol, importing its module on first access.
34
+
35
+ Args:
36
+ name (str): Name of the attribute being read.
37
+
38
+ Returns:
39
+ Any: The requested symbol.
40
+
41
+ Raises:
42
+ AttributeError: If the name is not part of the public surface.
43
+ """
44
+ module = _MODULES.get(name)
45
+ if module is None:
46
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
47
+
48
+ from importlib import import_module
49
+
50
+ return getattr(import_module(module, __name__), name)
51
+
52
+
53
+ def __dir__() -> list[str]:
54
+ """List the public surface without importing anything.
55
+
56
+ Returns:
57
+ list[str]: The names in ``__all__``.
58
+ """
59
+ return list(__all__)
@@ -147,7 +147,14 @@ class CrudRepository[Entity: Base | Type[Base]]:
147
147
  self.columns = self.entity.columns()
148
148
  self._relationship_attributes = None # popolato lazy dalla property relationship_attributes
149
149
 
150
- base_handler = handler_class(self.columns) if handler_class else BaseHandler(self.columns)
150
+ # ``handler_class`` accetta una classe — che si costruisce dalle colonne — oppure
151
+ # un'istanza già pronta: il suggerimento di tipo prometteva entrambe e ne reggeva una
152
+ if handler_class is None:
153
+ base_handler = BaseHandler(self.columns)
154
+ elif isinstance(handler_class, type):
155
+ base_handler = handler_class(self.columns)
156
+ else:
157
+ base_handler = handler_class
151
158
 
152
159
  self.stmt_manager = StatementManager(handlers=handlers, base_handler=base_handler)
153
160
 
@@ -423,7 +430,7 @@ class CrudRepository[Entity: Base | Type[Base]]:
423
430
  if records:
424
431
  return records[0]
425
432
  if strict:
426
- raise EntityNotFoundException()
433
+ raise EntityNotFoundException(custom_message=self.entity.__name__)
427
434
  return None
428
435
 
429
436
  def _get(self, session: Session, pk: Any, columns: list[str] = None, exclude_columns: list[str] = None, **kwhere):
@@ -523,7 +530,7 @@ class CrudRepository[Entity: Base | Type[Base]]:
523
530
  if records:
524
531
  return records[0]
525
532
  if strict:
526
- raise EntityNotFoundException()
533
+ raise EntityNotFoundException(custom_message=self.entity.__name__)
527
534
  return None
528
535
 
529
536
  def _find(self, session: Session, where: dict[str, Any] = None, columns: list[str] = None, exclude_columns: list[str] = None, limit: int = 0, orders_by: dict[str, bool] = None, **kwhere):
@@ -32,22 +32,3 @@ class Handler:
32
32
  the handler claims nothing.
33
33
  """
34
34
  return []
35
-
36
- def handle(self, stmt, neq=False, where=None):
37
- """Apply the conditions of this handler alone to a statement.
38
-
39
- Adapter for the isolated use of a handler, outside the ``StatementManager``
40
- pipeline: it collects the conditions of ``conditions`` and adds them with a single
41
- ``.where()`` call. Nothing is applied when the handler produces no condition.
42
-
43
- Args:
44
- stmt (Select | Update | Delete): Statement to apply the filters to.
45
- neq (bool): If ``True``, the conditions are negated. Default: ``False``.
46
- where (dict[str, Any]): Filters. The keys the handler claims are removed
47
- in-place. Default: ``None``.
48
-
49
- Returns:
50
- Select | Update | Delete: Statement with the WHERE conditions applied.
51
- """
52
- conditions = self.conditions(neq=neq, where=where)
53
- return stmt.where(*conditions) if conditions else stmt
@@ -5,6 +5,8 @@ from typing import Any, Type
5
5
  from sqlalchemy import ColumnElement, Delete, Select, Update
6
6
 
7
7
  from general.exception.crud_exceptions import HasNoAttributeException
8
+ from sqlalchemy.sql.base import ReadOnlyColumnCollection
9
+
8
10
  from .base_handler import BaseHandler
9
11
 
10
12
 
@@ -27,19 +29,49 @@ class StatementManager:
27
29
  def __init__(self, handlers: list[BaseHandler | Type[BaseHandler]] = None, base_handler: BaseHandler = None):
28
30
  """Initialize the manager with the handler list and the mandatory base handler.
29
31
 
32
+ A handler can be given as an instance or as a class: a class is built with the
33
+ columns of the ``base_handler``, which is what every handler needs and the only
34
+ thing some of them need. Building it here is what makes a wrong handler fail at
35
+ construction, where the caller can read the cause, instead of at the first query.
36
+
30
37
  Args:
31
- handlers (list[BaseHandler], optional): Additional handlers to run before the
32
- base handler, such as ``JsonHandler`` or ``ILikeHandler``.
38
+ handlers (list[BaseHandler | Type[BaseHandler]], optional): Additional handlers
39
+ to run before the base handler, such as ``JsonHandler`` or ``ILikeHandler``.
40
+ Each one as an instance or as a class.
33
41
  base_handler (BaseHandler): Main handler for the standard filters. Mandatory.
34
42
 
35
43
  Raises:
36
44
  ValueError: If ``base_handler`` is not provided.
45
+ TypeError: If a handler class needs more than the columns to be built.
37
46
  """
38
47
  if not base_handler:
39
- raise ValueError("StatemantManager: base_handler is not set")
40
- self._handlers = handlers if handlers else []
48
+ raise ValueError("StatementManager: base_handler is not set")
49
+ self._handlers = [self._instance_of(handler, base_handler.columns) for handler in handlers] if handlers else []
41
50
  self._base_handler = base_handler
42
51
 
52
+ @staticmethod
53
+ def _instance_of(handler: BaseHandler | Type[BaseHandler], columns: ReadOnlyColumnCollection) -> BaseHandler:
54
+ """Return the handler itself, building it from the columns when given as a class.
55
+
56
+ Args:
57
+ handler (BaseHandler | Type[BaseHandler]): Handler instance or class.
58
+ columns (ReadOnlyColumnCollection): Columns to build a class with.
59
+
60
+ Returns:
61
+ BaseHandler: The handler ready to be run by the pipeline.
62
+
63
+ Raises:
64
+ TypeError: If the class needs more arguments than the columns, with the name of
65
+ the handler and the suggestion to pass an instance.
66
+ """
67
+ if not isinstance(handler, type):
68
+ return handler
69
+
70
+ try:
71
+ return handler(columns)
72
+ except TypeError as e:
73
+ raise TypeError(f"{handler.__name__} needs more than the columns to be built: pass an instance, not the class") from e
74
+
43
75
  def conditions(self, neq: bool = False, where: dict[str, Any] = None) -> list[ColumnElement[Any]]:
44
76
  """Collect the conditions of every handler without touching any statement.
45
77
 
general/logger.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import logging
2
2
  import logging.config
3
+ import reprlib
3
4
  from functools import wraps
4
5
  from time import perf_counter
5
6
 
@@ -21,6 +22,11 @@ color = COLOR['BLUE']
21
22
  end_color = COLOR['ENDC']
22
23
  exc_color = COLOR['RED']
23
24
 
25
+ # Bounded repr of the call arguments for the error record: truncates long strings,
26
+ # collections and object reprs, and falls back to a placeholder when an argument's
27
+ # own ``__repr__`` raises, so that it cannot replace the original exception.
28
+ _args_repr = reprlib.Repr(maxlevel=3, maxtuple=10, maxlist=10, maxdict=10, maxset=10, maxstring=200, maxother=200)
29
+
24
30
  LOGGING_CONFIG = {
25
31
  "version": 1,
26
32
  "disable_existing_loggers": False,
@@ -100,8 +106,9 @@ def log(func):
100
106
  ``HTTPException`` is propagated as is, any other exception is converted into an
101
107
  ``InternalServerException``, whose ``detail`` does not carry the original message so
102
108
  that internal details never reach the HTTP response body. The call arguments are not
103
- serialized on the happy path; on error they are attached to the record as the
104
- ``func_args`` and ``func_kwargs`` structured fields, available to a JSON handler.
109
+ serialized on the happy path; on error their truncated ``repr`` is appended to the
110
+ message, and they are also attached to the record as the ``func_args`` and
111
+ ``func_kwargs`` structured fields, available to a JSON handler.
105
112
 
106
113
  The wrapper is **synchronous**: applied to a coroutine function it measures the
107
114
  coroutine creation time, not its execution, and does not intercept the exceptions
@@ -123,7 +130,8 @@ def log(func):
123
130
  result = func(*args, **kwargs)
124
131
  except Exception as e:
125
132
  extra = dict(func_args=args, func_kwargs=kwargs)
126
- logging.exception(f"Exception {exc_color} {func_name} {end_color}: {repr(e)}", extra=extra)
133
+ call = f"args={_args_repr.repr(args)} kwargs={_args_repr.repr(kwargs)}"
134
+ logging.exception(f"Exception {exc_color} {func_name} {end_color}: {repr(e)} - {call}", extra=extra)
127
135
  raise e.with_traceback(None) if isinstance(e, HTTPException) else InternalServerException()
128
136
  else:
129
137
  logging.info(f"{color} {func_name} {end_color} completed in {(perf_counter() - start):.3f} seconds")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-general-be-lib
3
- Version: 0.11.1
3
+ Version: 0.11.3
4
4
  Summary: General purpose backend library — SQLAlchemy CRUD/Geometry repositories, FastAPI exceptions, Pydantic base models, logger utilities.
5
5
  Author-email: Andrea Di Placido <a.diplacido@arpes.it>, "Arpes S.r.l." <it.admin@arpes.it>
6
6
  License: MIT
@@ -31,6 +31,7 @@ Requires-Dist: testcontainers[postgres]>=4; extra == "dev"
31
31
  Requires-Dist: psycopg[binary]>=3; extra == "dev"
32
32
  Requires-Dist: build; extra == "dev"
33
33
  Requires-Dist: twine; extra == "dev"
34
+ Requires-Dist: mypy>=1.11; extra == "dev"
34
35
  Dynamic: license-file
35
36
 
36
37
  # python-general-be-lib
@@ -1,42 +1,42 @@
1
1
  general/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  general/context.py,sha256=ArxisBIbmij72IWKQwBfJBhmAucUGlMnEPRQnYl1A6k,1165
3
- general/logger.py,sha256=P-7-BLtO1XC2m43wXrnJcTakr2iZBE0gUkMVppJ9exE,4506
3
+ general/logger.py,sha256=MnK8ZDA9x4xhX0KcpOxTieosnFIhFVwSa8b52Q4T9tA,5039
4
4
  general/paginator_dto.py,sha256=DB2hfcrckuEiHEIORLT4EgCcnX4AYYKGlHRr-l-Q1Cw,3741
5
5
  general/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  general/exception/__init__.py,sha256=MZpSDUKeopct7ZqMd1g4XlNS8sM9mmXIlHTIYPOhu9c,849
7
7
  general/exception/access_exceptions.py,sha256=tNIBjxM0-5iSOXDc7Il01eb36mEk-POQGVaHhCpG278,744
8
- general/exception/crud_exceptions.py,sha256=JZs3dXBOp0dYZ5yfNBbMSd2xoLTCMxXxz1myt46Ql2g,4351
8
+ general/exception/crud_exceptions.py,sha256=7zA9J8KPlvK9MpHbhFEmFpdGVMcqw7hCyRGSJB4-K7U,4356
9
9
  general/exception/exception_interface.py,sha256=k7KreAYMwKPQQghkCissdu3ASZZqrRFWM1lAGzeR8sM,1294
10
10
  general/interface/__init__.py,sha256=G11sI1Oxtb-Z_-ORAuKS_Kkdwopt1uXmEXYtZEJYiLs,445
11
- general/interface/base/__init__.py,sha256=fA1hdSY5TX6k_UpvA0eAfYeNWkXY6fPrHBqZVIdf6PY,270
11
+ general/interface/base/__init__.py,sha256=wRKbvb8lF33_2iG100mEQXz1tEkh9BF5bPcIi7ri_Rk,1801
12
12
  general/interface/base/base_model.py,sha256=aIzrRZVUytmbgmEH1bya29rVFOm-Njinn_JXkgkBrr8,2575
13
- general/interface/base/declarative_base.py,sha256=IyfgH8eJ_dlh3h9MBKC7kNbb1TeJxWTeGagQASqWCrU,8910
14
- general/interface/metadata/__init__.py,sha256=pXKYY4uO92eQI3gtuG4FKZbBi76gu-VJLxaAy-emeP8,474
15
- general/interface/metadata/crud_metadata.py,sha256=NzTc1Q98zoDWaUTbvLbZEZgOmyji_dAl9KLajYB0_lI,48070
13
+ general/interface/base/declarative_base.py,sha256=J-q6nJIdYixFk9tgWjmGVII2cHeOazf0e4snaO_rHhI,9302
14
+ general/interface/metadata/__init__.py,sha256=CawnfGK7WcJmtqi9CjEjBqCyX_vuHFK-Td1orXTH__U,1849
15
+ general/interface/metadata/crud_metadata.py,sha256=SfV2__zgkTTeX1opLHDMRIeyB1DKiObr7pGOHkGVFlo,48120
16
16
  general/interface/metadata/geom_metadata.py,sha256=xWNZnWhN_Om91pcqSsURKi5EUYNZh444zDqMwoOpq84,15508
17
17
  general/interface/mixin/__init__.py,sha256=M5-e6T_R63Utwh3_WcmoE3wanwIZjNjbgLYrrFlSpTA,659
18
18
  general/interface/mixin/audit_mixin.py,sha256=N2JDD9JxXDMeBqu0yAlhVWFOK3EeUA2b215hPvXytUU,1421
19
19
  general/interface/mixin/softdelete_mixin.py,sha256=526luzM4DBCorcq99kZ6BYqtQKKJCpnxX9rSEigfyIU,2148
20
20
  general/interface/mixin/timestamp_mixin.py,sha256=wmcIx2Y8jgVqg9A-1E61BvkcKCo52ZjKNHeKfXJmUl0,2220
21
- general/interface/repository/__init__.py,sha256=eWoNy35LVu6sDrK5ju7VAeoclknKO0-yTgjVckJpi8s,321
22
- general/interface/repository/crud_repository.py,sha256=hUpFzY9ANWJQh5Z_cvwrM4YH8FXX5mTobEFnX5XltPg,55559
21
+ general/interface/repository/__init__.py,sha256=QQD6okLfRozC0uOZPGrwOUDKJyZTgpObvwJ3OOSJdbM,1813
22
+ general/interface/repository/crud_repository.py,sha256=Hr7APBsN1uFqEfM78ZSIcgheg4ilvND4OMc7TBNOlcw,55962
23
23
  general/interface/repository/geometry_repository.py,sha256=Fmv0qhfqumnU5fiETMMAmiB0UyG43b19jlPXQ8cJ9CU,11289
24
24
  general/interface/repository/many_to_many_repository.py,sha256=KRJ2SMUGDYNoGV-ea541wlWg0FW4NQ_Ry85aJBarmC8,11183
25
25
  general/interface/repository/view_repository.py,sha256=wxDGw7kenuVrDd9nfh7-omw2m9Jex5WzF_lhEiqPoA0,7902
26
26
  general/interface/repository/handler/__init__.py,sha256=uhtGETCY-s9lJsn919u0e7XnPsGjBjxjjtJFnn5XrV4,686
27
27
  general/interface/repository/handler/base_handler.py,sha256=aVT6s60rsdZUqQlKWlUyuiGgVxzFLJCb7uztn859sL4,3363
28
- general/interface/repository/handler/handler.py,sha256=o_wD9L5sF4RySyetOJHMRE7Ho_3PqP5gWCj2zw9D7Lk,2467
28
+ general/interface/repository/handler/handler.py,sha256=tzoJXjf43bgdczwSbcvVeUtt6xZU6ZSkVgfMFwuu2eg,1538
29
29
  general/interface/repository/handler/ilike_handler.py,sha256=OM3klDlx7ixqWF7kklWj8kbgVY_5ZNitcQ0usGnQP_0,4015
30
30
  general/interface/repository/handler/interval_handler.py,sha256=4TtEcpzUFZeyB-yitib5Kpe3U67aS07uye4K7jXrtG4,5517
31
31
  general/interface/repository/handler/json_handler.py,sha256=f_nGemsxTPJ3W0xkU99sCFA0EVo1xa8p803NyjcGJT4,4414
32
32
  general/interface/repository/handler/json_ilike_handler.py,sha256=icfA4dO8E_W_KUEG5HB1nLVI1jfjxzkG8ZJ-IaCd4kY,3530
33
33
  general/interface/repository/handler/or_handler.py,sha256=UOjIh77H4y-x434YGLYRfVIXKnod1M5XPiMf71V2JTg,3137
34
34
  general/interface/repository/handler/soft_delete_handler.py,sha256=1WD1n6q5plyJ0RDniJcEwNlic1WJqXvSlCj99VLc_3A,4100
35
- general/interface/repository/handler/statement_manager.py,sha256=EBv2ApCBYfo18fqoALftMxsN-_2Yq9n-yzfEQkh9ZLg,6612
35
+ general/interface/repository/handler/statement_manager.py,sha256=JSj6K-iQJ06kLdsMTOqK62cIvR87ioOA1LmLTGpqrB0,8205
36
36
  general/utils/__init__.py,sha256=_SPe88reIZ0JxwK7mp-u_p-9c4hCcZ-daUihi0gymNk,103
37
37
  general/utils/consts.py,sha256=nE75Ud7sVuDw9K_xmIJNjL_5f_BVJmwGNPGFYc26H3Y,264
38
- python_general_be_lib-0.11.1.dist-info/licenses/LICENSE,sha256=iUaO1XZyB9P3Tmog0OILuTisP6vXGe3QKz-4yRTxOFk,1069
39
- python_general_be_lib-0.11.1.dist-info/METADATA,sha256=-U0oYx9zfT6TCJl8KEEZ4kWKiQ6SdDWx8woNr7EYSJs,3410
40
- python_general_be_lib-0.11.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
41
- python_general_be_lib-0.11.1.dist-info/top_level.txt,sha256=tTZePW8_CNUqSgKFd2SEH72ZbnhS0OYjRsgcv0ikSFY,8
42
- python_general_be_lib-0.11.1.dist-info/RECORD,,
38
+ python_general_be_lib-0.11.3.dist-info/licenses/LICENSE,sha256=iUaO1XZyB9P3Tmog0OILuTisP6vXGe3QKz-4yRTxOFk,1069
39
+ python_general_be_lib-0.11.3.dist-info/METADATA,sha256=kXWrKc_wD4H6khCeqnluMKmFoD-8AopOF8m3RXISA1s,3452
40
+ python_general_be_lib-0.11.3.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
41
+ python_general_be_lib-0.11.3.dist-info/top_level.txt,sha256=tTZePW8_CNUqSgKFd2SEH72ZbnhS0OYjRsgcv0ikSFY,8
42
+ python_general_be_lib-0.11.3.dist-info/RECORD,,