alpha-python 0.5.1__tar.gz → 0.6.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.
Files changed (169) hide show
  1. {alpha_python-0.5.1 → alpha_python-0.6.0}/PKG-INFO +23 -6
  2. {alpha_python-0.5.1 → alpha_python-0.6.0}/README.md +4 -2
  3. {alpha_python-0.5.1 → alpha_python-0.6.0}/pyproject.toml +59 -5
  4. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/__init__.py +57 -5
  5. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/adapters/rest_api_unit_of_work.py +9 -3
  6. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/adapters/sqla_unit_of_work.py +23 -5
  7. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/containers/container.py +52 -47
  8. alpha_python-0.6.0/src/alpha/domain/__init__.py +21 -0
  9. alpha_python-0.6.0/src/alpha/domain/models/__init__.py +21 -0
  10. alpha_python-0.6.0/src/alpha/domain/models/base_model.py +61 -0
  11. alpha_python-0.6.0/src/alpha/domain/models/group.py +85 -0
  12. alpha_python-0.6.0/src/alpha/domain/models/life_cycle_base.py +29 -0
  13. alpha_python-0.5.1/src/alpha/domain/models/user.py → alpha_python-0.6.0/src/alpha/domain/models/role.py +55 -58
  14. alpha_python-0.6.0/src/alpha/domain/models/user.py +143 -0
  15. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/encoder.py +21 -0
  16. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/class_factories.py +49 -22
  17. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/default_field_factory.py +1 -0
  18. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/field_iterator.py +8 -2
  19. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/jwt_factory.py +54 -16
  20. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/logging_handler_factory.py +7 -5
  21. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/model_class_factory.py +6 -3
  22. alpha_python-0.6.0/src/alpha/factories/models/factory_classes.py +39 -0
  23. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/password_factory.py +32 -15
  24. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/request_factory.py +24 -13
  25. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/response_factory.py +5 -2
  26. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/type_factories.py +16 -2
  27. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/api_generate_handler.py +32 -33
  28. alpha_python-0.6.0/src/alpha/handlers/run-api.sh +4 -0
  29. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/controller.mustache +115 -15
  30. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/controller_test.mustache +1 -1
  31. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/model.mustache +7 -1
  32. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/setup.mustache +0 -19
  33. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/infra/__init__.py +14 -5
  34. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/infra/connectors/__init__.py +9 -4
  35. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/infra/connectors/ldap_connector.py +38 -29
  36. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/infra/connectors/oidc_connector.py +1 -1
  37. {alpha_python-0.5.1/src/alpha/infra/databases → alpha_python-0.6.0/src/alpha/infra/connectors}/sql_alchemy.py +42 -38
  38. alpha_python-0.6.0/src/alpha/infra/databases/sql_alchemy.py +9 -0
  39. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/infra/models/filter_operators.py +6 -1
  40. alpha_python-0.6.0/src/alpha/infra/models/json_patch.py +45 -0
  41. alpha_python-0.6.0/src/alpha/infra/models/order_by.py +141 -0
  42. alpha_python-0.6.0/src/alpha/infra/models/query_clause.py +68 -0
  43. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/infra/models/search_filter.py +96 -0
  44. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/interfaces/__init__.py +2 -2
  45. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/interfaces/api_repository.py +11 -5
  46. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/interfaces/factories.py +5 -2
  47. alpha_python-0.6.0/src/alpha/interfaces/patchable.py +24 -0
  48. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/interfaces/providers.py +4 -4
  49. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/interfaces/sql_mapper.py +6 -3
  50. alpha_python-0.6.0/src/alpha/interfaces/sql_repository.py +356 -0
  51. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/interfaces/token_factory.py +7 -7
  52. alpha_python-0.6.0/src/alpha/interfaces/unit_of_work.py +70 -0
  53. alpha_python-0.6.0/src/alpha/interfaces/updatable.py +21 -0
  54. alpha_python-0.6.0/src/alpha/mixins/__init__.py +5 -0
  55. alpha_python-0.6.0/src/alpha/mixins/group_lifecycle.py +159 -0
  56. alpha_python-0.6.0/src/alpha/mixins/user_lifecycle.py +188 -0
  57. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/providers/database_provider.py +5 -4
  58. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/providers/ldap_provider.py +82 -66
  59. alpha_python-0.6.0/src/alpha/providers/models/credentials.py +43 -0
  60. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/providers/models/identity.py +15 -6
  61. alpha_python-0.6.0/src/alpha/providers/models/token.py +111 -0
  62. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/providers/oidc_provider.py +56 -33
  63. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/repositories/rest_api_repository.py +23 -24
  64. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/repositories/sql_alchemy_repository.py +179 -133
  65. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/services/authentication_service.py +264 -47
  66. alpha_python-0.6.0/src/alpha/services/models/__init__.py +0 -0
  67. alpha_python-0.6.0/src/alpha/services/models/cookie.py +5 -0
  68. alpha_python-0.6.0/src/alpha/services/user_lifecycle_management.py +63 -0
  69. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/utils/__init__.py +2 -0
  70. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/utils/_http_codes.py +8 -0
  71. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/utils/is_attrs.py +1 -1
  72. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/utils/is_pydantic.py +1 -1
  73. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/utils/logging_configurator.py +18 -16
  74. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/utils/logging_level_checker.py +3 -3
  75. alpha_python-0.6.0/src/alpha/utils/openapi_test/__init__.py +0 -0
  76. alpha_python-0.6.0/src/alpha/utils/openapi_test/container.py +181 -0
  77. alpha_python-0.6.0/src/alpha/utils/openapi_test/exceptions.py +17 -0
  78. alpha_python-0.6.0/src/alpha/utils/openapi_test/models.py +83 -0
  79. alpha_python-0.6.0/src/alpha/utils/openapi_test/orm.py +90 -0
  80. alpha_python-0.6.0/src/alpha/utils/openapi_test/service.py +172 -0
  81. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/utils/request_headers.py +8 -0
  82. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/utils/response_object.py +9 -7
  83. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/utils/secret_generator.py +2 -2
  84. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha_python.egg-info/PKG-INFO +23 -6
  85. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha_python.egg-info/SOURCES.txt +13 -1
  86. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha_python.egg-info/requires.txt +4 -4
  87. alpha_python-0.6.0/tests/test_cli.py +168 -0
  88. alpha_python-0.5.1/src/alpha/domain/__init__.py +0 -10
  89. alpha_python-0.5.1/src/alpha/domain/models/__init__.py +0 -10
  90. alpha_python-0.5.1/src/alpha/domain/models/base_model.py +0 -25
  91. alpha_python-0.5.1/src/alpha/domain/models/group.py +0 -35
  92. alpha_python-0.5.1/src/alpha/domain/models/life_cycle_base.py +0 -10
  93. alpha_python-0.5.1/src/alpha/factories/models/factory_classes.py +0 -20
  94. alpha_python-0.5.1/src/alpha/handlers/run-api.sh +0 -12
  95. alpha_python-0.5.1/src/alpha/handlers/templates/python-flask/requirements.mustache +0 -19
  96. alpha_python-0.5.1/src/alpha/infra/models/json_patch.py +0 -19
  97. alpha_python-0.5.1/src/alpha/infra/models/order_by.py +0 -69
  98. alpha_python-0.5.1/src/alpha/infra/models/query_clause.py +0 -43
  99. alpha_python-0.5.1/src/alpha/interfaces/patchable.py +0 -8
  100. alpha_python-0.5.1/src/alpha/interfaces/sql_repository.py +0 -369
  101. alpha_python-0.5.1/src/alpha/interfaces/unit_of_work.py +0 -53
  102. alpha_python-0.5.1/src/alpha/interfaces/updateable.py +0 -7
  103. alpha_python-0.5.1/src/alpha/mixins/__init__.py +0 -3
  104. alpha_python-0.5.1/src/alpha/providers/models/credentials.py +0 -21
  105. alpha_python-0.5.1/src/alpha/providers/models/token.py +0 -55
  106. alpha_python-0.5.1/src/alpha/services/user_lifecycle_management.py +0 -331
  107. {alpha_python-0.5.1 → alpha_python-0.6.0}/LICENSE +0 -0
  108. {alpha_python-0.5.1 → alpha_python-0.6.0}/setup.cfg +0 -0
  109. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/adapters/__init__.py +0 -0
  110. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/cli.py +0 -0
  111. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/containers/__init__.py +0 -0
  112. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/exceptions.py +0 -0
  113. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/__init__.py +0 -0
  114. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/_type_conversion_matrix.py +0 -0
  115. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/_type_mapping.py +0 -0
  116. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/factories/models/__init__.py +0 -0
  117. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/__init__.py +0 -0
  118. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/api_run_handler.py +0 -0
  119. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/base_handler.py +0 -0
  120. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/gen-code.sh +0 -0
  121. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/models/__init__.py +0 -0
  122. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/models/argument.py +0 -0
  123. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/models/command.py +0 -0
  124. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/models/section.py +0 -0
  125. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/models/subparser.py +0 -0
  126. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/__init__.py +0 -0
  127. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/Dockerfile.mustache +0 -0
  128. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/README.mustache +0 -0
  129. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/__init__model.mustache +0 -0
  130. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/__init__test.mustache +0 -0
  131. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/__main__.mustache +0 -0
  132. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/base_model.mustache +0 -0
  133. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/dockerignore.mustache +0 -0
  134. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/encoder.mustache +0 -0
  135. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/git_push.sh.mustache +0 -0
  136. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/gitignore.mustache +0 -0
  137. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/openapi.mustache +0 -0
  138. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/param_type.mustache +0 -0
  139. /alpha_python-0.5.1/src/alpha/providers/api_key_provider.py → /alpha_python-0.6.0/src/alpha/handlers/templates/python-flask/requirements.mustache +0 -0
  140. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/security_controller_.mustache +0 -0
  141. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/test-requirements.mustache +0 -0
  142. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/tox.mustache +0 -0
  143. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/travis.mustache +0 -0
  144. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/typing_utils.mustache +0 -0
  145. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/handlers/templates/python-flask/util.mustache +0 -0
  146. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/infra/databases/__init__.py +0 -0
  147. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/infra/models/__init__.py +0 -0
  148. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/interfaces/attrs_instance.py +0 -0
  149. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/interfaces/dataclass_instance.py +0 -0
  150. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/interfaces/handler.py +0 -0
  151. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/interfaces/openapi_model.py +0 -0
  152. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/interfaces/pydantic_instance.py +0 -0
  153. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/interfaces/sql_database.py +0 -0
  154. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/mixins/jwt_provider.py +0 -0
  155. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/providers/__init__.py +0 -0
  156. /alpha_python-0.5.1/src/alpha/py.typed → /alpha_python-0.6.0/src/alpha/providers/api_key_provider.py +0 -0
  157. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/providers/models/__init__.py +0 -0
  158. /alpha_python-0.5.1/src/alpha/services/models/__init__.py → /alpha_python-0.6.0/src/alpha/py.typed +0 -0
  159. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/repositories/__init__.py +0 -0
  160. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/repositories/models/__init__.py +0 -0
  161. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/repositories/models/repository_model.py +0 -0
  162. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/services/__init__.py +0 -0
  163. {alpha_python-0.5.1/src/alpha/services/models → alpha_python-0.6.0/src/alpha/utils}/cookie.py +0 -0
  164. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/utils/verify_identity.py +0 -0
  165. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha/utils/version_checker.py +0 -0
  166. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha_python.egg-info/dependency_links.txt +0 -0
  167. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha_python.egg-info/entry_points.txt +0 -0
  168. {alpha_python-0.5.1 → alpha_python-0.6.0}/src/alpha_python.egg-info/top_level.txt +0 -0
  169. {alpha_python-0.5.1 → alpha_python-0.6.0}/tests/test_encoder.py +0 -0
