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.
Files changed (62) hide show
  1. alpha/__init__.py +0 -0
  2. alpha/adapters/__init__.py +0 -0
  3. alpha/adapters/sqla_unit_of_work.py +120 -0
  4. alpha/domain/__init__.py +0 -0
  5. alpha/domain/models/__init__.py +0 -0
  6. alpha/domain/models/base_model.py +25 -0
  7. alpha/encoder.py +62 -0
  8. alpha/exceptions.py +99 -0
  9. alpha/factories/__init__.py +0 -0
  10. alpha/factories/_type_conversion_matrix.py +233 -0
  11. alpha/factories/_type_mapping.py +29 -0
  12. alpha/factories/class_factories.py +496 -0
  13. alpha/factories/default_field_factory.py +50 -0
  14. alpha/factories/field_iterator.py +188 -0
  15. alpha/factories/logging_handler_factory.py +86 -0
  16. alpha/factories/model_class_factory.py +176 -0
  17. alpha/factories/models/__init__.py +0 -0
  18. alpha/factories/models/factory_classes.py +20 -0
  19. alpha/factories/request_factory.py +211 -0
  20. alpha/factories/response_factory.py +186 -0
  21. alpha/factories/type_factories.py +204 -0
  22. alpha/infra/__init__.py +0 -0
  23. alpha/infra/database/__init__.py +0 -0
  24. alpha/infra/database/sql_alchemy_database.py +159 -0
  25. alpha/infra/database/sql_alchemy_view.py +48 -0
  26. alpha/infra/models/__init__.py +0 -0
  27. alpha/infra/models/filter_operators.py +98 -0
  28. alpha/infra/models/json_patch.py +21 -0
  29. alpha/infra/models/order_by.py +69 -0
  30. alpha/infra/models/query_clause.py +45 -0
  31. alpha/infra/models/search_filter.py +586 -0
  32. alpha/interfaces/__init__.py +0 -0
  33. alpha/interfaces/attrs_instance.py +10 -0
  34. alpha/interfaces/dataclass_instance.py +11 -0
  35. alpha/interfaces/factories.py +102 -0
  36. alpha/interfaces/openapi_model.py +21 -0
  37. alpha/interfaces/patchable.py +8 -0
  38. alpha/interfaces/sql_database.py +36 -0
  39. alpha/interfaces/sql_mapper.py +23 -0
  40. alpha/interfaces/sql_repository.py +380 -0
  41. alpha/interfaces/token_factory.py +56 -0
  42. alpha/interfaces/unit_of_work.py +53 -0
  43. alpha/interfaces/updateable.py +7 -0
  44. alpha/py.typed +0 -0
  45. alpha/repositories/__init__.py +0 -0
  46. alpha/repositories/default_sql_repository.py +679 -0
  47. alpha/repositories/models/__init__.py +0 -0
  48. alpha/repositories/models/repository_model.py +16 -0
  49. alpha/services/__init__.py +0 -0
  50. alpha/services/authentication_service.py +71 -0
  51. alpha/utils/__init__.py +0 -0
  52. alpha/utils/_http_codes.py +148 -0
  53. alpha/utils/is_attrs.py +18 -0
  54. alpha/utils/logging_configurator.py +133 -0
  55. alpha/utils/logging_level_checker.py +26 -0
  56. alpha/utils/response_object.py +26 -0
  57. alpha/utils/version_check.py +17 -0
  58. alpha_python-0.1.0.dist-info/METADATA +22 -0
  59. alpha_python-0.1.0.dist-info/RECORD +62 -0
  60. alpha_python-0.1.0.dist-info/WHEEL +5 -0
  61. alpha_python-0.1.0.dist-info/licenses/LICENSE +21 -0
  62. 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)
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
+ }
@@ -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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -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