alpha-python 0.5.1__py3-none-any.whl → 0.6.1__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 (94) hide show
  1. alpha/__init__.py +57 -5
  2. alpha/adapters/rest_api_unit_of_work.py +9 -3
  3. alpha/adapters/sqla_unit_of_work.py +23 -5
  4. alpha/cli.py +27 -23
  5. alpha/containers/container.py +52 -47
  6. alpha/domain/__init__.py +12 -1
  7. alpha/domain/models/__init__.py +12 -1
  8. alpha/domain/models/base_model.py +37 -1
  9. alpha/domain/models/group.py +51 -1
  10. alpha/domain/models/life_cycle_base.py +19 -0
  11. alpha/domain/models/role.py +127 -0
  12. alpha/domain/models/user.py +78 -65
  13. alpha/encoder.py +25 -3
  14. alpha/factories/class_factories.py +49 -22
  15. alpha/factories/default_field_factory.py +1 -0
  16. alpha/factories/field_iterator.py +8 -2
  17. alpha/factories/jwt_factory.py +59 -18
  18. alpha/factories/logging_handler_factory.py +7 -5
  19. alpha/factories/model_class_factory.py +6 -3
  20. alpha/factories/models/factory_classes.py +20 -1
  21. alpha/factories/password_factory.py +39 -15
  22. alpha/factories/request_factory.py +24 -13
  23. alpha/factories/response_factory.py +5 -2
  24. alpha/factories/type_factories.py +16 -2
  25. alpha/handlers/api_generate_handler.py +37 -33
  26. alpha/handlers/run-api.sh +0 -8
  27. alpha/handlers/templates/python-flask/__main__.mustache +26 -9
  28. alpha/handlers/templates/python-flask/controller.mustache +131 -30
  29. alpha/handlers/templates/python-flask/controller_test.mustache +1 -1
  30. alpha/handlers/templates/python-flask/model.mustache +7 -1
  31. alpha/handlers/templates/python-flask/requirements.mustache +0 -19
  32. alpha/handlers/templates/python-flask/setup.mustache +0 -19
  33. alpha/infra/__init__.py +14 -5
  34. alpha/infra/connectors/__init__.py +9 -4
  35. alpha/infra/connectors/ldap_connector.py +38 -29
  36. alpha/infra/connectors/oidc_connector.py +1 -1
  37. alpha/infra/connectors/sql_alchemy.py +166 -0
  38. alpha/infra/databases/sql_alchemy.py +7 -160
  39. alpha/infra/models/filter_operators.py +6 -1
  40. alpha/infra/models/json_patch.py +32 -6
  41. alpha/infra/models/order_by.py +78 -4
  42. alpha/infra/models/query_clause.py +33 -8
  43. alpha/infra/models/search_filter.py +96 -0
  44. alpha/interfaces/__init__.py +2 -2
  45. alpha/interfaces/api_repository.py +11 -5
  46. alpha/interfaces/factories.py +5 -2
  47. alpha/interfaces/patchable.py +17 -1
  48. alpha/interfaces/providers.py +4 -4
  49. alpha/interfaces/sql_mapper.py +6 -3
  50. alpha/interfaces/sql_repository.py +128 -141
  51. alpha/interfaces/token_factory.py +12 -10
  52. alpha/interfaces/unit_of_work.py +32 -15
  53. alpha/interfaces/updatable.py +21 -0
  54. alpha/mixins/__init__.py +3 -1
  55. alpha/mixins/group_lifecycle.py +159 -0
  56. alpha/mixins/user_lifecycle.py +188 -0
  57. alpha/providers/database_provider.py +5 -4
  58. alpha/providers/ldap_provider.py +82 -66
  59. alpha/providers/models/credentials.py +28 -6
  60. alpha/providers/models/identity.py +20 -11
  61. alpha/providers/models/token.py +56 -0
  62. alpha/providers/oidc_provider.py +56 -35
  63. alpha/repositories/rest_api_repository.py +23 -24
  64. alpha/repositories/sql_alchemy_repository.py +179 -133
  65. alpha/services/authentication_service.py +274 -51
  66. alpha/services/models/cookie.py +3 -49
  67. alpha/services/user_lifecycle_management.py +17 -285
  68. alpha/utils/__init__.py +2 -0
  69. alpha/utils/_http_codes.py +8 -0
  70. alpha/utils/cookie.py +51 -0
  71. alpha/utils/is_attrs.py +1 -1
  72. alpha/utils/is_pydantic.py +1 -1
  73. alpha/utils/logging_configurator.py +19 -17
  74. alpha/utils/logging_level_checker.py +3 -3
  75. alpha/utils/openapi_test/__init__.py +0 -0
  76. alpha/utils/openapi_test/container.py +181 -0
  77. alpha/utils/openapi_test/exceptions.py +17 -0
  78. alpha/utils/openapi_test/models.py +83 -0
  79. alpha/utils/openapi_test/orm.py +90 -0
  80. alpha/utils/openapi_test/response.py +12 -0
  81. alpha/utils/openapi_test/service.py +166 -0
  82. alpha/utils/request_headers.py +8 -0
  83. alpha/utils/response_object.py +19 -8
  84. alpha/utils/secret_generator.py +2 -2
  85. alpha/utils/verify_identity.py +7 -7
  86. alpha_python-0.6.1.dist-info/METADATA +210 -0
  87. alpha_python-0.6.1.dist-info/RECORD +144 -0
  88. alpha/interfaces/updateable.py +0 -7
  89. alpha_python-0.5.1.dist-info/METADATA +0 -100
  90. alpha_python-0.5.1.dist-info/RECORD +0 -132
  91. {alpha_python-0.5.1.dist-info → alpha_python-0.6.1.dist-info}/WHEEL +0 -0
  92. {alpha_python-0.5.1.dist-info → alpha_python-0.6.1.dist-info}/entry_points.txt +0 -0
  93. {alpha_python-0.5.1.dist-info → alpha_python-0.6.1.dist-info}/licenses/LICENSE +0 -0
  94. {alpha_python-0.5.1.dist-info → alpha_python-0.6.1.dist-info}/top_level.txt +0 -0