@@ -1,16 +1,29 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alpha-python
3
- Version: 0.5.1
3
+ Version: 0.6.0
4
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
5
  Author-email: Bart Reijling <bart@reijling.eu>
6
- Requires-Python: >=3.11
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/breijling/alpha
8
+ Project-URL: Issues, https://github.com/breijling/alpha/issues
9
+ Project-URL: Documentation, https://alpha-python.readthedocs.io/en/latest/
10
+ Project-URL: Changelog, https://alpha-python.readthedocs.io/en/latest/changelog/
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Requires-Python: <3.15,>=3.11
7
20
  Description-Content-Type: text/markdown
8
21
  License-File: LICENSE
9
22
  Requires-Dist: attrs>=25.4.0
10
23
  Requires-Dist: gunicorn>=23.0.0
11
24
  Requires-Dist: jsonpatch>=1.33
12
25
  Requires-Dist: numpy>=2.3.5
13
- Requires-Dist: pandas>=2.3.3
26
+ Requires-Dist: pandas>=1.13
14
27
  Requires-Dist: pydantic>=2.12.5
15
28
  Requires-Dist: pyjwt>=2.10.1
16
29
  Requires-Dist: six>=1.17.0
@@ -18,8 +31,10 @@ Requires-Dist: sqlalchemy>=2.0.44
18
31
  Requires-Dist: requests>=2.28.1
