alpha-python 0.1.0__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.
- alpha/__init__.py +0 -0
- alpha/adapters/__init__.py +0 -0
- alpha/adapters/sqla_unit_of_work.py +120 -0
- alpha/domain/__init__.py +0 -0
- alpha/domain/models/__init__.py +0 -0
- alpha/domain/models/base_model.py +25 -0
- alpha/encoder.py +62 -0
- alpha/exceptions.py +99 -0
- alpha/factories/__init__.py +0 -0
- alpha/factories/_type_conversion_matrix.py +233 -0
- alpha/factories/_type_mapping.py +29 -0
- alpha/factories/class_factories.py +496 -0
- alpha/factories/default_field_factory.py +50 -0
- alpha/factories/field_iterator.py +188 -0
- alpha/factories/logging_handler_factory.py +86 -0
- alpha/factories/model_class_factory.py +176 -0
- alpha/factories/models/__init__.py +0 -0
- alpha/factories/models/factory_classes.py +20 -0
- alpha/factories/request_factory.py +211 -0
- alpha/factories/response_factory.py +186 -0
- alpha/factories/type_factories.py +204 -0
- alpha/infra/__init__.py +0 -0
- alpha/infra/database/__init__.py +0 -0
- alpha/infra/database/sql_alchemy_database.py +159 -0
- alpha/infra/database/sql_alchemy_view.py +48 -0
- alpha/infra/models/__init__.py +0 -0
- alpha/infra/models/filter_operators.py +98 -0
- alpha/infra/models/json_patch.py +21 -0
- alpha/infra/models/order_by.py +69 -0
- alpha/infra/models/query_clause.py +45 -0
- alpha/infra/models/search_filter.py +586 -0
- alpha/interfaces/__init__.py +0 -0
- alpha/interfaces/attrs_instance.py +10 -0
- alpha/interfaces/dataclass_instance.py +11 -0
- alpha/interfaces/factories.py +102 -0
- alpha/interfaces/openapi_model.py +21 -0
- alpha/interfaces/patchable.py +8 -0
- alpha/interfaces/sql_database.py +36 -0
- alpha/interfaces/sql_mapper.py +23 -0
- alpha/interfaces/sql_repository.py +380 -0
- alpha/interfaces/token_factory.py +56 -0
- alpha/interfaces/unit_of_work.py +53 -0
- alpha/interfaces/updateable.py +7 -0
- alpha/py.typed +0 -0
- alpha/repositories/__init__.py +0 -0
- alpha/repositories/default_sql_repository.py +679 -0
- alpha/repositories/models/__init__.py +0 -0
- alpha/repositories/models/repository_model.py +16 -0
- alpha/services/__init__.py +0 -0
- alpha/services/authentication_service.py +71 -0
- alpha/utils/__init__.py +0 -0
- alpha/utils/_http_codes.py +148 -0
- alpha/utils/is_attrs.py +18 -0
- alpha/utils/logging_configurator.py +133 -0
- alpha/utils/logging_level_checker.py +26 -0
- alpha/utils/response_object.py +26 -0
- alpha/utils/version_check.py +17 -0
- alpha_python-0.1.0.dist-info/METADATA +22 -0
- alpha_python-0.1.0.dist-info/RECORD +62 -0
- alpha_python-0.1.0.dist-info/WHEEL +5 -0
- alpha_python-0.1.0.dist-info/licenses/LICENSE +21 -0
- alpha_python-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from lib.identity_provider import IdentityProvider
|
|
2
|
+
from alpha.interfaces.token_factory import TokenFactory
|
|
3
|
+
from alpha import exceptions
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AuthenticationService:
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
token_factory: TokenFactory,
|
|
10
|
+
identity_provider: IdentityProvider,
|
|
11
|
+
user_id_attribute: str = "user_id",
|
|
12
|
+
) -> None:
|
|
13
|
+
self.token_factory = token_factory
|
|
14
|
+
self.identity_provider = identity_provider
|
|
15
|
+
self.user_id_attribute = user_id_attribute
|
|
16
|
+
|
|
17
|
+
def login(self, username: str, password: str) -> str:
|
|
18
|
+
user = self.identity_provider.authenticate(username, password)
|
|
19
|
+
if not user:
|
|
20
|
+
raise exceptions.UnauthorizedException("Invalid credentials")
|
|
21
|
+
|
|
22
|
+
user_id = getattr(user, self.user_id_attribute, None)
|
|
23
|
+
if not user_id:
|
|
24
|
+
raise exceptions.InternalServerErrorException(
|
|
25
|
+
"User ID attribute missing"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
return self.token_factory.create(user.id, user.to_dict())
|
|
29
|
+
|
|
30
|
+
def logout(self, token: str) -> str:
|
|
31
|
+
if not self.token_factory.validate(token):
|
|
32
|
+
raise exceptions.UnauthorizedException("Invalid token")
|
|
33
|
+
|
|
34
|
+
return "Logged out"
|
|
35
|
+
|
|
36
|
+
def get_user_info(self, token: str) -> dict[str, str]:
|
|
37
|
+
if not self.token_factory.validate(token):
|
|
38
|
+
raise exceptions.UnauthorizedException("Invalid token")
|
|
39
|
+
|
|
40
|
+
payload = self.token_factory.get_payload(token)
|
|
41
|
+
return payload
|
|
42
|
+
|
|
43
|
+
def refresh_token(self, token: str) -> str:
|
|
44
|
+
if not self.token_factory.validate(token):
|
|
45
|
+
raise exceptions.UnauthorizedException("Invalid token")
|
|
46
|
+
|
|
47
|
+
payload = self.token_factory.get_payload(token)
|
|
48
|
+
user_id = payload.get(self.user_id_attribute)
|
|
49
|
+
if not user_id:
|
|
50
|
+
raise exceptions.BadRequestException("Invalid token payload")
|
|
51
|
+
|
|
52
|
+
return self.token_factory.create(user_id, payload)
|
|
53
|
+
|
|
54
|
+
def change_password(
|
|
55
|
+
self,
|
|
56
|
+
username: str,
|
|
57
|
+
password: str,
|
|
58
|
+
new_password: str,
|
|
59
|
+
) -> bool:
|
|
60
|
+
user = self.identity_provider.authenticate(username, password)
|
|
61
|
+
if not user:
|
|
62
|
+
raise exceptions.UnauthorizedException("Invalid credentials")
|
|
63
|
+
|
|
64
|
+
return self.identity_provider.change_password(username, new_password)
|
|
65
|
+
|
|
66
|
+
def pretend_login(self, user_id: str) -> str:
|
|
67
|
+
user_info = self.identity_provider.get_user_info(user_id)
|
|
68
|
+
if not user_info:
|
|
69
|
+
raise exceptions.NotFoundException("User not found")
|
|
70
|
+
|
|
71
|
+
return self.token_factory.create(user_id, user_info)
|
alpha/utils/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
http_codes_en: dict[int, tuple[str, str]] = {
|
|
2
|
+
100: ('Continue', 'Request received, please continue'),
|
|
3
|
+
101: (
|
|
4
|
+
'Switching Protocols',
|
|
5
|
+
'Switching to new protocol; obey Upgrade header',
|
|
6
|
+
),
|
|
7
|
+
200: ('OK', 'Request fulfilled, document follows'),
|
|
8
|
+
201: ('Created', 'Document created, URL follows'),
|
|
9
|
+
202: ('Accepted', 'Request accepted, processing continues off-line'),
|
|
10
|
+
203: ('Non-Authoritative Information', 'Request fulfilled from cache'),
|
|
11
|
+
204: ('No Content', 'Request fulfilled, nothing follows'),
|
|
12
|
+
205: ('Reset Content', 'Clear input form for further input.'),
|
|
13
|
+
206: ('Partial Content', 'Partial content follows.'),
|
|
14
|
+
300: ('Multiple Choices', 'Object has several resources -- see URI list'),
|
|
15
|
+
301: ('Moved Permanently', 'Object moved permanently -- see URI list'),
|
|
16
|
+
302: ('Found', 'Object moved temporarily -- see URI list'),
|
|
17
|
+
303: ('See Other', 'Object moved -- see Method and URL list'),
|
|
18
|
+
304: ('Not Modified', 'Document has not changed since given time'),
|
|
19
|
+
305: (
|
|
20
|
+
'Use Proxy',
|
|
21
|
+
'You must use proxy specified in Location to access this ' 'resource.',
|
|
22
|
+
),
|
|
23
|
+
307: ('Temporary Redirect', 'Object moved temporarily -- see URI list'),
|
|
24
|
+
400: ('Bad Request', 'Bad request syntax or unsupported method'),
|
|
25
|
+
401: ('Unauthorized', 'No permission -- see authorization schemes'),
|
|
26
|
+
402: ('Payment Required', 'No payment -- see charging schemes'),
|
|
27
|
+
403: ('Forbidden', 'Request forbidden -- authorization will not help'),
|
|
28
|
+
404: ('Not Found', 'Nothing matches the given URI'),
|
|
29
|
+
405: (
|
|
30
|
+
'Method Not Allowed',
|
|
31
|
+
'Specified method is invalid for this server.',
|
|
32
|
+
),
|
|
33
|
+
406: ('Not Acceptable', 'URI not available in preferred format.'),
|
|
34
|
+
407: (
|
|
35
|
+
'Proxy Authentication Required',
|
|
36
|
+
'You must authenticate with ' 'this proxy before proceeding.',
|
|
37
|
+
),
|
|
38
|
+
408: ('Request Timeout', 'Request timed out; try again later.'),
|
|
39
|
+
409: ('Conflict', 'Request conflict.'),
|
|
40
|
+
410: ('Gone', 'URI no longer exists and has been permanently removed.'),
|
|
41
|
+
411: ('Length Required', 'Client must specify Content-Length.'),
|
|
42
|
+
412: ('Precondition Failed', 'Precondition in headers is false.'),
|
|
43
|
+
413: ('Request Entity Too Large', 'Entity is too large.'),
|
|
44
|
+
414: ('Request-URI Too Long', 'URI is too long.'),
|
|
45
|
+
415: ('Unsupported Media Type', 'Entity body in unsupported format.'),
|
|
46
|
+
416: ('Requested Range Not Satisfiable', 'Cannot satisfy request range.'),
|
|
47
|
+
417: ('Expectation Failed', 'Expect condition could not be satisfied.'),
|
|
48
|
+
500: ('Internal Server Error', 'Server got itself in trouble'),
|
|
49
|
+
501: ('Not Implemented', 'Server does not support this operation'),
|
|
50
|
+
502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),
|
|
51
|
+
503: (
|
|
52
|
+
'Service Unavailable',
|
|
53
|
+
'The server cannot process the request due to a high load',
|
|
54
|
+
),
|
|
55
|
+
504: (
|
|
56
|
+
'Gateway Timeout',
|
|
57
|
+
'The gateway server did not receive a timely response',
|
|
58
|
+
),
|
|
59
|
+
505: ('HTTP Version Not Supported', 'Cannot fulfill request.'),
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
http_codes_nl: dict[int, tuple[str, str]] = {
|
|
63
|
+
100: ('Doorgaan', 'Verzoek ontvangen, gelieve door te gaan'),
|
|
64
|
+
101: (
|
|
65
|
+
'Protocol Wisselen',
|
|
66
|
+
'Overstappen naar nieuw protocol; gehoorzaam de Upgrade-header',
|
|
67
|
+
),
|
|
68
|
+
200: ('OK', 'Verzoek ingewilligd, document volgt'),
|
|
69
|
+
201: ('Gecreëerd', 'Document aangemaakt, URL volgt'),
|
|
70
|
+
202: (
|
|
71
|
+
'Geaccepteerd',
|
|
72
|
+
'Verzoek geaccepteerd, verwerking gaat offline verder',
|
|
73
|
+
),
|
|
74
|
+
203: ('Niet-Autoritatieve Informatie', 'Verzoek vervuld vanuit cache'),
|
|
75
|
+
204: ('Geen Inhoud', 'Verzoek vervuld, er volgt niets'),
|
|
76
|
+
205: ('Inhoud Resetten', 'Formulier leegmaken voor verdere invoer.'),
|
|
77
|
+
206: ('Gedeeltelijke Inhoud', 'Gedeeltelijke inhoud volgt.'),
|
|
78
|
+
300: (
|
|
79
|
+
'Meerdere Opties',
|
|
80
|
+
'Object heeft verschillende bronnen -- zie URI-lijst',
|
|
81
|
+
),
|
|
82
|
+
301: (
|
|
83
|
+
'Permanent Verplaatst',
|
|
84
|
+
'Object permanent verplaatst -- zie URI-lijst',
|
|
85
|
+
),
|
|
86
|
+
302: ('Gevonden', 'Object tijdelijk verplaatst -- zie URI-lijst'),
|
|
87
|
+
303: ('Zie Andere', 'Object verplaatst -- zie Methode en URL-lijst'),
|
|
88
|
+
304: (
|
|
89
|
+
'Niet Gewijzigd',
|
|
90
|
+
'Document is niet gewijzigd sinds de opgegeven tijd',
|
|
91
|
+
),
|
|
92
|
+
305: (
|
|
93
|
+
'Gebruik Proxy',
|
|
94
|
+
'Je moet de proxy gebruiken die is opgegeven in Locatie om toegang te krijgen tot deze bron.',
|
|
95
|
+
),
|
|
96
|
+
307: (
|
|
97
|
+
'Tijdelijke Omleiding',
|
|
98
|
+
'Object tijdelijk verplaatst -- zie URI-lijst',
|
|
99
|
+
),
|
|
100
|
+
400: (
|
|
101
|
+
'Slecht Verzoek',
|
|
102
|
+
'Slechte verzoeksyntax of niet-ondersteunde methode',
|
|
103
|
+
),
|
|
104
|
+
401: ('Ongeautoriseerd', 'Geen toestemming -- zie autorisatieschema\'s'),
|
|
105
|
+
402: ('Betaling Vereist', 'Geen betaling -- zie tariefschema\'s'),
|
|
106
|
+
403: ('Verboden', 'Verzoek verboden -- autorisatie zal niet helpen'),
|
|
107
|
+
404: ('Niet Gevonden', 'Niets komt overeen met de opgegeven URI'),
|
|
108
|
+
405: (
|
|
109
|
+
'Methode Niet Toegestaan',
|
|
110
|
+
'Opgegeven methode is ongeldig voor deze server.',
|
|
111
|
+
),
|
|
112
|
+
406: ('Niet Acceptabel', 'URI niet beschikbaar in het gewenste formaat.'),
|
|
113
|
+
407: (
|
|
114
|
+
'Proxy-Authenticatie Vereist',
|
|
115
|
+
'Je moet je authenticeren bij deze proxy voordat je verder gaat.',
|
|
116
|
+
),
|
|
117
|
+
408: ('Verzoek Timeout', 'Verzoek is verlopen; probeer later opnieuw.'),
|
|
118
|
+
409: ('Conflict', 'Verzoekconflict.'),
|
|
119
|
+
410: ('Verdwenen', 'URI bestaat niet meer en is permanent verwijderd.'),
|
|
120
|
+
411: ('Lengte Vereist', 'Client moet Content-Length specificeren.'),
|
|
121
|
+
412: ('Voorwaarde Mislukt', 'Voorwaarde in headers is onwaar.'),
|
|
122
|
+
413: ('Verzoek Entiteit Te Groot', 'Entiteit is te groot.'),
|
|
123
|
+
414: ('Verzoek-URI Te Lang', 'URI is te lang.'),
|
|
124
|
+
415: (
|
|
125
|
+
'Niet Ondersteund Mediatype',
|
|
126
|
+
'Entiteitslichaam in een niet-ondersteund formaat.',
|
|
127
|
+
),
|
|
128
|
+
416: (
|
|
129
|
+
'Gevraagd Bereik Niet Voldaan',
|
|
130
|
+
'Kan het verzoeksbereik niet voldoen.',
|
|
131
|
+
),
|
|
132
|
+
417: ('Verwachting Mislukt', 'Verwachting kan niet worden vervuld.'),
|
|
133
|
+
500: ('Interne Serverfout', 'Server heeft problemen met zichzelf'),
|
|
134
|
+
501: ('Niet Geïmplementeerd', 'Server ondersteunt deze bewerking niet'),
|
|
135
|
+
502: (
|
|
136
|
+
'Slechte Gateway',
|
|
137
|
+
'Ongeldige reacties van een andere server/proxy.',
|
|
138
|
+
),
|
|
139
|
+
503: (
|
|
140
|
+
'Service Niet Beschikbaar',
|
|
141
|
+
'De server kan het verzoek niet verwerken vanwege een hoge belasting',
|
|
142
|
+
),
|
|
143
|
+
504: (
|
|
144
|
+
'Gateway Timeout',
|
|
145
|
+
'De gateway-server heeft geen tijdige reactie ontvangen',
|
|
146
|
+
),
|
|
147
|
+
505: ('HTTP-Versie Niet Ondersteund', 'Kan het verzoek niet vervullen.'),
|
|
148
|
+
}
|
alpha/utils/is_attrs.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def is_attrs(obj: Any) -> bool:
|
|
5
|
+
"""Validates if an object is an attrs class or instance
|
|
6
|
+
|
|
7
|
+
Parameters
|
|
8
|
+
----------
|
|
9
|
+
obj : Any
|
|
10
|
+
An object which will be checked to be an attrs class or instance
|
|
11
|
+
|
|
12
|
+
Returns
|
|
13
|
+
-------
|
|
14
|
+
bool
|
|
15
|
+
Returns True if obj is an attrs class or instance
|
|
16
|
+
"""
|
|
17
|
+
cls = obj if isinstance(obj, type) else type(obj)
|
|
18
|
+
return hasattr(cls, '__attrs_attrs__')
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""Contains LoggingConfigurator & GunicornLogger classes"""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from logging.config import dictConfig
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from gunicorn import glogging
|
|
8
|
+
|
|
9
|
+
from alpha.factories.logging_handler_factory import LoggingHandlerFactory
|
|
10
|
+
|
|
11
|
+
FORMAT = " | ".join(
|
|
12
|
+
[
|
|
13
|
+
"%(asctime)s",
|
|
14
|
+
"%(name)s",
|
|
15
|
+
"%(levelname)s",
|
|
16
|
+
"%(module)s.%(funcName)s",
|
|
17
|
+
"%(message)s",
|
|
18
|
+
]
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class LoggingConfigurator:
|
|
23
|
+
"""To create a default logger"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
config: dict[str, Any] | None = None,
|
|
28
|
+
fmt: str = FORMAT,
|
|
29
|
+
handlers: list[dict[str, Any]] | None = None,
|
|
30
|
+
level: str | int = logging.INFO,
|
|
31
|
+
stream: str = "stdout",
|
|
32
|
+
logger_name: str = "root",
|
|
33
|
+
) -> None:
|
|
34
|
+
"""_summary_
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
config, optional
|
|
39
|
+
_description_, by default None
|
|
40
|
+
fmt, optional
|
|
41
|
+
_description_, by default FORMAT
|
|
42
|
+
handlers, optional
|
|
43
|
+
_description_, by default None
|
|
44
|
+
level, optional
|
|
45
|
+
_description_, by default logging.INFO
|
|
46
|
+
stream, optional
|
|
47
|
+
_description_, by default "stdout"
|
|
48
|
+
logger_name, optional
|
|
49
|
+
_description_, by default 'root'
|
|
50
|
+
"""
|
|
51
|
+
if not fmt:
|
|
52
|
+
fmt = FORMAT
|
|
53
|
+
if not stream:
|
|
54
|
+
stream = "stdout"
|
|
55
|
+
if not level:
|
|
56
|
+
level = logging.INFO
|
|
57
|
+
if not handlers:
|
|
58
|
+
handlers = []
|
|
59
|
+
|
|
60
|
+
logging_level = (
|
|
61
|
+
getattr(logging, level.upper())
|
|
62
|
+
if isinstance(level, str)
|
|
63
|
+
else level
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
default_config: dict[str, Any] = {
|
|
67
|
+
"version": 1,
|
|
68
|
+
"formatters": {"default": {"format": fmt}},
|
|
69
|
+
"handlers": {
|
|
70
|
+
"console": {
|
|
71
|
+
"class": "logging.StreamHandler",
|
|
72
|
+
"level": logging_level,
|
|
73
|
+
"formatter": "default",
|
|
74
|
+
"stream": f"ext://sys.{stream}",
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
logger_name: {"level": level, "handlers": ["console"]},
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
for ix, handler in enumerate(handlers):
|
|
81
|
+
handler_name = f"handler_{ix}"
|
|
82
|
+
handler_obj = LoggingHandlerFactory.parse(handler)
|
|
83
|
+
default_config["handlers"].update({handler_name: handler_obj})
|
|
84
|
+
|
|
85
|
+
default_config[logger_name]["handlers"].append(handler_name)
|
|
86
|
+
|
|
87
|
+
handler_level = getattr(logging, handler_obj["level"])
|
|
88
|
+
if handler_level < logging_level:
|
|
89
|
+
logging_level = handler_level
|
|
90
|
+
default_config[logger_name]["level"] = logging_level
|
|
91
|
+
|
|
92
|
+
if config:
|
|
93
|
+
dictConfig(config)
|
|
94
|
+
else:
|
|
95
|
+
dictConfig(default_config)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class GunicornLogger(glogging.Logger):
|
|
99
|
+
"""This class overrides the default gunicorn logger."""
|
|
100
|
+
|
|
101
|
+
def setup(self, cfg: Any):
|
|
102
|
+
"""Set the FORMAT on the gunicorn logging handler.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
cfg: gunicorn glogging configuration
|
|
106
|
+
"""
|
|
107
|
+
super().setup(cfg) # type: ignore
|
|
108
|
+
|
|
109
|
+
self._set_handler( # type: ignore
|
|
110
|
+
log=self.error_log,
|
|
111
|
+
output=cfg.errorlog,
|
|
112
|
+
fmt=logging.Formatter(fmt=FORMAT),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def logging_level_checker(level: str | int, logger_name: str = "root") -> bool:
|
|
117
|
+
"""A simple function to check if a logging level is active.
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
level : Union[str, int]
|
|
122
|
+
The logging level as a string or the corresponding integer
|
|
123
|
+
|
|
124
|
+
Returns
|
|
125
|
+
-------
|
|
126
|
+
bool
|
|
127
|
+
Returns if the logging level is active
|
|
128
|
+
"""
|
|
129
|
+
if isinstance(level, str):
|
|
130
|
+
level_int = getattr(logging, level.upper())
|
|
131
|
+
else:
|
|
132
|
+
level_int = level
|
|
133
|
+
return logging.getLogger(logger_name).level <= level_int
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""_summary_
|
|
2
|
+
"""
|
|
3
|
+
import logging
|
|
4
|
+
from logging import getLogger
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def logging_level_checker(level: str | int, logger_name: str = "root") -> bool:
|
|
8
|
+
"""A simple function to check if a logging level is active.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
----------
|
|
12
|
+
level : str | int
|
|
13
|
+
The logging level as a string or the corresponding integer
|
|
14
|
+
logger_name : str, optional
|
|
15
|
+
The logger name, by default "root"
|
|
16
|
+
|
|
17
|
+
Returns
|
|
18
|
+
-------
|
|
19
|
+
bool
|
|
20
|
+
Returns if the logging level is active
|
|
21
|
+
"""
|
|
22
|
+
if isinstance(level, str):
|
|
23
|
+
level_int = getattr(logging, level.upper())
|
|
24
|
+
else:
|
|
25
|
+
level_int = int(level)
|
|
26
|
+
return getLogger(logger_name).level <= level_int
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from alpha.utils._http_codes import http_codes_en
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def create_response_object(
|
|
7
|
+
status_code: int,
|
|
8
|
+
status_message: str,
|
|
9
|
+
data: Any | None = None,
|
|
10
|
+
data_type: str = "application/json",
|
|
11
|
+
http_codes: dict[int, tuple[str, str]] = http_codes_en,
|
|
12
|
+
) -> tuple[dict[str, Any], int]:
|
|
13
|
+
obj = {
|
|
14
|
+
"detail": status_message,
|
|
15
|
+
"status": status_code,
|
|
16
|
+
"title": http_codes[status_code][0],
|
|
17
|
+
"type": "about:blank" if not data_type else data_type,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if data is not None:
|
|
21
|
+
obj["data"] = data
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
obj,
|
|
25
|
+
status_code,
|
|
26
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def minor_version_gte(minor: int) -> bool:
|
|
5
|
+
"""Check is the minor python version is greater then or equal to the minor
|
|
6
|
+
parameter value
|
|
7
|
+
|
|
8
|
+
Parameters
|
|
9
|
+
----------
|
|
10
|
+
minor
|
|
11
|
+
Minor version value
|
|
12
|
+
|
|
13
|
+
Returns
|
|
14
|
+
-------
|
|
15
|
+
True if the runtime minor version is greater then or equal to the value
|
|
16
|
+
"""
|
|
17
|
+
return sys.version_info.minor >= minor
|
|
@@ -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,62 @@
|
|
|
1
|
+
alpha/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
alpha/encoder.py,sha256=ZKPHnG4DT6azne3Sh9tNOuPO9s8xnjlr64CQ0e2abjI,1924
|
|
3
|
+
alpha/exceptions.py,sha256=Hl1gBW3e4cx0M6vRAgPKvbbWKX4EA9feh_jD4RCa_6Y,1859
|
|
4
|
+
alpha/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
alpha/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
alpha/adapters/sqla_unit_of_work.py,sha256=rOgojbXTWx32UnUiPjU67zaevjjuQTCMCNB6cuXcQcM,3731
|
|
7
|
+
alpha/domain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
alpha/domain/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
alpha/domain/models/base_model.py,sha256=VzPDUdizaDAydvv3PfSqWwkUtzaBSKv1et7yPcKEL44,837
|
|
10
|
+
alpha/factories/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
alpha/factories/_type_conversion_matrix.py,sha256=mhMYpus6OFE0sZB0gQ-b1ndIOhiA1ScprvDa9tLANAM,5055
|
|
12
|
+
alpha/factories/_type_mapping.py,sha256=f8cRfu8KUfw1ggY0Txs6fEX2e6GaXrsNcc2SCeYFRHM,789
|
|
13
|
+
alpha/factories/class_factories.py,sha256=MDUnWQC1a3OUE0HyKEZx6watdMes8BjjoZQaOzBWfVo,15582
|
|
14
|
+
alpha/factories/default_field_factory.py,sha256=ZvPU6BdrdELmZNXIeTmRp_YOCIscWFC9W6s05qXyXrk,1758
|
|
15
|
+
alpha/factories/field_iterator.py,sha256=nh0GD2m0GxrQ8kCB5Y287PLd_XqfDbFRe0T8bDYbUy0,5168
|
|
16
|
+
alpha/factories/logging_handler_factory.py,sha256=H9gVS1rNt5Jln3C_2EbOvJG-gqS9ksTsYUIx2UK7gVk,3059
|
|
17
|
+
alpha/factories/model_class_factory.py,sha256=vXPyTT3--Qy43_gRX73pyr9YGheZPfSWexSfICK4LMo,5536
|
|
18
|
+
alpha/factories/request_factory.py,sha256=271gFfiDf5ZgtDcB0CQYG4ppbj-XuKic2ENWVNMrg2s,6704
|
|
19
|
+
alpha/factories/response_factory.py,sha256=QFtOq2n7cYkBeLoz-mZdBtHkVsJiQ2rHNF6SdP_nz_E,6399
|
|
20
|
+
alpha/factories/type_factories.py,sha256=_cBJQQtccnbq-fThP402J1YuI5vM0BlmSJWGyZi0MTU,6017
|
|
21
|
+
alpha/factories/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
alpha/factories/models/factory_classes.py,sha256=jpa9KQRQ8b3Y554zx5vad5aAisT1Or_YXD9C6-SgAsk,497
|
|
23
|
+
alpha/infra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
|
+
alpha/infra/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
+
alpha/infra/database/sql_alchemy_database.py,sha256=jPuXmhhKMBysKSfZyNEQ2gI8tm0rOiHSwnxuG3ofSSY,4641
|
|
26
|
+
alpha/infra/database/sql_alchemy_view.py,sha256=zuq18ynA_zXkUTv8cZ4HSzYRt21U3EonVs_UHTwP_Do,1419
|
|
27
|
+
alpha/infra/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
+
alpha/infra/models/filter_operators.py,sha256=hQ4Eq6QYlmWJxVSKORtbS45qb5A8qBBWJzrKVP6pYak,2588
|
|
29
|
+
alpha/infra/models/json_patch.py,sha256=PlJkhV6cyacIdPi7aTqFwbdA_XOECoIynljX6wfltLc,615
|
|
30
|
+
alpha/infra/models/order_by.py,sha256=gp0Y43wTaoetwZevTw7BQrO7tao8HFQOZ8VihXrsIoo,1892
|
|
31
|
+
alpha/infra/models/query_clause.py,sha256=bCFCvxzZgDlDj08_6XVfes-jxF5HdM5aVeAfhVIr9z0,1527
|
|
32
|
+
alpha/infra/models/search_filter.py,sha256=IQNW3HWSsN4BFzx7XEwGIkWHMI3iu6kpLTz4KhPwYSU,18149
|
|
33
|
+
alpha/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
+
alpha/interfaces/attrs_instance.py,sha256=56PjY6s0FuoX63EJusFDXsPFJpxRDGZwbD-R19j7RIw,257
|
|
35
|
+
alpha/interfaces/dataclass_instance.py,sha256=BSau0UxwdhuXsp6oKsWnptSx6QTt2uT-vcheqgfsSos,307
|
|
36
|
+
alpha/interfaces/factories.py,sha256=l2wZ47UpVhrVjKtHI9-aU8Q_cbGyIh5EdMve48NcBX4,2547
|
|
37
|
+
alpha/interfaces/openapi_model.py,sha256=9QayfwbwTg_3-reFso_ktwNqGI2f2C4AQOAPvPHH4OQ,443
|
|
38
|
+
alpha/interfaces/patchable.py,sha256=iV091FX5HkwOhfXswYHCi_EJqCLDPQBgi_ia8mZ_1jg,265
|
|
39
|
+
alpha/interfaces/sql_database.py,sha256=H52NR1ti2j9G9zJsibPtKmXL7WdHOzeSyPXO4Zq9wlA,996
|
|
40
|
+
alpha/interfaces/sql_mapper.py,sha256=NyPYc4DuG9HBd9LO8ooYidD-rv1poSty5GmzW6jmE8g,465
|
|
41
|
+
alpha/interfaces/sql_repository.py,sha256=yMT95fti5xlg0lM-c0EEpkt9j44JJwNe9Mc2ac5MKZg,9032
|
|
42
|
+
alpha/interfaces/token_factory.py,sha256=lOt50hGMpOM2fCkvd7iDORlfYrjB3O6JEmRXGT4QdCA,1402
|
|
43
|
+
alpha/interfaces/unit_of_work.py,sha256=yQ0Zexj3gVOzH7pjwF_9tvAKUPvzCielvgdzzCgLuZA,870
|
|
44
|
+
alpha/interfaces/updateable.py,sha256=7Vq6kzNa8hyTVk_vzjUdM8hUyRWclHt7L3erRlo7L2U,173
|
|
45
|
+
alpha/repositories/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
|
+
alpha/repositories/default_sql_repository.py,sha256=krdG2TPp6QvMXRdzLT8agqzMv5ijBZjIsf16aU7lhio,19920
|
|
47
|
+
alpha/repositories/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
|
+
alpha/repositories/models/repository_model.py,sha256=toIEZieDWtXpcHF61d2x5cN1l8sH3KW_5ATcrwIKqyQ,363
|
|
49
|
+
alpha/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
50
|
+
alpha/services/authentication_service.py,sha256=qf02lTTDG2IJs6avXOeWRMvnUnVheEv3d4NZf8rnpG4,2510
|
|
51
|
+
alpha/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
52
|
+
alpha/utils/_http_codes.py,sha256=QLU43JnjvYGsv6u_quRP7jzgg996boa4-a-yKcSw9Bo,6558
|
|
53
|
+
alpha/utils/is_attrs.py,sha256=LlLozdSnKEjFtVwJm9AWf7NAIkBPotnpbhFmwz3f4AI,432
|
|
54
|
+
alpha/utils/logging_configurator.py,sha256=gnN1mlV9sPnSrWvR8jrGuBrc8pYWeQ2cyTpzCkWDOFM,3741
|
|
55
|
+
alpha/utils/logging_level_checker.py,sha256=x3MrwV0aqmtd-YOb5VxZzNm6MKsX3YtaVxUQ6dT0E4E,669
|
|
56
|
+
alpha/utils/response_object.py,sha256=fb8OrWTPHWcyv-BnwqB1cBoWnTrBv5u6kIQby_8Qzo8,612
|
|
57
|
+
alpha/utils/version_check.py,sha256=W8v69hDbrr0VvJ40gpFmXMtVawrDmUz_YGWssKUTmVE,380
|
|
58
|
+
alpha_python-0.1.0.dist-info/licenses/LICENSE,sha256=g04fgRYvHhkjGRbn6pYcdlqErAMTv21Sqv4Yxq2DYz8,1066
|
|
59
|
+
alpha_python-0.1.0.dist-info/METADATA,sha256=EGfDKRiF5stV_VCQFLmATFAjZmpHg8UpAUyB8IHar54,998
|
|
60
|
+
alpha_python-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
61
|
+
alpha_python-0.1.0.dist-info/top_level.txt,sha256=tqmNnOmi2RSSiPo99C03fD5Cc3r9za9xTjPAoQC1EGA,6
|
|
62
|
+
alpha_python-0.1.0.dist-info/RECORD,,
|
|
@@ -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 @@
|
|
|
1
|
+
alpha
|