aspyx 1.0.1__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of aspyx might be problematic. Click here for more details.
- aspyx/di/__init__.py +7 -5
- aspyx/di/aop/aop.py +2 -2
- aspyx/di/configuration/__init__.py +4 -1
- aspyx/di/configuration/configuration.py +4 -54
- aspyx/di/configuration/env_configuration_source.py +55 -0
- aspyx/di/configuration/yaml_configuration_source.py +26 -0
- aspyx/di/di.py +260 -94
- aspyx/di/util/__init__.py +8 -0
- aspyx/di/util/stringbuilder.py +31 -0
- aspyx/reflection/reflection.py +40 -6
- {aspyx-1.0.1.dist-info → aspyx-1.2.0.dist-info}/METADATA +95 -27
- aspyx-1.2.0.dist-info/RECORD +18 -0
- aspyx-1.0.1.dist-info/RECORD +0 -14
- {aspyx-1.0.1.dist-info → aspyx-1.2.0.dist-info}/WHEEL +0 -0
- {aspyx-1.0.1.dist-info → aspyx-1.2.0.dist-info}/licenses/LICENSE +0 -0
- {aspyx-1.0.1.dist-info → aspyx-1.2.0.dist-info}/top_level.txt +0 -0
aspyx/di/__init__.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module provides dependency injection and aop capabilities for Python applications.
|
|
3
3
|
"""
|
|
4
|
-
from .di import
|
|
4
|
+
from .di import DIException, AbstractCallableProcessor, LifecycleCallable, Lifecycle, Providers, Environment, ClassInstanceProvider, injectable, factory, environment, inject, order, create, on_init, on_running, on_destroy, inject_environment, Factory, PostProcessor
|
|
5
5
|
|
|
6
6
|
# import something from the subpackages, so that teh decorators are executed
|
|
7
7
|
|
|
8
|
-
from
|
|
9
|
-
from
|
|
8
|
+
from .configuration import ConfigurationManager
|
|
9
|
+
from .aop import before
|
|
10
10
|
|
|
11
11
|
imports = [ConfigurationManager, before]
|
|
12
12
|
|
|
@@ -19,14 +19,16 @@ __all__ = [
|
|
|
19
19
|
"environment",
|
|
20
20
|
"inject",
|
|
21
21
|
"create",
|
|
22
|
+
"order",
|
|
22
23
|
|
|
23
24
|
"on_init",
|
|
25
|
+
"on_running",
|
|
24
26
|
"on_destroy",
|
|
25
27
|
"inject_environment",
|
|
26
28
|
"Factory",
|
|
27
29
|
"PostProcessor",
|
|
28
|
-
"
|
|
30
|
+
"AbstractCallableProcessor",
|
|
29
31
|
"LifecycleCallable",
|
|
30
|
-
"
|
|
32
|
+
"DIException",
|
|
31
33
|
"Lifecycle"
|
|
32
34
|
]
|
aspyx/di/aop/aop.py
CHANGED
|
@@ -533,10 +533,10 @@ class AdviceProcessor(PostProcessor):
|
|
|
533
533
|
def process(self, instance: object, environment: Environment):
|
|
534
534
|
join_point_dict = self.advice.join_points4(instance, environment)
|
|
535
535
|
|
|
536
|
-
for member,
|
|
536
|
+
for member, joinPoints in join_point_dict.items():
|
|
537
537
|
Environment.logger.debug("add aspects for %s:%s", type(instance), member.__name__)
|
|
538
538
|
|
|
539
539
|
def wrap(jp):
|
|
540
540
|
return lambda *args, **kwargs: Invocation(member, jp).call(*args, **kwargs)
|
|
541
541
|
|
|
542
|
-
setattr(instance, member.__name__, types.MethodType(wrap(
|
|
542
|
+
setattr(instance, member.__name__, types.MethodType(wrap(joinPoints), instance))
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Configuration value handling
|
|
3
3
|
"""
|
|
4
|
-
from .configuration import ConfigurationManager, ConfigurationSource,
|
|
4
|
+
from .configuration import ConfigurationManager, ConfigurationSource, value
|
|
5
|
+
from .env_configuration_source import EnvConfigurationSource
|
|
6
|
+
from .yaml_configuration_source import YamlConfigurationSource
|
|
5
7
|
|
|
6
8
|
__all__ = [
|
|
7
9
|
"ConfigurationManager",
|
|
8
10
|
"ConfigurationSource",
|
|
9
11
|
"EnvConfigurationSource",
|
|
12
|
+
"YamlConfigurationSource",
|
|
10
13
|
"value"
|
|
11
14
|
]
|
|
@@ -4,11 +4,9 @@ Configuration handling module.
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
from abc import ABC, abstractmethod
|
|
7
|
-
import os
|
|
8
7
|
from typing import Optional, Type, TypeVar
|
|
9
|
-
from dotenv import load_dotenv
|
|
10
8
|
|
|
11
|
-
from aspyx.di import injectable, Environment,
|
|
9
|
+
from aspyx.di import injectable, Environment, LifecycleCallable, Lifecycle
|
|
12
10
|
from aspyx.di.di import order, inject
|
|
13
11
|
from aspyx.reflection import Decorators, DecoratorDescriptor, TypeDescriptor
|
|
14
12
|
|
|
@@ -67,7 +65,7 @@ class ConfigurationManager:
|
|
|
67
65
|
|
|
68
66
|
def get(self, path: str, type: Type[T], default : Optional[T]=None) -> T:
|
|
69
67
|
"""
|
|
70
|
-
|
|
68
|
+
Retrieve a configuration value by path and type, with optional coercion.
|
|
71
69
|
Arguments:
|
|
72
70
|
path (str): The path to the configuration value, e.g. "database.host".
|
|
73
71
|
type (Type[T]): The expected type.
|
|
@@ -119,54 +117,6 @@ class ConfigurationSource(ABC):
|
|
|
119
117
|
return the configuration values of this source as a dictionary.
|
|
120
118
|
"""
|
|
121
119
|
|
|
122
|
-
@injectable()
|
|
123
|
-
class EnvConfigurationSource(ConfigurationSource):
|
|
124
|
-
"""
|
|
125
|
-
EnvConfigurationSource loads all environment variables.
|
|
126
|
-
"""
|
|
127
|
-
|
|
128
|
-
__slots__ = []
|
|
129
|
-
|
|
130
|
-
# constructor
|
|
131
|
-
|
|
132
|
-
def __init__(self):
|
|
133
|
-
super().__init__()
|
|
134
|
-
|
|
135
|
-
load_dotenv()
|
|
136
|
-
|
|
137
|
-
# implement
|
|
138
|
-
|
|
139
|
-
def load(self) -> dict:
|
|
140
|
-
def merge_dicts(a, b):
|
|
141
|
-
"""Recursively merges b into a"""
|
|
142
|
-
for key, value in b.items():
|
|
143
|
-
if isinstance(value, dict) and key in a and isinstance(a[key], dict):
|
|
144
|
-
merge_dicts(a[key], value)
|
|
145
|
-
else:
|
|
146
|
-
a[key] = value
|
|
147
|
-
return a
|
|
148
|
-
|
|
149
|
-
def explode_key(key, value):
|
|
150
|
-
"""Explodes keys with '.' or '/' into nested dictionaries"""
|
|
151
|
-
parts = key.replace('/', '.').split('.')
|
|
152
|
-
d = current = {}
|
|
153
|
-
for part in parts[:-1]:
|
|
154
|
-
current[part] = {}
|
|
155
|
-
current = current[part]
|
|
156
|
-
current[parts[-1]] = value
|
|
157
|
-
return d
|
|
158
|
-
|
|
159
|
-
exploded = {}
|
|
160
|
-
|
|
161
|
-
for key, value in os.environ.items():
|
|
162
|
-
if '.' in key or '/' in key:
|
|
163
|
-
partial = explode_key(key, value)
|
|
164
|
-
merge_dicts(exploded, partial)
|
|
165
|
-
else:
|
|
166
|
-
exploded[key] = value
|
|
167
|
-
|
|
168
|
-
return exploded
|
|
169
|
-
|
|
170
120
|
# decorator
|
|
171
121
|
|
|
172
122
|
def value(key: str, default=None):
|
|
@@ -188,8 +138,8 @@ def value(key: str, default=None):
|
|
|
188
138
|
@injectable()
|
|
189
139
|
@order(9)
|
|
190
140
|
class ConfigurationLifecycleCallable(LifecycleCallable):
|
|
191
|
-
def __init__(self,
|
|
192
|
-
super().__init__(value,
|
|
141
|
+
def __init__(self, manager: ConfigurationManager):
|
|
142
|
+
super().__init__(value, Lifecycle.ON_INJECT)
|
|
193
143
|
|
|
194
144
|
self.manager = manager
|
|
195
145
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""
|
|
2
|
+
EnvConfigurationSource - Loads environment variables as configuration source.
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from dotenv import load_dotenv
|
|
7
|
+
|
|
8
|
+
from .configuration import ConfigurationSource
|
|
9
|
+
|
|
10
|
+
class EnvConfigurationSource(ConfigurationSource):
|
|
11
|
+
"""
|
|
12
|
+
EnvConfigurationSource loads all environment variables.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
__slots__ = []
|
|
16
|
+
|
|
17
|
+
# constructor
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
super().__init__()
|
|
21
|
+
|
|
22
|
+
# implement
|
|
23
|
+
|
|
24
|
+
def load(self) -> dict:
|
|
25
|
+
def merge_dicts(a, b):
|
|
26
|
+
"""Recursively merges b into a"""
|
|
27
|
+
for key, value in b.items():
|
|
28
|
+
if isinstance(value, dict) and key in a and isinstance(a[key], dict):
|
|
29
|
+
merge_dicts(a[key], value)
|
|
30
|
+
else:
|
|
31
|
+
a[key] = value
|
|
32
|
+
return a
|
|
33
|
+
|
|
34
|
+
def explode_key(key, value):
|
|
35
|
+
"""Explodes keys with '.' or '/' into nested dictionaries"""
|
|
36
|
+
parts = key.replace('/', '.').split('.')
|
|
37
|
+
d = current = {}
|
|
38
|
+
for part in parts[:-1]:
|
|
39
|
+
current[part] = {}
|
|
40
|
+
current = current[part]
|
|
41
|
+
current[parts[-1]] = value
|
|
42
|
+
return d
|
|
43
|
+
|
|
44
|
+
exploded = {}
|
|
45
|
+
|
|
46
|
+
load_dotenv()
|
|
47
|
+
|
|
48
|
+
for key, value in os.environ.items():
|
|
49
|
+
if '.' in key or '/' in key:
|
|
50
|
+
partial = explode_key(key, value)
|
|
51
|
+
merge_dicts(exploded, partial)
|
|
52
|
+
else:
|
|
53
|
+
exploded[key] = value
|
|
54
|
+
|
|
55
|
+
return exploded
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
YamlConfigurationSource - Loads variables from a YAML configuration file.
|
|
3
|
+
"""
|
|
4
|
+
import yaml
|
|
5
|
+
|
|
6
|
+
from .configuration import ConfigurationSource
|
|
7
|
+
|
|
8
|
+
class YamlConfigurationSource(ConfigurationSource):
|
|
9
|
+
"""
|
|
10
|
+
YamlConfigurationSource loads variables from a YAML configuration file.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__slots__ = ["file"]
|
|
14
|
+
|
|
15
|
+
# constructor
|
|
16
|
+
|
|
17
|
+
def __init__(self, file: str):
|
|
18
|
+
super().__init__()
|
|
19
|
+
|
|
20
|
+
self.file = file
|
|
21
|
+
|
|
22
|
+
# implement
|
|
23
|
+
|
|
24
|
+
def load(self) -> dict:
|
|
25
|
+
with open(self.file, "r") as file:
|
|
26
|
+
return yaml.safe_load(file)
|