19
32
  Requires-Dist: dependency-injector[yaml]!=4.48.3,<5.0.0,>=4.42.0
20
33
  Requires-Dist: argon2-cffi>=25.1.0
34
+ Requires-Dist: httpx
35
+ Requires-Dist: cryptography
21
36
  Provides-Extra: api-generator
22
- Requires-Dist: openapi-generator-cli==7.14.0; (python_version >= "3.11" and python_version < "4.0") and extra == "api-generator"
37
+ Requires-Dist: openapi-generator-cli==7.14.0; extra == "api-generator"
23
38
  Requires-Dist: jdk4py; extra == "api-generator"
24
39
  Provides-Extra: flask
25
40
  Requires-Dist: connexion[swagger-ui]<3,>=2.14.2; extra == "flask"
@@ -40,7 +55,7 @@ Provides-Extra: ldap
40
55
  Requires-Dist: ldap3>=2.9.1; extra == "ldap"
41
56
  Dynamic: license-file
42
57
 
43
- # alpha
58
+ # Alpha
44
59
 
45
60
  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.
46
61
 
@@ -53,7 +68,9 @@ Alpha is intended to be the first dependency you need to add to your Python appl
53
68
 
54
69
  ## Documentation
55
70
 
56
- TODO: Add documentation link when available.
71
+ [![Documentation Status](https://readthedocs.org/projects/alpha-python/badge/?version=latest)](https://alpha-python.readthedocs.io/en/latest/)
72
+
73
+ Full documentation is available at [alpha-python.readthedocs.io](https://alpha-python.readthedocs.io/).
57
74
 
58
75
  ## Installation
59
76
 
@@ -1,4 +1,4 @@
1
- # alpha
1
+ # Alpha
2
2
 
3
3
  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.
4
4
 
@@ -11,7 +11,9 @@ Alpha is intended to be the first dependency you need to add to your Python appl
11
11
 
12
12
  ## Documentation
13
13
 
14
- TODO: Add documentation link when available.
14
+ [![Documentation Status](https://readthedocs.org/projects/alpha-python/badge/?version=latest)](https://alpha-python.readthedocs.io/en/latest/)
15
+
16
+ Full documentation is available at [alpha-python.readthedocs.io](https://alpha-python.readthedocs.io/).
15
17
 
16
18
  ## Installation
17
19
 
@@ -1,18 +1,30 @@
1
1
  [project]
2
2
  name = "alpha-python"
3
- version = "0.5.1"
3
+ version = "0.6.0"
4
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
5
  readme = "README.md"
6
6
  authors = [
7
7
  { name = "Bart Reijling", email = "bart@reijling.eu" }
8
8
  ]
9
- requires-python = ">=3.11"
9
+ classifiers = [
10
+ "Development Status :: 4 - Beta",
11
+ "Intended Audience :: Developers",
12
+ "Programming Language :: Python :: 3",
13
+ "Programming Language :: Python :: 3 :: Only",
14
+ "Programming Language :: Python :: 3.11",
15
+ "Programming Language :: Python :: 3.12",
16
+ "Programming Language :: Python :: 3.13",
17
+ "Programming Language :: Python :: 3.14",
18
+ ]
19
+ license = "MIT"
20
+ license-files = ['LICENSE']
21
+ requires-python = ">=3.11, <3.15"
10
22
  dependencies = [
11
23
  "attrs>=25.4.0",
12
24
  "gunicorn>=23.0.0",
13
25
  "jsonpatch>=1.33",
14
26
  "numpy>=2.3.5",
15
- "pandas>=2.3.3",
27
+ "pandas>=1.13",
16
28
  "pydantic>=2.12.5",
17
29
  "pyjwt>=2.10.1",
18
30
  "six>=1.17.0",
@@ -20,8 +32,16 @@ dependencies = [
20
32
  "requests>=2.28.1",
21
33
  "dependency-injector[yaml]>=4.42.0,<5.0.0,!=4.48.3",
22
34
  "argon2-cffi>=25.1.0",
35
+ "httpx",
36
+ "cryptography",
23
37
  ]
24
38
 
39
+ [project.urls]
40
+ Homepage = "https://github.com/breijling/alpha"
41
+ Issues = "https://github.com/breijling/alpha/issues"
42
+ Documentation = "https://alpha-python.readthedocs.io/en/latest/"
43
+ Changelog = "https://alpha-python.readthedocs.io/en/latest/changelog/"
44
+
25
45
  [project.scripts]
26
46
  alpha = "alpha.cli:init"
27
47
 
@@ -60,11 +80,18 @@ dev = [
60
80
  "ipykernel>=7.2.0",
61
81
  "flask<2",
62
82
  "httpx>=0.28.1",
83
+ "tox>=4.53.0",
63
84
  ]
85
+ # docs = [
86
+ # "mkdocs-material>=9.5",
87
+ # "mkdocstrings[python]>=0.29",
88
+ # "mkdocs-autorefs>=1.0",
89
+ # "mkdocs-mermaid2-plugin>=1.2.0"
90
+ # ]
64
91
 
65
92
  [project.optional-dependencies]
66
93
  api-generator = [
67
- "openapi-generator-cli==7.14.0 ; python_version >= '3.11' and python_version < '4.0'",
94
+ "openapi-generator-cli==7.14.0",
68
95
  "jdk4py"
69
96
  ]
70
97
  flask = [
@@ -97,6 +124,33 @@ testpaths = [
97
124
  "tests"
98
125
  ]
99
126
 
127
+ [tool.tox]
128
+ legacy_tox_ini = """
129
+ [tox]
130
+ min_version = 4.0
131
+ env_list = py311,py312,py313,py314
132
+ isolated_build = true
133
+
134
+ [testenv]
135
+ description = Run full test suite on {basepython}
136
+ package = editable
137
+ extras = flask,postgresql,mysql,ldap,api-generator
138
+ deps =
139
+ pytest>=9.0.1
140
+ pytest-cov>=7.0.0
141
+ uv
142
+ commands =
143
+ pytest {posargs}
144
+ pass_env =
145
+ GITHUB_ACTIONS
146
+ TEST_PSQL_HOST
147
+ TEST_PSQL_PORT
148
+ TEST_PSQL_USERNAME
149
+ TEST_PSQL_PASSWORD
150
+ TEST_PSQL_DATABASE
151
+ """
152
+
153
+
100
154
  [tool.coverage.run]
101
155
  source = ["src"]
102
156
  omit = [
@@ -108,7 +162,7 @@ omit = [
108
162
  [tool.black]
109
163
  line-length = 79
110
164
  skip-string-normalization = true
111
- target-version = ['py310', 'py311', 'py312', 'py313']
165
+ target-version = ['py311', 'py312', 'py313', 'py314']
112
166
 
113
167
  [tool.isort]
114
168
  py_version = 311
@@ -1,16 +1,25 @@
1
+ from importlib.metadata import version
2
+
1
3
  from alpha.adapters.rest_api_unit_of_work import RestApiUnitOfWork
2
4
  from alpha.adapters.sqla_unit_of_work import SqlAlchemyUnitOfWork
3
5
  from alpha.factories.jwt_factory import JWTFactory
4
6
  from alpha.factories.logging_handler_factory import LoggingHandlerFactory
5
7
  from alpha.factories.model_class_factory import ModelClassFactory
6
8
  from alpha.domain.models.user import User
7
- from alpha.domain.models.base_model import BaseDomainModel, DomainModel
9
+ from alpha.domain.models.group import Group
10
+ from alpha.domain.models.role import Role
11
+ from alpha.domain.models.base_model import (
12
+ BaseDomainModel,
13
+ DomainModel,
14
+ DomainModelCovariant,
15
+ DomainModelContravariant,
16
+ )
8
17
  from alpha.domain.models.life_cycle_base import LifeCycleBase
9
18
  from alpha.infra.connectors.oidc_connector import (
10
19
  OIDCConnector,
11
20
  KeyCloakOIDCConnector,
12
21
  )
13
- from alpha.infra.databases.sql_alchemy import SqlAlchemyDatabase
22
+ from alpha.infra.connectors.sql_alchemy import SqlAlchemyDatabase
14
23
  from alpha.infra.models.filter_operators import And, Or
15
24
  from alpha.infra.models.json_patch import JsonPatch
16
25
  from alpha.infra.models.order_by import OrderBy, Order
@@ -19,7 +28,7 @@ from alpha.interfaces.attrs_instance import AttrsInstance
19
28
  from alpha.interfaces.dataclass_instance import DataclassInstance
20
29
  from alpha.interfaces.pydantic_instance import PydanticInstance
21
30
  from alpha.interfaces.openapi_model import OpenAPIModel
22
- from alpha.interfaces.updateable import Updateable
31
+ from alpha.interfaces.updatable import Updatable
23
32
  from alpha.interfaces.patchable import Patchable
24
33
  from alpha.interfaces.api_repository import ApiRepository
25
34
  from alpha.interfaces.sql_repository import SqlRepository
@@ -36,6 +45,8 @@ from alpha.interfaces.providers import (
36
45
  )
37
46
  from alpha.interfaces.token_factory import TokenFactory
38
47
  from alpha.mixins.jwt_provider import JWTProviderMixin
48
+ from alpha.mixins.user_lifecycle import UserLifecycleMixin
49
+ from alpha.mixins.group_lifecycle import GroupLifecycleMixin
39
50
  from alpha.providers.models.identity import (
40
51
  Identity,
41
52
  DEFAULT_LDAP_MAPPINGS,
@@ -44,7 +55,12 @@ from alpha.providers.models.identity import (
44
55
  )
45
56
  from alpha.providers.models.credentials import PasswordCredentials
46
57
  from alpha.providers.models.token import Token
47
- from alpha.providers.oidc_provider import OIDCProvider, KeyCloakProvider
58
+ from alpha.providers.oidc_provider import (
59
+ OIDCProvider,
60
+ KeyCloakProvider,
61
+ DEFAULT_OIDC_MAPPINGS,
62
+ DEFAULT_KEYCLOAK_MAPPINGS,
63
+ )
48
64
  from alpha.repositories.models.repository_model import RepositoryModel
49
65
  from alpha.repositories.rest_api_repository import RestApiRepository
50
66
  from alpha.repositories.sql_alchemy_repository import SqlAlchemyRepository
@@ -63,6 +79,7 @@ from alpha.utils.verify_identity import verify_identity
63
79
  from alpha.utils.version_checker import minor_version_gte
64
80
  from alpha.encoder import JSONEncoder
65
81
 
82
+
66
83
  # Optional LDAP support - only import if ldap3 is available
67
84
  try:
68
85
  from alpha.infra.connectors.ldap_connector import (
@@ -77,6 +94,9 @@ try:
77
94
  except ImportError:
78
95
  _LDAP_AVAILABLE = False # type: ignore
79
96
 
97
+
98
+ __version__ = version("alpha-python")
99
+
80
100
  __all__ = [
81
101
  "RestApiUnitOfWork",
82
102
  "SqlAlchemyUnitOfWork",
@@ -85,8 +105,12 @@ __all__ = [
85
105
  "ModelClassFactory",
86
106
  "BaseDomainModel",
87
107
  "DomainModel",
108
+ "DomainModelCovariant",
109
+ "DomainModelContravariant",
88
110
  "LifeCycleBase",
89
111
  "User",
112
+ "Group",
113
+ "Role",
90
114
  "OIDCConnector",
91
115
  "KeyCloakOIDCConnector",
92
116
  "SqlAlchemyDatabase",
@@ -101,7 +125,7 @@ __all__ = [
101
125
  "DataclassInstance",
102
126
  "PydanticInstance",
103
127
  "OpenAPIModel",
104
- "Updateable",
128
+ "Updatable",
105
129
  "Patchable",
106
130
  "ApiRepository",
107
131
  "SqlRepository",
@@ -116,6 +140,8 @@ __all__ = [
116
140
  "TokenIssuer",
117
141
  "TokenFactory",
118
142
  "JWTProviderMixin",
143
+ "UserLifecycleMixin",
144
+ "GroupLifecycleMixin",
119
145
  "Identity",
120
146
  "DEFAULT_LDAP_MAPPINGS",
121
147
  "DEFAULT_AD_MAPPINGS",
@@ -124,6 +150,8 @@ __all__ = [
124
150
  "Token",
125
151
  "OIDCProvider",
126
152
  "KeyCloakProvider",
153
+ "DEFAULT_OIDC_MAPPINGS",
154
+ "DEFAULT_KEYCLOAK_MAPPINGS",
127
155
  "RepositoryModel",
128
156
  "RestApiRepository",
129
157
  "SqlAlchemyRepository",
@@ -151,3 +179,27 @@ if _LDAP_AVAILABLE:
151
179
  "ADProvider",
152
180
  ]
153
181
  )
182
+
183
+
184
+ def _ensure_ast_str_compat() -> None:
185
+ """Provide ast.Str compatibility for Python 3.14+.
186
+
187
+ Older Werkzeug versions (used by Flask 1.x) still instantiate ast.Str.
188
+ Python 3.14 removed that alias, so we recreate it with ast.Constant.
189
+ """
190
+ if hasattr(ast, "Str"):
191
+ return
192
+
193
+ class _StrCompat(ast.Constant):
194
+ def __new__(cls, s: str = "", **kwargs): # noqa: N804
195
+ return ast.Constant(value=s, **kwargs)
196
+
197
+ setattr(ast, "Str", _StrCompat)
198
+
199
+
200
+ try:
201
+ import ast
202
+
203
+ _ensure_ast_str_compat()
204
+ except ImportError:
205
+ pass
@@ -11,7 +11,13 @@ UOW = TypeVar("UOW", bound="RestApiUnitOfWork")
11
11
 
12
12
 
13
13
  class RestApiUnitOfWork:
14
- """Unit of Work implementation for REST API interactions."""
14
+ """Unit of Work implementation for REST API interactions.
15
+
16
+ This class manages the lifecycle of a shared HTTP session and provides
17
+ access to configured repositories for API interactions. It does not support
18
+ transactional operations like commit, flush, rollback, or refresh, as these
19
+ concepts do not apply to REST API interactions.
20
+ """
15
21
 
16
22
  def __init__(
17
23
  self,
@@ -22,9 +28,9 @@ class RestApiUnitOfWork:
22
28
 
23
29
  Parameters
24
30
  ----------
25
- repos : list[RepositoryModel]
31
+ repos
26
32
  The list of repository models to use.
27
- session : requests.sessions.Session | None
33
+ session
28
34
  The requests session (or compatible HTTP client, e.g., httpx) to
29
35
  use for context management, by default None
30
36
 
@@ -12,7 +12,12 @@ UOW = TypeVar("UOW", bound="SqlAlchemyUnitOfWork")
12
12
 
13
13
 
14
14
  class SqlAlchemyUnitOfWork:
15
- """Unit of Work implementation for SQLAlchemy databases."""
15
+ """Unit of Work implementation for SQLAlchemy databases.
16
+
17
+ This class manages the lifecycle of a SQLAlchemy session and provides
18
+ access to configured repositories for database interactions. It supports
19
+ transactional operations such as commit, flush, rollback, and refresh.
20
+ """
16
21
 
17
22
  def __init__(
18
23
  self,
@@ -23,9 +28,9 @@ class SqlAlchemyUnitOfWork:
23
28
 
24
29
  Parameters
25
30
  ----------
26
- db : SqlDatabase
31
+ db
27
32
  The database instance to use.
28
- repos : list[RepositoryModel]
33
+ repos
29
34
  The list of repository models to use.
30
35
 
31
36
  Raises
@@ -45,6 +50,7 @@ class SqlAlchemyUnitOfWork:
45
50
 
46
51
  Returns
47
52
  -------
53
+ UOW
48
54
  The Unit of Work instance.
49
55
 
50
56
  Raises
@@ -107,7 +113,13 @@ class SqlAlchemyUnitOfWork:
107
113
  self._session.rollback()
108
114
 
109
115
  def refresh(self, obj: object) -> None:
110
- """Refresh the state of a given object."""
116
+ """Refresh the state of a given object.
117
+
118
+ Parameters
119
+ ----------
120
+ obj
121
+ The object to refresh.
122
+ """
111
123
  if not self._session:
112
124
  raise exceptions.DatabaseSessionError(
113
125
  "No active database session is defined"
@@ -116,5 +128,11 @@ class SqlAlchemyUnitOfWork:
116
128
 
117
129
  @property
118
130
  def session(self) -> Session | None:
119
- """Get the current database session."""
131
+ """Get the current database session.
132
+
133
+ Returns
134
+ -------
135
+ Session | None
136
+ The current database session.
137
+ """
120
138
  return self._session
@@ -8,13 +8,18 @@ from alpha.handlers.models.argument import Argument
8
8
 
9
9
 
10
10
  class Container(containers.DeclarativeContainer):
11
- """Dependency injection container for the alpha package."""
11
+ """Dependency injection container for the alpha package.
12
+
13
+ The container is used to manage the dependencies of the alpha package,
14
+ including the API generation and running commands. It allows for easy
15
+ configuration and extension of the commands and their dependencies.
16
+ """
12
17
 
13
18
  config = providers.Configuration()
14
19
 
15
20
  api_gen_command = providers.Factory(
16
21
  Command,
17
- name='gen',
22
+ name="gen",
18
23
  help=(
19
24
  "Generate the API code and watch OpenAPI spec file. The API code "
20
25
  "will be generated into the ./api folder."
@@ -23,46 +28,46 @@ class Container(containers.DeclarativeContainer):
23
28
  arguments=providers.List(
24
29
  providers.Factory(
25
30
  Argument,
26
- default='specification/openapi.yaml',
27
- name='--spec-file',
28
- help='Path to the specification file',
31
+ default="specification/openapi.yaml",
32
+ name="--spec-file",
33
+ help="Path to the specification file",
29
34
  args={
30
- 'type': str,
31
- 'nargs': '?',
35
+ "type": str,
36
+ "nargs": "?",
32
37
  },
33
38
  ),
34
39
  providers.Factory(
35
40
  Argument,
36
41
  default=config.api_package_name,
37
- name='--api-package',
42
+ name="--api-package",
38
43
  help=(
39
44
  "Name of the API package to generate. Automatically "
40
45
  "determined or guessed. If incorrect, "
41
46
  "just use this argument."
42
47
  ),
43
48
  args={
44
- 'type': str,
45
- 'nargs': '?',
49
+ "type": str,
50
+ "nargs": "?",
46
51
  },
47
52
  ),
48
53
  providers.Factory(
49
54
  Argument,
50
55
  default=config.service_package_name,
51
- name='--service-package',
56
+ name="--service-package",
52
57
  help=(
53
58
  "Name of the service package to use. Automatically "
54
59
  "determined or guessed. If incorrect, "
55
60
  "just use this argument."
56
61
  ),
57
62
  args={
58
- 'type': str,
59
- 'nargs': '?',
63
+ "type": str,
64
+ "nargs": "?",
60
65
  },
61
66
  ),
62
67
  providers.Factory(
63
68
  Argument,
64
69
  default=config.container_import,
65
- name='--container-import',
70
+ name="--container-import",
66
71
  help=(
67
72
  "Name of the container to use. Automatically "
68
73
  "determined or guessed. If incorrect, "
@@ -70,76 +75,76 @@ class Container(containers.DeclarativeContainer):
70
75
  "use empty string for this variable"
71
76
  ),
72
77
  args={
73
- 'type': str,
74
- 'nargs': '?',
78
+ "type": str,
79
+ "nargs": "?",
75
80
  },
76
81
  ),
77
82
  providers.Factory(
78
83
  Argument,
79
84
  default=config.init_container_from,
80
- name='--init-container-from',
85
+ name="--init-container-from",
81
86
  help=(
82
87
  "Location of where the container initialize function "
83
88
  "should be imported from."
84
89
  ),
85
90
  args={
86
- 'type': str,
87
- 'nargs': '?',
91
+ "type": str,
92
+ "nargs": "?",
88
93
  },
89
94
  ),
90
95
  providers.Factory(
91
96
  Argument,
92
97
  default=config.init_container_function,
93
- name='--init-container-function',
98
+ name="--init-container-function",
94
99
  help="Name of the container initialize function.",
95
100
  args={
96
- 'type': str,
97
- 'nargs': '?',
101
+ "type": str,
102
+ "nargs": "?",
98
103
  },
99
104
  ),
100
105
  providers.Factory(
101
106
  Argument,
102
- default='post_process.py',
103
- name='--post-process-file',
107
+ default="post_process.py",
108
+ name="--post-process-file",
104
109
  help="Path to the post process file to use after generation",
105
110
  args={
106
- 'type': str,
107
- 'nargs': '?',
111
+ "type": str,
112
+ "nargs": "?",
108
113
  },
109
114
  ),
110
115
  providers.Factory(
111
116
  Argument,
112
- default='python-flask',
113
- name='--generator-name',
117
+ default="python-flask",
118
+ name="--generator-name",
114
119
  help="Name of the openapi generator to use",
115
120
  args={
116
- 'type': str,
117
- 'nargs': '?',
121
+ "type": str,
122
+ "nargs": "?",
118
123
  },
119
124
  ),
120
125
  providers.Factory(
121
126
  Argument,
122
127
  default=False,
123
- name='--no-watch',
128
+ name="--no-watch",
124
129
  help=(
125
130
  "To prevent watching the spec file for changes and only "
126
131
  "run the generation once."
127
132
  ),
128
133
  args={
129
- 'action': 'store_true',
134
+ "action": "store_true",
130
135
  },
131
136
  ),
132
137
  providers.Factory(
133
138
  Argument,
134
139
  default=False,
135
- name='--templates-only',
140
+ name="--templates-only",
136
141
  help=(
137
142
  "Only create a templates folder containing openapi "
138
143
  "mustache templates in the current working directory. "
139
144
  "Skip generation of API code."
140
145
  ),
141
146
  args={
142
- 'action': 'store_true',
147
+ "action": "store_true",
143
148
  },
144
149
  ),
145
150
  ),
@@ -147,28 +152,28 @@ class Container(containers.DeclarativeContainer):
147
152
 
148
153
  api_run_command = providers.Factory(
149
154
  Command,
150
- name='run',
151
- help='Run API in development mode',
155
+ name="run",
156
+ help="Run API in development mode",
152
157
  handler=providers.Factory(ApiRunHandler),
153
158
  arguments=providers.List(
154
159
  providers.Factory(
155
160
  Argument,
156
161
  default=config.api_package_name,
157
- name='--api-package',
158
- help='Name of the API package to generate',
162
+ name="--api-package",
163
+ help="Name of the API package to generate",
159
164
  args={
160
- 'type': str,
161
- 'nargs': '?',
165
+ "type": str,
166
+ "nargs": "?",
162
167
  },
163
168
  ),
164
169
  providers.Factory(
165
170
  Argument,
166
- default='8080',
167
- name='--port',
168
- help='Port to run server on',
171
+ default="8080",
172
+ name="--port",
173
+ help="Port to run server on",
169
174
  args={
170
- 'type': str,
171
- 'nargs': '?',
175
+ "type": str,
176
+ "nargs": "?",
172
177
  },
173
178
  ),
174
179
  ),
@@ -176,8 +181,8 @@ class Container(containers.DeclarativeContainer):
176
181
 
177
182
  api_section = providers.Factory(
178
183
  Section,
179
- name='api',
180
- description='OpenAPI development commands.',
184
+ name="api",
185
+ description="OpenAPI development commands.",
181
186
  help=(
182
187
  "All commands for generating and developing an API using the "
183
188
  "OpenAPI standards"
@@ -0,0 +1,21 @@
1
+ from alpha.domain.models.user import User
2
+ from alpha.domain.models.group import Group
3
+ from alpha.domain.models.role import Role
4
+ from alpha.domain.models.base_model import (
5
+ BaseDomainModel,
6
+ DomainModel,
7
+ DomainModelCovariant,
8
+ DomainModelContravariant,
9
+ )
10
+ from alpha.domain.models.life_cycle_base import LifeCycleBase
11
+
12
+ __all__ = [
13
+ "BaseDomainModel",
14
+ "DomainModel",
15
+ "DomainModelCovariant",
16
+ "DomainModelContravariant",
17
+ "LifeCycleBase",
18
+ "User",
19
+ "Group",
20
+ "Role",
21
+ ]