alpha/__init__.py CHANGED
@@ -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
alpha/cli.py CHANGED
@@ -20,18 +20,18 @@ def main(sections: list[Section] = Provide[Container.sections]) -> None:
20
20
 
21
21
  # Create the main parser
22
22
  parser = argparse.ArgumentParser(
23
- description='Alpha command line interface.',
23
+ description="Alpha command line interface.",
24
24
  formatter_class=argparse.ArgumentDefaultsHelpFormatter,
25
25
  )
26
26
  subparsers = parser.add_subparsers(
27
- title='Use one of the sub categories to run commands on',
28
- dest='section',
27
+ title="Use one of the sub categories to run commands on",
28
+ dest="section",
29
29
  )
30
30
 
31
31
  # Parser dict to store in all parsers to match later on when finding a
32
32
  # handler.
33
- section_parsers = {}
34
- command_parsers = {}
33
+ section_parsers: dict[str, argparse.ArgumentParser] = {}
34
+ command_parsers: dict[str, dict[str, argparse.ArgumentParser]] = {}
35
35
 
36
36
  # Create all sections
37
37
  for section in sections:
@@ -43,7 +43,7 @@ def main(sections: list[Section] = Provide[Container.sections]) -> None:
43
43
  formatter_class=argparse.ArgumentDefaultsHelpFormatter,
44
44
  )
45
45
  section_subparser = section_parsers[section.name].add_subparsers(
46
- dest='command'
46
+ dest="command"
47
47
  )
48
48
 
49
49
  # Create all commands per section
@@ -88,8 +88,8 @@ def main(sections: list[Section] = Provide[Container.sections]) -> None:
88
88
  # Get all arguments and remove the section and command so they can be
89
89
  # 'kwarged' into the Handler set_arguments function.
90
90
  handler_args = vars(args)
91
- del handler_args['section']
92
- del handler_args['command']
91
+ del handler_args["section"]
92
+ del handler_args["command"]
93
93
 
94
94
  # Find the right handler
95
95
  for section in sections:
@@ -102,7 +102,7 @@ def main(sections: list[Section] = Provide[Container.sections]) -> None:
102
102
  command.handler.handle_command()
103
103
  return
104
104
 
105
- print('No handler found, you should never read this')
105
+ print("No handler found, you should never read this")
106
106
  return
107
107
 
108
108
 
