tiferet 1.0.0a19__py3-none-any.whl → 1.0.0b0__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.
- tiferet/__init__.py +3 -2
- tiferet/commands/__init__.py +6 -0
- tiferet/commands/app.py +102 -0
- tiferet/commands/core.py +124 -0
- tiferet/commands/dependencies.py +76 -0
- tiferet/commands/settings.py +101 -0
- tiferet/configs/__init__.py +3 -67
- tiferet/configs/error.py +48 -0
- tiferet/configs/settings.py +37 -0
- tiferet/contexts/__init__.py +0 -8
- tiferet/contexts/app.py +215 -182
- tiferet/contexts/cache.py +76 -0
- tiferet/contexts/container.py +92 -190
- tiferet/contexts/error.py +78 -80
- tiferet/contexts/feature.py +120 -83
- tiferet/contracts/__init__.py +4 -0
- tiferet/contracts/app.py +92 -0
- tiferet/contracts/cache.py +70 -0
- tiferet/contracts/container.py +147 -0
- tiferet/contracts/error.py +177 -0
- tiferet/contracts/feature.py +159 -0
- tiferet/contracts/settings.py +34 -0
- tiferet/data/__init__.py +3 -4
- tiferet/data/app.py +71 -208
- tiferet/data/container.py +52 -38
- tiferet/data/error.py +15 -24
- tiferet/data/feature.py +27 -8
- tiferet/{domain/core.py → data/settings.py} +36 -96
- tiferet/handlers/__init__.py +0 -0
- tiferet/handlers/container.py +116 -0
- tiferet/handlers/error.py +49 -0
- tiferet/handlers/feature.py +94 -0
- tiferet/models/__init__.py +4 -0
- tiferet/models/app.py +150 -0
- tiferet/models/container.py +135 -0
- tiferet/{domain → models}/error.py +86 -36
- tiferet/{domain → models}/feature.py +107 -47
- tiferet/models/settings.py +148 -0
- tiferet/proxies/__init__.py +0 -0
- tiferet/proxies/yaml/__init__.py +0 -0
- tiferet/{repos → proxies/yaml}/app.py +13 -41
- tiferet/{repos → proxies/yaml}/container.py +26 -56
- tiferet/{repos → proxies/yaml}/error.py +11 -70
- tiferet/proxies/yaml/feature.py +92 -0
- {tiferet-1.0.0a19.dist-info → tiferet-1.0.0b0.dist-info}/METADATA +12 -3
- tiferet-1.0.0b0.dist-info/RECORD +51 -0
- {tiferet-1.0.0a19.dist-info → tiferet-1.0.0b0.dist-info}/WHEEL +1 -1
- tiferet/commands/container.py +0 -54
- tiferet/commands/error.py +0 -21
- tiferet/commands/feature.py +0 -90
- tiferet/contexts/request.py +0 -110
- tiferet/domain/__init__.py +0 -5
- tiferet/domain/app.py +0 -131
- tiferet/domain/container.py +0 -141
- tiferet/repos/__init__.py +0 -7
- tiferet/repos/feature.py +0 -151
- tiferet-1.0.0a19.dist-info/RECORD +0 -35
- {tiferet-1.0.0a19.dist-info → tiferet-1.0.0b0.dist-info/licenses}/LICENSE +0 -0
- {tiferet-1.0.0a19.dist-info → tiferet-1.0.0b0.dist-info}/top_level.txt +0 -0
tiferet/contexts/container.py
CHANGED
@@ -1,50 +1,13 @@
|
|
1
1
|
# *** imports
|
2
2
|
|
3
3
|
# ** core
|
4
|
-
import
|
5
|
-
from typing import Any
|
4
|
+
from typing import Any, List
|
6
5
|
|
7
6
|
# ** app
|
8
|
-
from
|
9
|
-
from ..
|
10
|
-
|
11
|
-
|
12
|
-
# *** functions
|
13
|
-
|
14
|
-
# ** function: create_injector
|
15
|
-
def create_injector(name: str, **dependencies) -> Any:
|
16
|
-
'''
|
17
|
-
Create an injector object with the given dependencies.
|
18
|
-
|
19
|
-
:param name: The name of the injector.
|
20
|
-
:type name: str
|
21
|
-
:param dependencies: The dependencies.
|
22
|
-
:type dependencies: dict
|
23
|
-
:return: The injector object.
|
24
|
-
:rtype: Any
|
25
|
-
'''
|
26
|
-
|
27
|
-
# Create container.
|
28
|
-
from dependencies import Injector
|
29
|
-
return type(f'{name.capitalize()}Container', (Injector,), {**dependencies})
|
30
|
-
|
31
|
-
|
32
|
-
# ** function: import_dependency
|
33
|
-
def import_dependency(module_path: str, class_name: str) -> Any:
|
34
|
-
'''
|
35
|
-
Import an object dependency from its configured Python module.
|
36
|
-
|
37
|
-
:param module_path: The module path.
|
38
|
-
:type module_path: str
|
39
|
-
:param class_name: The class name.
|
40
|
-
:type class_name: str
|
41
|
-
:return: The dependency.
|
42
|
-
:rtype: Any
|
43
|
-
'''
|
44
|
-
|
45
|
-
# Import module.
|
46
|
-
from importlib import import_module
|
47
|
-
return getattr(import_module(module_path), class_name)
|
7
|
+
from .cache import CacheContext
|
8
|
+
from ..handlers.container import ContainerService
|
9
|
+
from ..commands import *
|
10
|
+
from ..commands.dependencies import *
|
48
11
|
|
49
12
|
|
50
13
|
# *** contexts
|
@@ -55,178 +18,117 @@ class ContainerContext(Model):
|
|
55
18
|
A container context is a class that is used to create a container object.
|
56
19
|
'''
|
57
20
|
|
58
|
-
# * attribute:
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
)
|
65
|
-
|
66
|
-
# * attribute: attributes
|
67
|
-
attributes = DictType(
|
68
|
-
ModelType(ContainerAttribute),
|
69
|
-
default={},
|
70
|
-
required=True,
|
71
|
-
metadata=dict(
|
72
|
-
description='The container attributes.'
|
73
|
-
),
|
74
|
-
)
|
75
|
-
|
76
|
-
# * attribute: constants
|
77
|
-
constants = DictType(
|
78
|
-
StringType,
|
79
|
-
default={},
|
80
|
-
metadata=dict(
|
81
|
-
description='The container constants.'
|
82
|
-
),
|
83
|
-
)
|
84
|
-
|
85
|
-
# * attribute: feature_flag
|
86
|
-
feature_flag = StringType(
|
87
|
-
required=True,
|
88
|
-
default='core',
|
89
|
-
metadata=dict(
|
90
|
-
description='The feature flag.'
|
91
|
-
),
|
92
|
-
)
|
93
|
-
|
94
|
-
# * attribute: data_flag
|
95
|
-
data_flag = StringType(
|
96
|
-
required=True,
|
97
|
-
metadata=dict(
|
98
|
-
description='The data flag.'
|
99
|
-
),
|
100
|
-
)
|
21
|
+
# * attribute: cache
|
22
|
+
cache: CacheContext
|
23
|
+
|
24
|
+
# * attribute: container_service
|
25
|
+
container_service: ContainerService
|
26
|
+
|
101
27
|
|
102
28
|
# * method: init
|
103
|
-
def __init__(self,
|
29
|
+
def __init__(self, container_service: ContainerService, cache: CacheContext = None):
|
104
30
|
'''
|
105
31
|
Initialize the container context.
|
106
32
|
|
107
|
-
:param
|
108
|
-
:type
|
109
|
-
:param
|
110
|
-
:type
|
111
|
-
:param interface_flag: The interface flag.
|
112
|
-
:type interface_flag: str
|
113
|
-
:param feature_flag: The feature flag.
|
114
|
-
:type feature_flag: str
|
115
|
-
:param data_flag: The data flag.
|
116
|
-
:type data_flag: str
|
33
|
+
:param container_service: The container service to use for executing container requests.
|
34
|
+
:type container_service: ContainerService
|
35
|
+
:param cache: The cache context to use for caching container data.
|
36
|
+
:type cache: CacheContext
|
117
37
|
'''
|
118
38
|
|
119
|
-
#
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
# Get and set attributes and constants.
|
124
|
-
attrs, consts = container_repo.list_all()
|
125
|
-
|
126
|
-
# Parse the constants.
|
127
|
-
constants.update({key: self.parse_parameter(consts[key]) for key in consts})
|
128
|
-
|
129
|
-
# Add the attributes to the context.
|
130
|
-
for attr in attrs:
|
131
|
-
|
132
|
-
# If the attribute already exists, set the dependencies.
|
133
|
-
if attr.id in attributes:
|
134
|
-
for dep in attr.dependencies:
|
135
|
-
attr.set_dependency(dep)
|
136
|
-
continue
|
137
|
-
|
138
|
-
# Otherwise, add the attribute.
|
139
|
-
attributes[attr.id] = attr
|
140
|
-
|
141
|
-
# Add any parameters as constants.
|
142
|
-
for dep in attr.dependencies:
|
143
|
-
for key in dep.parameters:
|
144
|
-
constants[key] = self.parse_parameter(dep.parameters[key])
|
145
|
-
|
146
|
-
# Add the constants and attributes to the context.
|
147
|
-
super().__init__(dict(
|
148
|
-
interface_id=interface_id,
|
149
|
-
feature_flag=feature_flag,
|
150
|
-
data_flag=data_flag,
|
151
|
-
attributes=attributes,
|
152
|
-
constants=constants,
|
153
|
-
))
|
154
|
-
|
39
|
+
# Assign the attributes.
|
40
|
+
self.container_service = container_service
|
41
|
+
self.cache = cache if cache else CacheContext()
|
155
42
|
|
156
|
-
# * method:
|
157
|
-
def
|
158
|
-
|
159
|
-
# If the parameter is an environment variable, get the value.
|
160
|
-
if parameter.startswith('$env.'):
|
161
|
-
return os.getenv(parameter[5:])
|
162
|
-
|
163
|
-
# Otherwise, return the parameter.
|
164
|
-
return parameter
|
165
|
-
|
166
|
-
# * method: get_dependency
|
167
|
-
def get_dependency(self, attribute_id: str):
|
43
|
+
# * method: create_cache_key
|
44
|
+
def create_cache_key(self, flags: List[str] = None) -> str:
|
168
45
|
'''
|
169
|
-
|
46
|
+
Create a cache key for the container.
|
170
47
|
|
171
|
-
:param
|
172
|
-
:type
|
173
|
-
:return: The
|
174
|
-
:rtype:
|
48
|
+
:param flags: The feature or data flags to use.
|
49
|
+
:type flags: List[str]
|
50
|
+
:return: The cache key.
|
51
|
+
:rtype: str
|
175
52
|
'''
|
176
53
|
|
177
|
-
# Create the
|
178
|
-
|
179
|
-
|
180
|
-
# Get attribute.
|
181
|
-
return getattr(injector, attribute_id)
|
54
|
+
# Create the cache key from the flags.
|
55
|
+
return f"feature_container{'_' + '_'.join(flags) if flags else ''}"
|
182
56
|
|
183
|
-
# * method:
|
184
|
-
def
|
57
|
+
# * method: build_injector
|
58
|
+
def build_injector(self,
|
59
|
+
flags: List[str] = None,
|
60
|
+
) -> Injector:
|
185
61
|
'''
|
186
|
-
|
62
|
+
Build the container injector.
|
187
63
|
|
188
|
-
:param
|
189
|
-
:type
|
64
|
+
:param flags: The feature or data flags to use.
|
65
|
+
:type flags: List[str]
|
190
66
|
:return: The container injector object.
|
191
|
-
:rtype:
|
67
|
+
:rtype: Injector
|
192
68
|
'''
|
193
69
|
|
194
|
-
#
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
)
|
202
|
-
dependencies[attribute_id] = self.import_dependency(attribute, flag_map[attribute.type])
|
70
|
+
# Create the cache key for the injector from the flags.
|
71
|
+
cache_key = self.create_cache_key(flags)
|
72
|
+
|
73
|
+
# Check if the injector is already cached.
|
74
|
+
cached_injector = self.cache.get(cache_key)
|
75
|
+
if cached_injector:
|
76
|
+
return cached_injector
|
203
77
|
|
204
|
-
#
|
205
|
-
|
206
|
-
self.interface_id,
|
207
|
-
**self.constants,
|
208
|
-
**dependencies,
|
209
|
-
**kwargs)
|
78
|
+
# Get all attributes and constants from the container service.
|
79
|
+
attributes, constants = self.container_service.list_all()
|
210
80
|
|
211
|
-
|
212
|
-
|
81
|
+
# Load constants from the attributes.
|
82
|
+
constants = self.container_service.load_constants(attributes, constants, flags)
|
83
|
+
|
84
|
+
# Create the dependencies for the injector.
|
85
|
+
dependencies = {}
|
86
|
+
for attr in attributes:
|
87
|
+
try:
|
88
|
+
dependencies[attr.id] = self.container_service.get_dependency_type(attr, flags)
|
89
|
+
except TiferetError as e:
|
90
|
+
raise e
|
91
|
+
|
92
|
+
|
93
|
+
# Create the injector with the dependencies and constants.
|
94
|
+
injector = create_injector.execute(
|
95
|
+
cache_key,
|
96
|
+
dependencies=dependencies,
|
97
|
+
**constants
|
98
|
+
)
|
99
|
+
|
100
|
+
# Cache the injector.
|
101
|
+
self.cache.set(cache_key, injector)
|
102
|
+
|
103
|
+
# Return the injector.
|
104
|
+
return injector
|
105
|
+
|
106
|
+
# * method: get_dependency
|
107
|
+
def get_dependency(self, attribute_id: str, flags: List[str] = []) -> Any:
|
213
108
|
'''
|
214
|
-
|
109
|
+
Get an injector dependency by its attribute ID.
|
215
110
|
|
216
|
-
:
|
217
|
-
:type attribute: ContainerAttribute
|
218
|
-
:param flag: The flag for the dependency.
|
219
|
-
:type flag: str
|
220
|
-
:return: The dependency.
|
111
|
+
:return: The container attribute.
|
221
112
|
:rtype: Any
|
222
113
|
'''
|
223
114
|
|
224
|
-
# Get the
|
225
|
-
|
115
|
+
# Get the cached injector.
|
116
|
+
injector = self.build_injector(flags)
|
226
117
|
|
227
|
-
#
|
228
|
-
|
229
|
-
|
118
|
+
# Get the dependency from the injector.
|
119
|
+
dependency = get_dependency.execute(
|
120
|
+
injector=injector,
|
121
|
+
dependency_name=attribute_id,
|
122
|
+
)
|
123
|
+
|
124
|
+
# Raise an error if the dependency is not found.
|
125
|
+
if not dependency:
|
126
|
+
raise_error.execute(
|
127
|
+
'CONTAINER_DEPENDENCY_NOT_FOUND',
|
128
|
+
f'Dependency with ID {attribute_id} not found in container with flags {flags}.',
|
129
|
+
attribute_id,
|
130
|
+
flags
|
131
|
+
)
|
230
132
|
|
231
|
-
#
|
232
|
-
return
|
133
|
+
# Return the dependency.
|
134
|
+
return dependency
|
tiferet/contexts/error.py
CHANGED
@@ -4,71 +4,97 @@
|
|
4
4
|
from typing import Any, Tuple, List
|
5
5
|
|
6
6
|
# ** app
|
7
|
-
from
|
8
|
-
from ..
|
7
|
+
from .cache import CacheContext
|
8
|
+
from ..configs.error import ERRORS
|
9
|
+
from ..handlers.error import ErrorService
|
10
|
+
from ..models.error import Error, ModelObject
|
11
|
+
from ..commands import raise_error, TiferetError
|
9
12
|
|
10
13
|
|
11
14
|
# *** contexts
|
12
15
|
|
13
16
|
# ** context: error_context
|
14
|
-
class ErrorContext(
|
17
|
+
class ErrorContext(object):
|
15
18
|
'''
|
16
19
|
The error context object.
|
17
20
|
'''
|
18
21
|
|
19
|
-
# * attribute:
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
description='The errors lookup.'
|
25
|
-
)
|
26
|
-
)
|
22
|
+
# * attribute: error_service
|
23
|
+
error_service: ErrorService
|
24
|
+
|
25
|
+
# * attribute: cache
|
26
|
+
cache: CacheContext
|
27
27
|
|
28
28
|
# * method: init
|
29
|
-
def __init__(self,
|
29
|
+
def __init__(self, error_service: ErrorService, cache: CacheContext = None):
|
30
30
|
'''
|
31
|
-
Initialize the error context
|
32
|
-
|
33
|
-
:param
|
34
|
-
:type
|
31
|
+
Initialize the error context.
|
32
|
+
|
33
|
+
:param error_service: The error service to use for handling errors.
|
34
|
+
:type error_service: ErrorService
|
35
|
+
:param cache: The cache context to use for caching error data.
|
36
|
+
:type cache: CacheContext
|
37
|
+
'''
|
38
|
+
|
39
|
+
# Assign the attributes.
|
40
|
+
self.error_service = error_service
|
41
|
+
self.cache = cache if cache else CacheContext()
|
42
|
+
|
43
|
+
# * method: load_errors
|
44
|
+
def load_errors(self) -> List[Error]:
|
35
45
|
'''
|
46
|
+
Load errors from the error service.
|
36
47
|
|
37
|
-
|
38
|
-
|
48
|
+
:return: The list of loaded errors.
|
49
|
+
:rtype: List[Error]
|
50
|
+
'''
|
39
51
|
|
40
|
-
#
|
41
|
-
|
52
|
+
# Convert configured errors to a list of error objects.
|
53
|
+
configured_errors = [
|
54
|
+
ModelObject.new(
|
55
|
+
Error,
|
56
|
+
**error_data
|
57
|
+
) for error_data in ERRORS]
|
42
58
|
|
43
|
-
#
|
44
|
-
|
45
|
-
self.validate()
|
59
|
+
# Load errors from the error service, including any configured errors.
|
60
|
+
return self.error_service.load_errors(configured_errors)
|
46
61
|
|
47
|
-
|
48
|
-
|
62
|
+
|
63
|
+
# * method: get_error_by_code
|
64
|
+
def get_error_by_code(self, error_code: str) -> Error:
|
49
65
|
'''
|
50
|
-
|
66
|
+
Get an error by its code.
|
51
67
|
|
52
|
-
:
|
53
|
-
:
|
68
|
+
:param error_code: The error code to retrieve.
|
69
|
+
:type error_code: str
|
70
|
+
:return: The error object.
|
71
|
+
:rtype: Error
|
54
72
|
'''
|
55
73
|
|
56
|
-
#
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
74
|
+
# Check to see if there is an error map in the cache.
|
75
|
+
error_map = self.cache.get('error_map')
|
76
|
+
|
77
|
+
# If there is no error map or the error code does not exist in the map,
|
78
|
+
# we need to load the errors from the error service and create a new error map.
|
79
|
+
# This is to ensure that we always have the latest errors available.
|
80
|
+
if not error_map or not error_map.get(error_code):
|
81
|
+
errors = self.load_errors()
|
82
|
+
error_map = {error.error_code: error for error in errors}
|
83
|
+
self.cache.set('error_map', error_map)
|
84
|
+
|
85
|
+
# Raise an error if the error code does not exist in the error map.
|
86
|
+
if not error_map or error_code not in error_map:
|
87
|
+
raise_error.execute(
|
88
|
+
'ERROR_NOT_FOUND',
|
89
|
+
f'Error not found: {error_code}.',
|
90
|
+
error_code
|
67
91
|
)
|
68
|
-
|
92
|
+
|
93
|
+
# Return the error object from the error map.
|
94
|
+
return error_map.get(error_code)
|
69
95
|
|
70
96
|
# * method: handle_error
|
71
|
-
def handle_error(self, exception:
|
97
|
+
def handle_error(self, exception: TiferetError, lang: str = 'en_US', **kwargs) -> Tuple[bool, Any]:
|
72
98
|
'''
|
73
99
|
Handle an error.
|
74
100
|
|
@@ -80,47 +106,19 @@ class ErrorContext(Model):
|
|
80
106
|
:rtype: bool
|
81
107
|
'''
|
82
108
|
|
83
|
-
#
|
84
|
-
if isinstance(exception,
|
85
|
-
|
109
|
+
# Raise the exception if it is not a Tiferet error.
|
110
|
+
if not isinstance(exception, TiferetError):
|
111
|
+
raise exception
|
86
112
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
Format the error response.
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
:param kwargs: Additional keyword arguments.
|
95
|
-
:type kwargs: dict
|
96
|
-
:return: The formatted error message.
|
97
|
-
:rtype: Any
|
98
|
-
'''
|
99
|
-
|
100
|
-
# Split error message into error name and data.
|
101
|
-
message_tokens = error_message.split(': ', 1)
|
102
|
-
|
103
|
-
# Get error name and data.
|
104
|
-
if len(message_tokens) > 1:
|
105
|
-
error_name, error_data = message_tokens
|
106
|
-
else:
|
107
|
-
error_name = error_message
|
108
|
-
error_data = None
|
109
|
-
|
110
|
-
# Format error data if present.
|
111
|
-
error_data = error_data.split(', ') if error_data else None
|
112
|
-
|
113
|
-
# Get error.
|
114
|
-
error = self.errors.get(error_name)
|
115
|
-
|
116
|
-
# Set error response.
|
117
|
-
error_response = dict(
|
118
|
-
message=error.format(lang, *error_data if error_data else []),
|
119
|
-
error_code=error.error_code,
|
113
|
+
# Get the error by its code from the error service.
|
114
|
+
error = self.get_error_by_code(exception.error_code)
|
115
|
+
|
116
|
+
# Format the error response.
|
117
|
+
error_response = error.format_response(
|
118
|
+
lang,
|
119
|
+
*exception.args[1:],
|
120
120
|
**kwargs
|
121
121
|
)
|
122
122
|
|
123
|
-
# Return error response.
|
123
|
+
# Return the error response.
|
124
124
|
return error_response
|
125
|
-
|
126
|
-
|