alpha-python 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- alpha_python-0.1.0/LICENSE +21 -0
- alpha_python-0.1.0/PKG-INFO +22 -0
- alpha_python-0.1.0/README.md +3 -0
- alpha_python-0.1.0/pyproject.toml +69 -0
- alpha_python-0.1.0/setup.cfg +4 -0
- alpha_python-0.1.0/src/alpha/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/adapters/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/adapters/sqla_unit_of_work.py +120 -0
- alpha_python-0.1.0/src/alpha/domain/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/domain/models/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/domain/models/base_model.py +25 -0
- alpha_python-0.1.0/src/alpha/encoder.py +62 -0
- alpha_python-0.1.0/src/alpha/exceptions.py +99 -0
- alpha_python-0.1.0/src/alpha/factories/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/factories/_type_conversion_matrix.py +233 -0
- alpha_python-0.1.0/src/alpha/factories/_type_mapping.py +29 -0
- alpha_python-0.1.0/src/alpha/factories/class_factories.py +496 -0
- alpha_python-0.1.0/src/alpha/factories/default_field_factory.py +50 -0
- alpha_python-0.1.0/src/alpha/factories/field_iterator.py +188 -0
- alpha_python-0.1.0/src/alpha/factories/logging_handler_factory.py +86 -0
- alpha_python-0.1.0/src/alpha/factories/model_class_factory.py +176 -0
- alpha_python-0.1.0/src/alpha/factories/models/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/factories/models/factory_classes.py +20 -0
- alpha_python-0.1.0/src/alpha/factories/request_factory.py +211 -0
- alpha_python-0.1.0/src/alpha/factories/response_factory.py +186 -0
- alpha_python-0.1.0/src/alpha/factories/type_factories.py +204 -0
- alpha_python-0.1.0/src/alpha/infra/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/infra/database/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/infra/database/sql_alchemy_database.py +159 -0
- alpha_python-0.1.0/src/alpha/infra/database/sql_alchemy_view.py +48 -0
- alpha_python-0.1.0/src/alpha/infra/models/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/infra/models/filter_operators.py +98 -0
- alpha_python-0.1.0/src/alpha/infra/models/json_patch.py +21 -0
- alpha_python-0.1.0/src/alpha/infra/models/order_by.py +69 -0
- alpha_python-0.1.0/src/alpha/infra/models/query_clause.py +45 -0
- alpha_python-0.1.0/src/alpha/infra/models/search_filter.py +586 -0
- alpha_python-0.1.0/src/alpha/interfaces/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/interfaces/attrs_instance.py +10 -0
- alpha_python-0.1.0/src/alpha/interfaces/dataclass_instance.py +11 -0
- alpha_python-0.1.0/src/alpha/interfaces/factories.py +102 -0
- alpha_python-0.1.0/src/alpha/interfaces/openapi_model.py +21 -0
- alpha_python-0.1.0/src/alpha/interfaces/patchable.py +8 -0
- alpha_python-0.1.0/src/alpha/interfaces/sql_database.py +36 -0
- alpha_python-0.1.0/src/alpha/interfaces/sql_mapper.py +23 -0
- alpha_python-0.1.0/src/alpha/interfaces/sql_repository.py +380 -0
- alpha_python-0.1.0/src/alpha/interfaces/token_factory.py +56 -0
- alpha_python-0.1.0/src/alpha/interfaces/unit_of_work.py +53 -0
- alpha_python-0.1.0/src/alpha/interfaces/updateable.py +7 -0
- alpha_python-0.1.0/src/alpha/py.typed +0 -0
- alpha_python-0.1.0/src/alpha/repositories/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/repositories/default_sql_repository.py +679 -0
- alpha_python-0.1.0/src/alpha/repositories/models/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/repositories/models/repository_model.py +16 -0
- alpha_python-0.1.0/src/alpha/services/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/services/authentication_service.py +71 -0
- alpha_python-0.1.0/src/alpha/utils/__init__.py +0 -0
- alpha_python-0.1.0/src/alpha/utils/_http_codes.py +148 -0
- alpha_python-0.1.0/src/alpha/utils/is_attrs.py +18 -0
- alpha_python-0.1.0/src/alpha/utils/logging_configurator.py +133 -0
- alpha_python-0.1.0/src/alpha/utils/logging_level_checker.py +26 -0
- alpha_python-0.1.0/src/alpha/utils/response_object.py +26 -0
- alpha_python-0.1.0/src/alpha/utils/version_check.py +17 -0
- alpha_python-0.1.0/src/alpha_python.egg-info/PKG-INFO +22 -0
- alpha_python-0.1.0/src/alpha_python.egg-info/SOURCES.txt +66 -0
- alpha_python-0.1.0/src/alpha_python.egg-info/dependency_links.txt +1 -0
- alpha_python-0.1.0/src/alpha_python.egg-info/requires.txt +9 -0
- alpha_python-0.1.0/src/alpha_python.egg-info/top_level.txt +1 -0
- alpha_python-0.1.0/tests/test_encoder.py +170 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 breijling
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: alpha-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Alpha is intended to be the first dependency you need to add to your Python application. It is a Python library which contains standard building blocks that can be used in applications that are used as APIs and/or make use of database interaction.
|
|
5
|
+
Author-email: Bart Reijling <bart@reijling.eu>
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: attrs>=25.4.0
|
|
10
|
+
Requires-Dist: gunicorn>=23.0.0
|
|
11
|
+
Requires-Dist: jsonpatch>=1.33
|
|
12
|
+
Requires-Dist: numpy>=2.3.5
|
|
13
|
+
Requires-Dist: pandas>=2.3.3
|
|
14
|
+
Requires-Dist: pydantic>=2.12.5
|
|
15
|
+
Requires-Dist: pyjwt>=2.10.1
|
|
16
|
+
Requires-Dist: six>=1.17.0
|
|
17
|
+
Requires-Dist: sqlalchemy>=2.0.44
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# alpha
|
|
21
|
+
|
|
22
|
+
Alpha is intended to be the first dependency you need to add to your Python application. It is a Python library which contains standard building blocks that can be used in applications that are used as APIs and/or make use of database interaction.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "alpha-python"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Alpha is intended to be the first dependency you need to add to your Python application. It is a Python library which contains standard building blocks that can be used in applications that are used as APIs and/or make use of database interaction."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Bart Reijling", email = "bart@reijling.eu" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"attrs>=25.4.0",
|
|
12
|
+
"gunicorn>=23.0.0",
|
|
13
|
+
"jsonpatch>=1.33",
|
|
14
|
+
"numpy>=2.3.5",
|
|
15
|
+
"pandas>=2.3.3",
|
|
16
|
+
"pydantic>=2.12.5",
|
|
17
|
+
"pyjwt>=2.10.1",
|
|
18
|
+
"six>=1.17.0",
|
|
19
|
+
"sqlalchemy>=2.0.44",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[build-system]
|
|
23
|
+
requires = ["setuptools>=64"]
|
|
24
|
+
build-backend = "setuptools.build_meta"
|
|
25
|
+
|
|
26
|
+
[dependency-groups]
|
|
27
|
+
dev = [
|
|
28
|
+
"black>=25.11.0",
|
|
29
|
+
"coverage>=7.12.0",
|
|
30
|
+
"isort>=7.0.0",
|
|
31
|
+
"mypy>=1.18.2",
|
|
32
|
+
"pytest>=9.0.1",
|
|
33
|
+
"pytest-cov>=7.0.0",
|
|
34
|
+
"ruff>=0.14.7",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[tool.pytest.ini_options]
|
|
38
|
+
minversion = 7.0
|
|
39
|
+
python_files = "test_*.py"
|
|
40
|
+
addopts = "-v -p no:warnings --cov --cov-report=lcov:./coverage/lcov.info --cov-report=term --cov-report=term-missing"
|
|
41
|
+
testpaths = [
|
|
42
|
+
"tests"
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[tool.coverage.run]
|
|
46
|
+
source = ["src"]
|
|
47
|
+
omit = [
|
|
48
|
+
"tests/*",
|
|
49
|
+
"__init__.py",
|
|
50
|
+
"_http_codes.py"
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[tool.black]
|
|
54
|
+
line-length = 79
|
|
55
|
+
skip-string-normalization = true
|
|
56
|
+
target-version = ['py310', 'py311', 'py312', 'py313']
|
|
57
|
+
|
|
58
|
+
[tool.isort]
|
|
59
|
+
py_version = 311
|
|
60
|
+
profile = "black"
|
|
61
|
+
line_length = 79
|
|
62
|
+
force_grid_wrap = 0
|
|
63
|
+
|
|
64
|
+
[tool.mypy]
|
|
65
|
+
python_version = "3.11"
|
|
66
|
+
exclude = ['^tests/']
|
|
67
|
+
|
|
68
|
+
[tool.ruff]
|
|
69
|
+
line-length = 79
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""Contains the SQLAlchemy Unit of Work implementation."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, TypeVar
|
|
4
|
+
|
|
5
|
+
from sqlalchemy.orm.session import Session
|
|
6
|
+
|
|
7
|
+
from alpha import exceptions
|
|
8
|
+
from alpha.interfaces.sql_database import SqlDatabase
|
|
9
|
+
from alpha.repositories.models.repository_model import RepositoryModel
|
|
10
|
+
|
|
11
|
+
UOW = TypeVar("UOW", bound="SqlAlchemyUnitOfWork")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SqlAlchemyUnitOfWork:
|
|
15
|
+
"""Unit of Work implementation for SQLAlchemy databases."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, db: SqlDatabase, repos: list[RepositoryModel]) -> None:
|
|
18
|
+
"""Initialize the Unit of Work with a database and repositories.
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
db : SqlDatabase
|
|
23
|
+
The database instance to use.
|
|
24
|
+
repos : list[RepositoryModel]
|
|
25
|
+
The list of repository models to use.
|
|
26
|
+
|
|
27
|
+
Raises
|
|
28
|
+
------
|
|
29
|
+
TypeError
|
|
30
|
+
If the provided database is not a valid SqlDatabase instance.
|
|
31
|
+
TypeError
|
|
32
|
+
If the provided repositories list is empty or contains invalid
|
|
33
|
+
models.
|
|
34
|
+
"""
|
|
35
|
+
if not isinstance(db, SqlDatabase): # type: ignore
|
|
36
|
+
raise TypeError("No valid database provided")
|
|
37
|
+
|
|
38
|
+
self._db = db
|
|
39
|
+
self._repositories = repos
|
|
40
|
+
self._session: Session | None = None
|
|
41
|
+
|
|
42
|
+
def __enter__(self: UOW) -> UOW:
|
|
43
|
+
"""Initialize the Unit of Work context.
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
The Unit of Work instance.
|
|
48
|
+
|
|
49
|
+
Raises
|
|
50
|
+
------
|
|
51
|
+
TypeError
|
|
52
|
+
If the provided repositories list is empty or contains invalid
|
|
53
|
+
models.
|
|
54
|
+
"""
|
|
55
|
+
self._session = self._db.get_session()
|
|
56
|
+
|
|
57
|
+
for repo in self._repositories:
|
|
58
|
+
session = self._session
|
|
59
|
+
model = repo.default_model
|
|
60
|
+
|
|
61
|
+
name: str = repo.name
|
|
62
|
+
repository = repo.repository
|
|
63
|
+
interface: Any = repo.interface
|
|
64
|
+
|
|
65
|
+
self.__setattr__(
|
|
66
|
+
name,
|
|
67
|
+
repository(session=session, default_model=model), # type: ignore
|
|
68
|
+
)
|
|
69
|
+
if interface:
|
|
70
|
+
if not isinstance(getattr(self, name), interface):
|
|
71
|
+
raise TypeError(f"Repository for {name} has no interface")
|
|
72
|
+
|
|
73
|
+
return self
|
|
74
|
+
|
|
75
|
+
def __exit__(self, *args: Any) -> None:
|
|
76
|
+
"""Finalize the Unit of Work context."""
|
|
77
|
+
if not self._session:
|
|
78
|
+
raise exceptions.DatabaseSessionError(
|
|
79
|
+
"No active database session is defined"
|
|
80
|
+
)
|
|
81
|
+
self._session.close()
|
|
82
|
+
self.rollback()
|
|
83
|
+
self._session = None # type: ignore
|
|
84
|
+
|
|
85
|
+
def commit(self) -> None:
|
|
86
|
+
"""Commit the current transaction."""
|
|
87
|
+
if not self._session:
|
|
88
|
+
raise exceptions.DatabaseSessionError(
|
|
89
|
+
"No active database session is defined"
|
|
90
|
+
)
|
|
91
|
+
self._session.commit()
|
|
92
|
+
|
|
93
|
+
def flush(self) -> None:
|
|
94
|
+
"""Flush the current transaction."""
|
|
95
|
+
if not self._session:
|
|
96
|
+
raise exceptions.DatabaseSessionError(
|
|
97
|
+
"No active database session is defined"
|
|
98
|
+
)
|
|
99
|
+
self._session.flush()
|
|
100
|
+
|
|
101
|
+
def rollback(self) -> None:
|
|
102
|
+
"""Rollback the current transaction."""
|
|
103
|
+
if not self._session:
|
|
104
|
+
raise exceptions.DatabaseSessionError(
|
|
105
|
+
"No active database session is defined"
|
|
106
|
+
)
|
|
107
|
+
self._session.rollback()
|
|
108
|
+
|
|
109
|
+
def refresh(self, obj: object) -> None:
|
|
110
|
+
"""Refresh the state of a given object."""
|
|
111
|
+
if not self._session:
|
|
112
|
+
raise exceptions.DatabaseSessionError(
|
|
113
|
+
"No active database session is defined"
|
|
114
|
+
)
|
|
115
|
+
self._session.refresh(obj)
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def session(self) -> Session | None:
|
|
119
|
+
"""Get the current database session."""
|
|
120
|
+
return self._session
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Any, TypeVar
|
|
3
|
+
|
|
4
|
+
DomainModel = TypeVar("DomainModel", bound="BaseDomainModel")
|
|
5
|
+
DomainModelCovariant = TypeVar(
|
|
6
|
+
"DomainModelCovariant", bound="BaseDomainModel", covariant=True
|
|
7
|
+
)
|
|
8
|
+
DomainModelContravariant = TypeVar(
|
|
9
|
+
"DomainModelContravariant", bound="BaseDomainModel", contravariant=True
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class BaseDomainModel:
|
|
15
|
+
def to_dict(self) -> dict[str, Any]:
|
|
16
|
+
obj: dict[str, Any] = {}
|
|
17
|
+
for attr in self.__dataclass_fields__.keys():
|
|
18
|
+
if not attr.startswith("_"):
|
|
19
|
+
obj[attr] = getattr(self, attr)
|
|
20
|
+
if attr == "_id":
|
|
21
|
+
obj[attr] = str(getattr(self, attr))
|
|
22
|
+
return obj
|
|
23
|
+
|
|
24
|
+
def update(self, obj: DomainModel) -> DomainModel:
|
|
25
|
+
raise NotImplementedError("Subclasses must implement the update method")
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from dataclasses import asdict, is_dataclass
|
|
3
|
+
from datetime import date, datetime, time
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from json import encoder
|
|
6
|
+
from typing import Any
|
|
7
|
+
from uuid import UUID
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import pandas as pd
|
|
11
|
+
import six
|
|
12
|
+
|
|
13
|
+
from alpha.interfaces.openapi_model import OpenAPIModel
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class JSONEncoder(encoder.JSONEncoder):
|
|
17
|
+
include_nulls = False
|
|
18
|
+
|
|
19
|
+
def default(self, o: Any) -> Any:
|
|
20
|
+
if isinstance(o, list):
|
|
21
|
+
return [self.default(item) for item in o] # type: ignore
|
|
22
|
+
if isinstance(o, OpenAPIModel):
|
|
23
|
+
dikt: dict[str, Any] = {}
|
|
24
|
+
for attr, _ in six.iteritems(o.openapi_types):
|
|
25
|
+
value = getattr(o, attr)
|
|
26
|
+
if value is None and not self.include_nulls:
|
|
27
|
+
continue
|
|
28
|
+
attr = o.attribute_map[attr]
|
|
29
|
+
dikt[attr] = value
|
|
30
|
+
return dikt
|
|
31
|
+
if hasattr(o, "to_dict"):
|
|
32
|
+
return o.to_dict()
|
|
33
|
+
if hasattr(o, "to_list"):
|
|
34
|
+
return o.to_list()
|
|
35
|
+
if isinstance(o, set):
|
|
36
|
+
return list(o) # type: ignore
|
|
37
|
+
if isinstance(o, Enum):
|
|
38
|
+
return o.name
|
|
39
|
+
if isinstance(o, UUID):
|
|
40
|
+
return str(o)
|
|
41
|
+
if isinstance(o, np.int64): # type: ignore
|
|
42
|
+
return int(o)
|
|
43
|
+
if isinstance(o, np.float32): # type: ignore
|
|
44
|
+
return float(o)
|
|
45
|
+
if isinstance(o, pd.Timestamp):
|
|
46
|
+
return o.isoformat()
|
|
47
|
+
if isinstance(o, datetime):
|
|
48
|
+
return o.isoformat()
|
|
49
|
+
if isinstance(o, date):
|
|
50
|
+
return o.isoformat()
|
|
51
|
+
if isinstance(o, time):
|
|
52
|
+
return o.isoformat()
|
|
53
|
+
if is_dataclass(o):
|
|
54
|
+
if isinstance(o, type):
|
|
55
|
+
cls = getattr(o, "__class__")
|
|
56
|
+
return cls.__name__
|
|
57
|
+
return asdict(o)
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
return json.JSONEncoder.default(self, o)
|
|
61
|
+
except Exception:
|
|
62
|
+
return None
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# HTTP Exceptions
|
|
2
|
+
class BadRequestException(Exception):
|
|
3
|
+
"""Equivalent to HTTP code 400"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class UnauthorizedException(Exception):
|
|
7
|
+
"""Equivalent to HTTP code 401"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ForbiddenException(Exception):
|
|
11
|
+
"""Equivalent to HTTP code 403"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class NotFoundException(Exception):
|
|
15
|
+
"""Equivalent to HTTP code 404"""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class NotAcceptableException(Exception):
|
|
19
|
+
"""Equivalent to HTTP code 406"""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ConflictException(Exception):
|
|
23
|
+
"""Equivalent to HTTP code 409"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class PayloadTooLargeException(Exception):
|
|
27
|
+
"""Equivalent to HTTP code 413"""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class UnprocessableContentException(Exception):
|
|
31
|
+
"""Equivalent to HTTP code 422"""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ErrorException(Exception): ...
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class InternalServerErrorException(ErrorException):
|
|
38
|
+
"""Equivalent to HTTP code 500"""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class NotImplementedException(ErrorException):
|
|
42
|
+
"""Equivalent to HTTP code 501"""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class BadGatewayException(ErrorException):
|
|
46
|
+
"""Equivalent to HTTP code 502"""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class ServiceUnavailableException(ErrorException):
|
|
50
|
+
"""Equivalent to HTTP code 503"""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
## Common exceptions
|
|
54
|
+
class DatabaseMapperError(Exception): ...
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class DatabaseSessionError(InternalServerErrorException): ...
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class InstrumentedAttributeMissing(Exception): ...
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class AlreadyExistsException(ForbiddenException): ...
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class TypingFactoryException(Exception): ...
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class ModelClassFactoryException(Exception): ...
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class DefaultFactoryException(Exception): ...
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class ObjectConversionNotSupported(Exception): ...
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class ObjectConversionNotAllowed(Exception): ...
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ObjectConversionError(Exception): ...
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class UnionArgumentError(Exception): ...
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class MixedArgumentTypesError(Exception): ...
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class MissingAttributeError(Exception): ...
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class ClassMismatchException(Exception): ...
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class LoggingHandlerException(Exception): ...
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class ClassFactoryException(Exception): ...
|
|
File without changes
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""Contains the TYPE_CONVERSION_MATRIX constant which can be used to determine
|
|
2
|
+
if it is allowed to cast an object to a different type.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import datetime
|
|
6
|
+
import uuid
|
|
7
|
+
|
|
8
|
+
TYPE_CONVERSION_MATRIX: dict[type, dict[type, bool]] = {
|
|
9
|
+
str: {
|
|
10
|
+
str: True,
|
|
11
|
+
complex: True,
|
|
12
|
+
int: True,
|
|
13
|
+
float: True,
|
|
14
|
+
bytes: True,
|
|
15
|
+
bytearray: True,
|
|
16
|
+
list: True,
|
|
17
|
+
dict: False,
|
|
18
|
+
set: True,
|
|
19
|
+
tuple: True,
|
|
20
|
+
bool: True,
|
|
21
|
+
datetime.datetime: True,
|
|
22
|
+
datetime.date: True,
|
|
23
|
+
uuid.UUID: True,
|
|
24
|
+
},
|
|
25
|
+
complex: {
|
|
26
|
+
str: True,
|
|
27
|
+
complex: True,
|
|
28
|
+
int: False,
|
|
29
|
+
float: False,
|
|
30
|
+
bytes: False,
|
|
31
|
+
bytearray: False,
|
|
32
|
+
list: False,
|
|
33
|
+
dict: False,
|
|
34
|
+
set: False,
|
|
35
|
+
tuple: False,
|
|
36
|
+
bool: True,
|
|
37
|
+
datetime.datetime: False,
|
|
38
|
+
datetime.date: False,
|
|
39
|
+
uuid.UUID: False,
|
|
40
|
+
},
|
|
41
|
+
int: {
|
|
42
|
+
str: True,
|
|
43
|
+
complex: True,
|
|
44
|
+
int: True,
|
|
45
|
+
float: True,
|
|
46
|
+
bytes: True,
|
|
47
|
+
bytearray: True,
|
|
48
|
+
list: False,
|
|
49
|
+
dict: False,
|
|
50
|
+
set: False,
|
|
51
|
+
tuple: False,
|
|
52
|
+
bool: True,
|
|
53
|
+
datetime.datetime: True,
|
|
54
|
+
datetime.date: True,
|
|
55
|
+
uuid.UUID: False,
|
|
56
|
+
},
|
|
57
|
+
float: {
|
|
58
|
+
str: True,
|
|
59
|
+
complex: True,
|
|
60
|
+
int: True,
|
|
61
|
+
float: True,
|
|
62
|
+
bytes: False,
|
|
63
|
+
bytearray: False,
|
|
64
|
+
list: False,
|
|
65
|
+
dict: False,
|
|
66
|
+
set: False,
|
|
67
|
+
tuple: False,
|
|
68
|
+
bool: True,
|
|
69
|
+
datetime.datetime: False,
|
|
70
|
+
datetime.date: False,
|
|
71
|
+
uuid.UUID: False,
|
|
72
|
+
},
|
|
73
|
+
bytes: {
|
|
74
|
+
str: False,
|
|
75
|
+
complex: False,
|
|
76
|
+
int: False,
|
|
77
|
+
float: False,
|
|
78
|
+
bytes: True,
|
|
79
|
+
bytearray: True,
|
|
80
|
+
list: False,
|
|
81
|
+
dict: False,
|
|
82
|
+
set: False,
|
|
83
|
+
tuple: False,
|
|
84
|
+
bool: True,
|
|
85
|
+
datetime.datetime: False,
|
|
86
|
+
datetime.date: False,
|
|
87
|
+
uuid.UUID: False,
|
|
88
|
+
},
|
|
89
|
+
bytearray: {
|
|
90
|
+
str: False,
|
|
91
|
+
complex: False,
|
|
92
|
+
int: False,
|
|
93
|
+
float: False,
|
|
94
|
+
bytes: True,
|
|
95
|
+
bytearray: True,
|
|
96
|
+
list: False,
|
|
97
|
+
dict: False,
|
|
98
|
+
set: False,
|
|
99
|
+
tuple: False,
|
|
100
|
+
bool: True,
|
|
101
|
+
datetime.datetime: False,
|
|
102
|
+
datetime.date: False,
|
|
103
|
+
uuid.UUID: False,
|
|
104
|
+
},
|
|
105
|
+
list: {
|
|
106
|
+
str: True,
|
|
107
|
+
complex: False,
|
|
108
|
+
int: False,
|
|
109
|
+
float: False,
|
|
110
|
+
bytes: True,
|
|
111
|
+
bytearray: True,
|
|
112
|
+
list: True,
|
|
113
|
+
dict: False,
|
|
114
|
+
set: True,
|
|
115
|
+
tuple: True,
|
|
116
|
+
bool: True,
|
|
117
|
+
datetime.datetime: False,
|
|
118
|
+
datetime.date: False,
|
|
119
|
+
uuid.UUID: False,
|
|
120
|
+
},
|
|
121
|
+
dict: {
|
|
122
|
+
str: True,
|
|
123
|
+
complex: False,
|
|
124
|
+
int: False,
|
|
125
|
+
float: False,
|
|
126
|
+
bytes: False,
|
|
127
|
+
bytearray: False,
|
|
128
|
+
list: True,
|
|
129
|
+
dict: True,
|
|
130
|
+
set: True,
|
|
131
|
+
tuple: True,
|
|
132
|
+
bool: True,
|
|
133
|
+
datetime.datetime: False,
|
|
134
|
+
datetime.date: False,
|
|
135
|
+
uuid.UUID: False,
|
|
136
|
+
},
|
|
137
|
+
set: {
|
|
138
|
+
str: True,
|
|
139
|
+
complex: False,
|
|
140
|
+
int: False,
|
|
141
|
+
float: False,
|
|
142
|
+
bytes: True,
|
|
143
|
+
bytearray: True,
|
|
144
|
+
list: True,
|
|
145
|
+
dict: False,
|
|
146
|
+
set: True,
|
|
147
|
+
tuple: True,
|
|
148
|
+
bool: True,
|
|
149
|
+
datetime.datetime: False,
|
|
150
|
+
datetime.date: False,
|
|
151
|
+
uuid.UUID: False,
|
|
152
|
+
},
|
|
153
|
+
tuple: {
|
|
154
|
+
str: True,
|
|
155
|
+
complex: False,
|
|
156
|
+
int: False,
|
|
157
|
+
float: False,
|
|
158
|
+
bytes: True,
|
|
159
|
+
bytearray: True,
|
|
160
|
+
list: True,
|
|
161
|
+
dict: False,
|
|
162
|
+
set: True,
|
|
163
|
+
tuple: True,
|
|
164
|
+
bool: True,
|
|
165
|
+
datetime.datetime: False,
|
|
166
|
+
datetime.date: False,
|
|
167
|
+
uuid.UUID: False,
|
|
168
|
+
},
|
|
169
|
+
bool: {
|
|
170
|
+
str: True,
|
|
171
|
+
complex: True,
|
|
172
|
+
int: True,
|
|
173
|
+
float: True,
|
|
174
|
+
bytes: True,
|
|
175
|
+
bytearray: True,
|
|
176
|
+
list: False,
|
|
177
|
+
dict: False,
|
|
178
|
+
set: False,
|
|
179
|
+
tuple: False,
|
|
180
|
+
bool: True,
|
|
181
|
+
datetime.datetime: False,
|
|
182
|
+
datetime.date: False,
|
|
183
|
+
uuid.UUID: False,
|
|
184
|
+
},
|
|
185
|
+
datetime.datetime: {
|
|
186
|
+
str: True,
|
|
187
|
+
complex: False,
|
|
188
|
+
int: False,
|
|
189
|
+
float: False,
|
|
190
|
+
bytes: False,
|
|
191
|
+
bytearray: False,
|
|
192
|
+
list: False,
|
|
193
|
+
dict: False,
|
|
194
|
+
set: False,
|
|
195
|
+
tuple: False,
|
|
196
|
+
bool: True,
|
|
197
|
+
datetime.datetime: True,
|
|
198
|
+
datetime.date: True,
|
|
199
|
+
uuid.UUID: False,
|
|
200
|
+
},
|
|
201
|
+
datetime.date: {
|
|
202
|
+
str: True,
|
|
203
|
+
complex: False,
|
|
204
|
+
int: False,
|
|
205
|
+
float: False,
|
|
206
|
+
bytes: False,
|
|
207
|
+
bytearray: False,
|
|
208
|
+
list: False,
|
|
209
|
+
dict: False,
|
|
210
|
+
set: False,
|
|
211
|
+
tuple: False,
|
|
212
|
+
bool: True,
|
|
213
|
+
datetime.datetime: True,
|
|
214
|
+
datetime.date: True,
|
|
215
|
+
uuid.UUID: False,
|
|
216
|
+
},
|
|
217
|
+
uuid.UUID: {
|
|
218
|
+
str: True,
|
|
219
|
+
complex: False,
|
|
220
|
+
int: True,
|
|
221
|
+
float: False,
|
|
222
|
+
bytes: False,
|
|
223
|
+
bytearray: False,
|
|
224
|
+
list: False,
|
|
225
|
+
dict: False,
|
|
226
|
+
set: False,
|
|
227
|
+
tuple: False,
|
|
228
|
+
bool: False,
|
|
229
|
+
datetime.datetime: False,
|
|
230
|
+
datetime.date: False,
|
|
231
|
+
uuid.UUID: False,
|
|
232
|
+
},
|
|
233
|
+
}
|