@@ -118,53 +118,57 @@ def _guess_current_package_name() -> str:
118
118
  """
119
119
 
120
120
  cwd = os.getcwd()
121
- pyproject_path = os.path.join(cwd, 'pyproject.toml')
121
+ pyproject_path = os.path.join(cwd, "pyproject.toml")
122
122
 
123
123
  # look for pyproject.toml file in subfolders
124
124
  if not os.path.isfile(pyproject_path):
125
125
  for entry in os.scandir(cwd):
126
126
  if not entry.is_dir():
127
127
  continue
128
- possible_path = os.path.join(entry.path, 'pyproject.toml')
128
+ possible_path = os.path.join(entry.path, "pyproject.toml")
129
129
  if os.path.isfile(possible_path):
130
130
  pyproject_path = possible_path
131
131
  break
132
132
 
133
133
  if os.path.isfile(pyproject_path):
134
134
  try:
135
- with open(pyproject_path, 'rb') as f:
135
+ with open(pyproject_path, "rb") as f:
136
136
  pyproject_data = tomllib.load(f)
137
137
  name = None
138
138
  try:
139
- if 'project' in pyproject_data:
140
- name = pyproject_data['project']['name']
141
- elif 'tool' in pyproject_data and 'poetry' in pyproject_data['tool']:
142
- name = pyproject_data['tool']['poetry']['name']
139
+ if "project" in pyproject_data:
140
+ name = pyproject_data["project"]["name"]
141
+ elif (
142
+ "tool" in pyproject_data
143
+ and "poetry" in pyproject_data["tool"]
144
+ ):
145
+ name = pyproject_data["tool"]["poetry"]["name"]
143
146
  if name is not None:
144
- return name.replace('-', '_')
147
+ return name.replace("-", "_")
145
148
  except KeyError:
146
- print('Could not find project name in pyproject.toml')
149
+ print("Could not find project name in pyproject.toml")
147
150
  except Exception:
148
151
  pass
149
152
  else:
150
- print('Could not find pyproject.toml')
153
+ print("Could not find pyproject.toml")
151
154
 
152
155
  # Fallback to use the current folder name
153
- print('Guessing package name from folder')
156
+ print("Guessing package name from folder")
154
157
  return os.path.basename(cwd)
155
158
 
159
+
156
160
  def init() -> None:
157
161
  """Init the container and wire it to the main function."""
158
162
  container = Container()
159
163
  guessed_name = _guess_current_package_name()
160
164
  if guessed_name:
161
- container.config.api_package_name.from_value(f'{guessed_name}_api')
165
+ container.config.api_package_name.from_value(f"{guessed_name}_api")
162
166
  container.config.service_package_name.from_value(guessed_name)
163
167
  container.config.container_import.from_value(
164
- f'from {guessed_name}.containers.container import Container'
168
+ f"from {guessed_name}.containers.container import Container"
165
169
  )
166
170
  container.config.init_container_from.from_value(guessed_name)
167
- container.config.init_container_function.from_value('init_container')
171
+ container.config.init_container_function.from_value("init_container")
168
172
  container.wire(modules=[sys.modules[__name__]])
169
173
 
170
174
  main()
@@ -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"
alpha/domain/__init__.py CHANGED
@@ -1,10 +1,21 @@
1
1
  from alpha.domain.models.user import User
2
- from alpha.domain.models.base_model import BaseDomainModel, DomainModel
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
+ )
3
10
  from alpha.domain.models.life_cycle_base import LifeCycleBase
4
11
 
5
12
  __all__ = [
6
13
  "BaseDomainModel",
7
14
  "DomainModel",
15
+ "DomainModelCovariant",
16
+ "DomainModelContravariant",
8
17
  "LifeCycleBase",
9
18
  "User",
19
+ "Group",
20
+ "Role",
10
21
  ]
@@ -1,10 +1,21 @@
1
1
  from alpha.domain.models.user import User
2
- from alpha.domain.models.base_model import BaseDomainModel, DomainModel
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
+ )
3
10
  from alpha.domain.models.life_cycle_base import LifeCycleBase
4
11
 
5
12
  __all__ = [
6
13
  "BaseDomainModel",
7
14
  "DomainModel",
15
+ "DomainModelCovariant",
16
+ "DomainModelContravariant",
8
17
  "LifeCycleBase",
9
18
  "User",
19
+ "Group",
20
+ "Role",
10
21
  ]