tiferet 1.0.0a0__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.
- app/__init__.py +0 -0
- app/clients/__init__.py +0 -0
- app/clients/yaml.py +93 -0
- app/commands/__init__.py +0 -0
- app/commands/container.py +54 -0
- app/commands/error.py +21 -0
- app/commands/feature.py +90 -0
- app/configs/__init__.py +69 -0
- app/configs/app.py +16 -0
- app/configs/container.py +91 -0
- app/contexts/__init__.py +2 -0
- app/contexts/app.py +130 -0
- app/contexts/container.py +167 -0
- app/contexts/env.py +109 -0
- app/contexts/error.py +95 -0
- app/contexts/feature.py +79 -0
- app/contexts/request.py +108 -0
- app/data/__init__.py +4 -0
- app/data/app.py +227 -0
- app/data/container.py +179 -0
- app/data/error.py +99 -0
- app/data/feature.py +132 -0
- app/domain/__init__.py +5 -0
- app/domain/app.py +330 -0
- app/domain/container.py +141 -0
- app/domain/core.py +199 -0
- app/domain/error.py +136 -0
- app/domain/feature.py +176 -0
- app/repos/__init__.py +0 -0
- app/repos/app.py +102 -0
- app/repos/container.py +164 -0
- app/repos/error.py +173 -0
- app/repos/feature.py +169 -0
- app/services/__init__.py +4 -0
- app/services/cli.py +186 -0
- app/services/container.py +44 -0
- tiferet-1.0.0a0.dist-info/LICENSE +28 -0
- tiferet-1.0.0a0.dist-info/METADATA +13 -0
- tiferet-1.0.0a0.dist-info/RECORD +41 -0
- tiferet-1.0.0a0.dist-info/WHEEL +5 -0
- tiferet-1.0.0a0.dist-info/top_level.txt +1 -0
app/domain/error.py
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
# *** imports
|
2
|
+
|
3
|
+
# ** core
|
4
|
+
from ..domain import *
|
5
|
+
|
6
|
+
|
7
|
+
# *** models
|
8
|
+
|
9
|
+
# ** model: error_message0
|
10
|
+
class ErrorMessage(ValueObject):
|
11
|
+
'''
|
12
|
+
An error message object.
|
13
|
+
'''
|
14
|
+
|
15
|
+
# * attribute: lang
|
16
|
+
lang = t.StringType(
|
17
|
+
required=True,
|
18
|
+
metadata=dict(
|
19
|
+
description='The language of the error message text.'
|
20
|
+
)
|
21
|
+
)
|
22
|
+
|
23
|
+
# * attribute: text
|
24
|
+
text = t.StringType(
|
25
|
+
required=True,
|
26
|
+
metadata=dict(
|
27
|
+
description='The error message text.'
|
28
|
+
)
|
29
|
+
)
|
30
|
+
|
31
|
+
# * method: format
|
32
|
+
def format(self, *args) -> str:
|
33
|
+
'''
|
34
|
+
Formats the error message text.
|
35
|
+
|
36
|
+
:param args: The arguments to format the error message text with.
|
37
|
+
:type args: tuple
|
38
|
+
:return: The formatted error message text.
|
39
|
+
:rtype: str
|
40
|
+
'''
|
41
|
+
|
42
|
+
# If there are no arguments, return the error message text.
|
43
|
+
if not args:
|
44
|
+
return self.text
|
45
|
+
|
46
|
+
# Format the error message text and return it.
|
47
|
+
return self.text.format(*args)
|
48
|
+
|
49
|
+
|
50
|
+
# ** model: error
|
51
|
+
class Error(Entity):
|
52
|
+
'''
|
53
|
+
An error object.
|
54
|
+
'''
|
55
|
+
|
56
|
+
# * attribute: name
|
57
|
+
name = t.StringType(
|
58
|
+
required=True,
|
59
|
+
metadata=dict(
|
60
|
+
description='The name of the error.'
|
61
|
+
)
|
62
|
+
)
|
63
|
+
|
64
|
+
# * attribute: error_code
|
65
|
+
error_code = t.StringType(
|
66
|
+
metadata=dict(
|
67
|
+
description='The unique code of the error.'
|
68
|
+
)
|
69
|
+
)
|
70
|
+
|
71
|
+
# * attribute: message
|
72
|
+
message = t.ListType(
|
73
|
+
t.ModelType(ErrorMessage),
|
74
|
+
required=True,
|
75
|
+
metadata=dict(
|
76
|
+
description='The error message translations for the error.'
|
77
|
+
)
|
78
|
+
)
|
79
|
+
|
80
|
+
# * method: new
|
81
|
+
@staticmethod
|
82
|
+
def new(name: str, id: str = None, error_code: str = None, **kwargs) -> 'Error':
|
83
|
+
'''Initializes a new Error object.
|
84
|
+
|
85
|
+
:param name: The name of the error.
|
86
|
+
:type name: str
|
87
|
+
:param id: The unique identifier for the error.
|
88
|
+
:type id: str
|
89
|
+
:param error_code: The error code for the error.
|
90
|
+
:type error_code: str
|
91
|
+
:param kwargs: Additional keyword arguments.
|
92
|
+
:type kwargs: dict
|
93
|
+
:return: A new Error object.
|
94
|
+
'''
|
95
|
+
|
96
|
+
# Format name as upper case snake case.
|
97
|
+
name = name.upper().replace(' ', '_')
|
98
|
+
|
99
|
+
# Set Id as the name if not provided.
|
100
|
+
if not id:
|
101
|
+
id = name
|
102
|
+
|
103
|
+
# Set the error code as the name if not provided.
|
104
|
+
if not error_code:
|
105
|
+
error_code = name
|
106
|
+
|
107
|
+
# Create and return a new Error object.
|
108
|
+
return super(Error, Error).new(
|
109
|
+
id=id,
|
110
|
+
name=name,
|
111
|
+
error_code=error_code,
|
112
|
+
**kwargs
|
113
|
+
)
|
114
|
+
|
115
|
+
# * method: format
|
116
|
+
def format(self, lang: str = 'en_US', *args) -> str:
|
117
|
+
'''
|
118
|
+
Formats the error message text for the specified language.
|
119
|
+
|
120
|
+
:param lang: The language of the error message text.
|
121
|
+
:type lang: str
|
122
|
+
:param args: The format arguments for the error message text.
|
123
|
+
:type args: tuple
|
124
|
+
:return: The formatted error message text.
|
125
|
+
:rtype: str
|
126
|
+
'''
|
127
|
+
|
128
|
+
# Iterate through the error messages.
|
129
|
+
for msg in self.message:
|
130
|
+
|
131
|
+
# Skip if the language does not match.
|
132
|
+
if msg.lang != lang:
|
133
|
+
continue
|
134
|
+
|
135
|
+
# Format the error message text.
|
136
|
+
return msg.format(*args)
|
app/domain/feature.py
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
# *** imports
|
2
|
+
|
3
|
+
# ** app
|
4
|
+
from ..domain import *
|
5
|
+
|
6
|
+
|
7
|
+
# *** models
|
8
|
+
|
9
|
+
# ** model: feature_command
|
10
|
+
class FeatureCommand(ValueObject):
|
11
|
+
'''
|
12
|
+
A command object for a feature command.
|
13
|
+
'''
|
14
|
+
|
15
|
+
# * attribute: name
|
16
|
+
name = t.StringType(
|
17
|
+
required=True,
|
18
|
+
metadata=dict(
|
19
|
+
description='The name of the feature handler.'
|
20
|
+
)
|
21
|
+
)
|
22
|
+
|
23
|
+
# * attribute: attribute_id
|
24
|
+
attribute_id = t.StringType(
|
25
|
+
required=True,
|
26
|
+
metadata=dict(
|
27
|
+
description='The container attribute ID for the feature command.'
|
28
|
+
)
|
29
|
+
)
|
30
|
+
|
31
|
+
# * attribute: params
|
32
|
+
params = t.DictType(
|
33
|
+
t.StringType(),
|
34
|
+
default={},
|
35
|
+
metadata=dict(
|
36
|
+
description='The custom parameters for the feature handler.'
|
37
|
+
)
|
38
|
+
)
|
39
|
+
|
40
|
+
# * attribute: return_to_data
|
41
|
+
return_to_data = t.BooleanType(
|
42
|
+
metadata=dict(
|
43
|
+
description='Whether to return the feature command result to the feature data context.'
|
44
|
+
)
|
45
|
+
)
|
46
|
+
|
47
|
+
# * attribute: data_key
|
48
|
+
data_key = t.StringType(
|
49
|
+
metadata=dict(
|
50
|
+
description='The data key to store the feature command result in if Return to Data is True.'
|
51
|
+
)
|
52
|
+
)
|
53
|
+
|
54
|
+
# * attribute: pass_on_error
|
55
|
+
pass_on_error = t.BooleanType(
|
56
|
+
metadata=dict(
|
57
|
+
description='Whether to pass on the error if the feature handler fails.'
|
58
|
+
)
|
59
|
+
)
|
60
|
+
|
61
|
+
# * method: new
|
62
|
+
@staticmethod
|
63
|
+
def new(**kwargs) -> 'FeatureCommand':
|
64
|
+
'''Initializes a new FeatureCommand object.
|
65
|
+
|
66
|
+
:param kwargs: Additional keyword arguments.
|
67
|
+
:type kwargs: dict
|
68
|
+
:return: A new FeatureCommand object.
|
69
|
+
'''
|
70
|
+
|
71
|
+
# Create a new FeatureCommand object.
|
72
|
+
obj = FeatureCommand(dict(
|
73
|
+
**kwargs
|
74
|
+
), strict=False)
|
75
|
+
|
76
|
+
# Validate and return the new FeatureCommand object.
|
77
|
+
obj.validate()
|
78
|
+
return obj
|
79
|
+
|
80
|
+
|
81
|
+
# ** model: feature
|
82
|
+
class Feature(Entity):
|
83
|
+
'''
|
84
|
+
A feature object.
|
85
|
+
'''
|
86
|
+
|
87
|
+
# * attribute: name
|
88
|
+
name = t.StringType(
|
89
|
+
required=True,
|
90
|
+
metadata=dict(
|
91
|
+
description='The name of the feature.'
|
92
|
+
)
|
93
|
+
)
|
94
|
+
|
95
|
+
# * attribute: group_id
|
96
|
+
group_id = t.StringType(
|
97
|
+
required=True,
|
98
|
+
metadata=dict(
|
99
|
+
description='The context group identifier for the feature.'
|
100
|
+
)
|
101
|
+
)
|
102
|
+
|
103
|
+
# * attribute: description
|
104
|
+
description = t.StringType(
|
105
|
+
metadata=dict(
|
106
|
+
description='The description of the feature.'
|
107
|
+
)
|
108
|
+
)
|
109
|
+
|
110
|
+
# * attribute: commands
|
111
|
+
commands = t.ListType(
|
112
|
+
t.ModelType(FeatureCommand),
|
113
|
+
default=[],
|
114
|
+
metadata=dict(
|
115
|
+
description='The command handler workflow for the feature.'
|
116
|
+
)
|
117
|
+
)
|
118
|
+
|
119
|
+
# * attribute: log_params
|
120
|
+
log_params = t.DictType(
|
121
|
+
t.StringType(),
|
122
|
+
default={},
|
123
|
+
metadata=dict(
|
124
|
+
description='The parameters to log for the feature.'
|
125
|
+
)
|
126
|
+
)
|
127
|
+
|
128
|
+
# * method: new
|
129
|
+
@staticmethod
|
130
|
+
def new(name: str, group_id: str, feature_key: str, description: str = None, **kwargs) -> 'Feature':
|
131
|
+
'''Initializes a new Feature object.
|
132
|
+
|
133
|
+
:param name: The name of the feature.
|
134
|
+
:type name: str
|
135
|
+
:param group_id: The context group identifier of the feature.
|
136
|
+
:type group_id: str
|
137
|
+
:param feature_key: The key of the feature.
|
138
|
+
:type feature_key: str
|
139
|
+
:param description: The description of the feature.
|
140
|
+
:type description: str
|
141
|
+
:param kwargs: Additional keyword arguments.
|
142
|
+
:type kwargs: dict
|
143
|
+
:return: A new Feature object.
|
144
|
+
'''
|
145
|
+
|
146
|
+
# Feature ID is the group ID and feature key separated by a period.
|
147
|
+
id = f'{group_id}.{feature_key}'
|
148
|
+
|
149
|
+
# Set the description as the name if not provided.
|
150
|
+
if not description:
|
151
|
+
description = name
|
152
|
+
|
153
|
+
# Create and return a new Feature object.
|
154
|
+
return super(Feature, Feature).new(
|
155
|
+
id=id,
|
156
|
+
name=name,
|
157
|
+
group_id=group_id,
|
158
|
+
description=description,
|
159
|
+
**kwargs
|
160
|
+
)
|
161
|
+
|
162
|
+
# * method: add_handler
|
163
|
+
def add_handler(self, handler: FeatureCommand, position: int = None):
|
164
|
+
'''Adds a handler to the feature.
|
165
|
+
|
166
|
+
:param handler: The handler to add.
|
167
|
+
:type handler: FeatureCommand
|
168
|
+
:param position: The position to add the handler at.
|
169
|
+
:type position: int
|
170
|
+
'''
|
171
|
+
|
172
|
+
# Add the handler to the feature.
|
173
|
+
if position:
|
174
|
+
self.commands.insert(position, handler)
|
175
|
+
else:
|
176
|
+
self.commands.append(handler)
|
app/repos/__init__.py
ADDED
File without changes
|
app/repos/app.py
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# *** imports
|
2
|
+
|
3
|
+
# ** app
|
4
|
+
from ..domain.app import AppInterface
|
5
|
+
from ..data.app import AppInterfaceData
|
6
|
+
from ..clients import yaml as yaml_client
|
7
|
+
|
8
|
+
|
9
|
+
# *** repository
|
10
|
+
|
11
|
+
# ** interface: app_repository
|
12
|
+
class AppRepository(object):
|
13
|
+
'''
|
14
|
+
An app repository is a class that is used to get an app interface.
|
15
|
+
'''
|
16
|
+
|
17
|
+
# * method: list_interfaces
|
18
|
+
def list_interfaces(self) -> list[AppInterface]:
|
19
|
+
'''
|
20
|
+
List all app interfaces.
|
21
|
+
|
22
|
+
:return: The list of app interfaces.
|
23
|
+
:rtype: list[AppInterface]
|
24
|
+
'''
|
25
|
+
|
26
|
+
# Not implemented.
|
27
|
+
raise NotImplementedError()
|
28
|
+
|
29
|
+
# * method: get_interface
|
30
|
+
def get_interface(self, id: str) -> AppInterface:
|
31
|
+
'''
|
32
|
+
Get the app interface.
|
33
|
+
|
34
|
+
:param id: The app interface id.
|
35
|
+
:type id: str
|
36
|
+
:return: The app interface.
|
37
|
+
:rtype: AppInterface
|
38
|
+
'''
|
39
|
+
|
40
|
+
# Not implemented.
|
41
|
+
raise NotImplementedError()
|
42
|
+
|
43
|
+
|
44
|
+
# ** proxy: yaml_proxy
|
45
|
+
class YamlProxy(object):
|
46
|
+
|
47
|
+
# * field: config_file
|
48
|
+
config_file: str = None
|
49
|
+
|
50
|
+
# * method: init
|
51
|
+
def __init__(self, app_config_file: str):
|
52
|
+
'''
|
53
|
+
Initialize the YAML proxy.
|
54
|
+
|
55
|
+
:param app_config_file: The application configuration file.
|
56
|
+
:type app_config_file: str
|
57
|
+
'''
|
58
|
+
|
59
|
+
# Set the configuration file.
|
60
|
+
self.config_file = app_config_file
|
61
|
+
|
62
|
+
# * method: list_interfaces
|
63
|
+
def list_interfaces(self) -> list[AppInterface]:
|
64
|
+
'''
|
65
|
+
List all app interfaces.
|
66
|
+
|
67
|
+
:return: The list of app interfaces.
|
68
|
+
:rtype: list[AppInterface]
|
69
|
+
'''
|
70
|
+
|
71
|
+
# Load the app interface data from the yaml configuration file and map it to the app interface object.
|
72
|
+
interfaces = yaml_client.load(
|
73
|
+
self.config_file,
|
74
|
+
create_data=lambda data: [
|
75
|
+
AppInterfaceData.new(
|
76
|
+
**record
|
77
|
+
).map() for record in data],
|
78
|
+
start_node=lambda data: data.get('interfaces'))
|
79
|
+
|
80
|
+
# Return the list of app interface objects.
|
81
|
+
return interfaces
|
82
|
+
|
83
|
+
# * method: get_interface
|
84
|
+
def get_interface(self, id: str) -> AppInterface:
|
85
|
+
'''
|
86
|
+
Get the app interface.
|
87
|
+
|
88
|
+
:param id: The app interface id.
|
89
|
+
:type id: str
|
90
|
+
:return: The app interface.
|
91
|
+
:rtype: AppInterface
|
92
|
+
'''
|
93
|
+
|
94
|
+
# Load the app interface data from the yaml configuration file.
|
95
|
+
_data: AppInterface = yaml_client.load(
|
96
|
+
self.config_file,
|
97
|
+
create_data=lambda data: AppInterfaceData.new (
|
98
|
+
id=id, **data),
|
99
|
+
start_node=lambda data: data.get('interfaces').get(id))
|
100
|
+
|
101
|
+
# Return the app interface object.
|
102
|
+
return _data.map()
|
app/repos/container.py
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# *** imports
|
2
|
+
|
3
|
+
# ** core
|
4
|
+
from typing import List, Dict, Tuple
|
5
|
+
|
6
|
+
# ** app
|
7
|
+
from ..domain.container import ContainerAttribute
|
8
|
+
from ..data.container import ContainerAttributeYamlData
|
9
|
+
from ..clients import yaml as yaml_client
|
10
|
+
|
11
|
+
|
12
|
+
# *** repository
|
13
|
+
|
14
|
+
# * interface: container_repository
|
15
|
+
class ContainerRepository(object):
|
16
|
+
'''
|
17
|
+
Container repository interface.
|
18
|
+
'''
|
19
|
+
|
20
|
+
# * field: role
|
21
|
+
read_role: str = None
|
22
|
+
|
23
|
+
# * field: write_role
|
24
|
+
write_role: str = None
|
25
|
+
|
26
|
+
# * method: get_attribute
|
27
|
+
def get_attribute(self, attribute_id: str, type: str) -> ContainerAttribute:
|
28
|
+
'''
|
29
|
+
Get the container attribute.
|
30
|
+
|
31
|
+
:param attribute_id: The attribute id.
|
32
|
+
:type attribute_id: str
|
33
|
+
:param type: The container attribute type.
|
34
|
+
:type type: str
|
35
|
+
:return: The container attribute.
|
36
|
+
:rtype: ContainerAttribute
|
37
|
+
'''
|
38
|
+
|
39
|
+
# Not implemented.
|
40
|
+
raise NotImplementedError()
|
41
|
+
|
42
|
+
# * method: list_all
|
43
|
+
def list_all(self) -> Tuple[List[ContainerAttribute], List[str]]:
|
44
|
+
'''
|
45
|
+
List all the container attributes and constants.
|
46
|
+
|
47
|
+
:return: The list of container attributes and constants.
|
48
|
+
:rtype: List[ContainerAttribute]
|
49
|
+
'''
|
50
|
+
|
51
|
+
# Not implemented.
|
52
|
+
raise NotImplementedError()
|
53
|
+
|
54
|
+
# * method: save_attribute
|
55
|
+
def save_attribute(self, attribute: ContainerAttribute):
|
56
|
+
'''
|
57
|
+
Save the container attribute.
|
58
|
+
|
59
|
+
:param attribute: The container attribute.
|
60
|
+
:type attribute: ContainerAttribute
|
61
|
+
'''
|
62
|
+
|
63
|
+
# Not implemented.
|
64
|
+
raise NotImplementedError
|
65
|
+
|
66
|
+
|
67
|
+
# ** proxy: yaml_proxy
|
68
|
+
class YamlProxy(ContainerRepository):
|
69
|
+
'''
|
70
|
+
Yaml proxy for container attributes.
|
71
|
+
'''
|
72
|
+
|
73
|
+
# * init
|
74
|
+
def __init__(self, container_config_file: str, read_role: str = 'to_object.yaml', write_role: str = 'to_data.yaml'):
|
75
|
+
'''
|
76
|
+
Initialize the yaml proxy.
|
77
|
+
|
78
|
+
:param container_config_file: The YAML file path for the container configuration.
|
79
|
+
:type container_config_file: str
|
80
|
+
:param read_role: The read role for the yaml proxy.
|
81
|
+
:type read_role: str
|
82
|
+
:param write_role: The write role for the yaml proxy.
|
83
|
+
:type write_role: str
|
84
|
+
'''
|
85
|
+
|
86
|
+
# Set the container configuration file.
|
87
|
+
self.config_file = container_config_file
|
88
|
+
|
89
|
+
# Set the read role.
|
90
|
+
self.read_role = read_role
|
91
|
+
|
92
|
+
# Set the write role.
|
93
|
+
self.write_role = write_role
|
94
|
+
|
95
|
+
# * method: get_attribute
|
96
|
+
def get_attribute(self, attribute_id: str, type: str) -> ContainerAttribute:
|
97
|
+
'''
|
98
|
+
Get the attribute from the yaml file.
|
99
|
+
|
100
|
+
:param attribute_id: The attribute id.
|
101
|
+
:type attribute_id: str
|
102
|
+
:param type: The attribute type.
|
103
|
+
:type type: str
|
104
|
+
:return: The container attribute.
|
105
|
+
:rtype: ContainerAttribute
|
106
|
+
'''
|
107
|
+
|
108
|
+
# Load the attribute data from the yaml configuration file.
|
109
|
+
data = yaml_client.load(
|
110
|
+
self.config_file,
|
111
|
+
create_data=lambda data: ContainerAttributeYamlData.new(
|
112
|
+
id=attribute_id, **data),
|
113
|
+
start_node=lambda data: data.get('attrs').get(attribute_id),
|
114
|
+
)
|
115
|
+
|
116
|
+
# If the data is None or the type does not match, return None.
|
117
|
+
if data is None or data.type != type:
|
118
|
+
return None
|
119
|
+
|
120
|
+
# Return the attribute.
|
121
|
+
return data.map(self.read_role)
|
122
|
+
|
123
|
+
# * method: list_all
|
124
|
+
def list_all(self) -> Tuple[List[ContainerAttribute], Dict[str, str]]:
|
125
|
+
'''
|
126
|
+
List all the container attributes and constants.
|
127
|
+
|
128
|
+
:return: The list of container attributes and constants.
|
129
|
+
:rtype: List[ContainerAttribute]
|
130
|
+
'''
|
131
|
+
|
132
|
+
# Load the attribute data from the yaml configuration file.
|
133
|
+
attr_data, consts = yaml_client.load(
|
134
|
+
self.config_file,
|
135
|
+
create_data=lambda data: (
|
136
|
+
[ContainerAttributeYamlData.new(id=id, **attr_data) for id, attr_data in data.get('attrs', {}).items()],
|
137
|
+
data.get('const', {}),
|
138
|
+
),
|
139
|
+
)
|
140
|
+
|
141
|
+
# Return the list of container attributes.
|
142
|
+
return (
|
143
|
+
[data.map(self.read_role) for data in attr_data],
|
144
|
+
consts
|
145
|
+
)
|
146
|
+
|
147
|
+
# * method: save_attribute
|
148
|
+
def save_attribute(self, attribute: ContainerAttribute):
|
149
|
+
'''
|
150
|
+
Save the attribute to the yaml file.
|
151
|
+
|
152
|
+
:param attribute: The attribute to save.
|
153
|
+
:type attribute: ContainerAttribute
|
154
|
+
'''
|
155
|
+
|
156
|
+
# Create a new container attribute data object.
|
157
|
+
data = ContainerAttributeYamlData.from_model(attribute)
|
158
|
+
|
159
|
+
# Update the attribute data.
|
160
|
+
yaml_client.save(
|
161
|
+
self.config_file,
|
162
|
+
data.to_primitive(role=self.write_role),
|
163
|
+
f'container/attrs/{attribute.id}'
|
164
|
+
)
|