aspyx 1.2.0__py3-none-any.whl → 1.3.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 +8 -4
- aspyx/di/aop/aop.py +87 -5
- aspyx/di/configuration/env_configuration_source.py +1 -1
- aspyx/di/configuration/yaml_configuration_source.py +1 -1
- aspyx/di/di.py +290 -200
- aspyx/di/threading/__init__.py +11 -0
- aspyx/di/threading/synchronized.py +46 -0
- aspyx/reflection/reflection.py +4 -1
- {aspyx-1.2.0.dist-info → aspyx-1.3.0.dist-info}/METADATA +96 -16
- aspyx-1.3.0.dist-info/RECORD +20 -0
- aspyx-1.2.0.dist-info/RECORD +0 -18
- {aspyx-1.2.0.dist-info → aspyx-1.3.0.dist-info}/WHEEL +0 -0
- {aspyx-1.2.0.dist-info → aspyx-1.3.0.dist-info}/licenses/LICENSE +0 -0
- {aspyx-1.2.0.dist-info → aspyx-1.3.0.dist-info}/top_level.txt +0 -0
aspyx/di/__init__.py
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module provides dependency injection and aop capabilities for Python applications.
|
|
3
3
|
"""
|
|
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
|
|
4
|
+
from .di import conditional, requires_class, requires_feature, 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
|
-
# import something from the subpackages, so that
|
|
6
|
+
# import something from the subpackages, so that the decorators are executed
|
|
7
7
|
|
|
8
8
|
from .configuration import ConfigurationManager
|
|
9
9
|
from .aop import before
|
|
10
|
+
from .threading import SynchronizeAdvice
|
|
10
11
|
|
|
11
|
-
imports = [ConfigurationManager, before]
|
|
12
|
+
imports = [ConfigurationManager, before, SynchronizeAdvice]
|
|
12
13
|
|
|
13
14
|
__all__ = [
|
|
14
15
|
"ClassInstanceProvider",
|
|
@@ -30,5 +31,8 @@ __all__ = [
|
|
|
30
31
|
"AbstractCallableProcessor",
|
|
31
32
|
"LifecycleCallable",
|
|
32
33
|
"DIException",
|
|
33
|
-
"Lifecycle"
|
|
34
|
+
"Lifecycle",
|
|
35
|
+
"conditional",
|
|
36
|
+
"requires_class",
|
|
37
|
+
"requires_feature"
|
|
34
38
|
]
|
aspyx/di/aop/aop.py
CHANGED
|
@@ -50,7 +50,7 @@ class AspectTarget(ABC):
|
|
|
50
50
|
__slots__ = [
|
|
51
51
|
"_function",
|
|
52
52
|
"_type",
|
|
53
|
-
|
|
53
|
+
"_async",
|
|
54
54
|
"_clazz",
|
|
55
55
|
"_instance",
|
|
56
56
|
"names",
|
|
@@ -65,6 +65,7 @@ class AspectTarget(ABC):
|
|
|
65
65
|
def __init__(self):
|
|
66
66
|
self._clazz = None
|
|
67
67
|
self._instance = None
|
|
68
|
+
self._async = False
|
|
68
69
|
self._function = None
|
|
69
70
|
self._type = None
|
|
70
71
|
|
|
@@ -108,6 +109,10 @@ class AspectTarget(ABC):
|
|
|
108
109
|
|
|
109
110
|
return self
|
|
110
111
|
|
|
112
|
+
def that_are_async(self):
|
|
113
|
+
self._async = True
|
|
114
|
+
return self
|
|
115
|
+
|
|
111
116
|
def of_type(self, type: Type):
|
|
112
117
|
self.types.append(type)
|
|
113
118
|
return self
|
|
@@ -178,6 +183,14 @@ class MethodAspectTarget(AspectTarget):
|
|
|
178
183
|
|
|
179
184
|
method_descriptor = descriptor.get_method(func.__name__)
|
|
180
185
|
|
|
186
|
+
# async
|
|
187
|
+
|
|
188
|
+
name = method_descriptor.method.__name__
|
|
189
|
+
is_async = method_descriptor.is_async()
|
|
190
|
+
|
|
191
|
+
if self._async is not method_descriptor.is_async():
|
|
192
|
+
return False
|
|
193
|
+
|
|
181
194
|
# type
|
|
182
195
|
|
|
183
196
|
if len(self.types) > 0:
|
|
@@ -234,6 +247,9 @@ class JoinPoint:
|
|
|
234
247
|
def call(self, invocation: 'Invocation'):
|
|
235
248
|
pass
|
|
236
249
|
|
|
250
|
+
async def call_async(self, invocation: 'Invocation'):
|
|
251
|
+
pass
|
|
252
|
+
|
|
237
253
|
class FunctionJoinPoint(JoinPoint):
|
|
238
254
|
__slots__ = [
|
|
239
255
|
"instance",
|
|
@@ -251,6 +267,11 @@ class FunctionJoinPoint(JoinPoint):
|
|
|
251
267
|
|
|
252
268
|
return self.func(self.instance, invocation)
|
|
253
269
|
|
|
270
|
+
async def call_async(self, invocation: 'Invocation'):
|
|
271
|
+
invocation.current_join_point = self
|
|
272
|
+
|
|
273
|
+
return await self.func(self.instance, invocation)
|
|
274
|
+
|
|
254
275
|
class MethodJoinPoint(FunctionJoinPoint):
|
|
255
276
|
__slots__ = []
|
|
256
277
|
|
|
@@ -262,6 +283,11 @@ class MethodJoinPoint(FunctionJoinPoint):
|
|
|
262
283
|
|
|
263
284
|
return self.func(*invocation.args, **invocation.kwargs)
|
|
264
285
|
|
|
286
|
+
async def call_async(self, invocation: 'Invocation'):
|
|
287
|
+
invocation.current_join_point = self
|
|
288
|
+
|
|
289
|
+
return await self.func(*invocation.args, **invocation.kwargs)
|
|
290
|
+
|
|
265
291
|
@dataclass
|
|
266
292
|
class JoinPoints:
|
|
267
293
|
before: list[JoinPoint]
|
|
@@ -328,6 +354,37 @@ class Invocation:
|
|
|
328
354
|
|
|
329
355
|
return self.result
|
|
330
356
|
|
|
357
|
+
async def call_async(self, *args, **kwargs):
|
|
358
|
+
# remember args
|
|
359
|
+
|
|
360
|
+
self.args = args
|
|
361
|
+
self.kwargs = kwargs
|
|
362
|
+
|
|
363
|
+
# run all before
|
|
364
|
+
|
|
365
|
+
for join_point in self.join_points.before:
|
|
366
|
+
join_point.call(self)
|
|
367
|
+
|
|
368
|
+
# run around's with the method being the last aspect!
|
|
369
|
+
|
|
370
|
+
try:
|
|
371
|
+
self.result = await self.join_points.around[0].call_async(self) # will follow the proceed chain
|
|
372
|
+
|
|
373
|
+
except Exception as e:
|
|
374
|
+
self.exception = e
|
|
375
|
+
for join_point in self.join_points.error:
|
|
376
|
+
join_point.call(self)
|
|
377
|
+
|
|
378
|
+
# run all before
|
|
379
|
+
|
|
380
|
+
for join_point in self.join_points.after:
|
|
381
|
+
join_point.call(self)
|
|
382
|
+
|
|
383
|
+
if self.exception is not None:
|
|
384
|
+
raise self.exception # rethrow the error
|
|
385
|
+
|
|
386
|
+
return self.result
|
|
387
|
+
|
|
331
388
|
def proceed(self, *args, **kwargs):
|
|
332
389
|
"""
|
|
333
390
|
Proceed to the next join point in the around chain up to the original method.
|
|
@@ -340,6 +397,18 @@ class Invocation:
|
|
|
340
397
|
|
|
341
398
|
return self.current_join_point.next.call(self)
|
|
342
399
|
|
|
400
|
+
async def proceed_async(self, *args, **kwargs):
|
|
401
|
+
"""
|
|
402
|
+
Proceed to the next join point in the around chain up to the original method.
|
|
403
|
+
"""
|
|
404
|
+
if len(args) > 0 or len(kwargs) > 0: # as soon as we have args, we replace the current ones
|
|
405
|
+
self.args = args
|
|
406
|
+
self.kwargs = kwargs
|
|
407
|
+
|
|
408
|
+
# next one please...
|
|
409
|
+
|
|
410
|
+
return await self.current_join_point.next.call_async(self)
|
|
411
|
+
|
|
343
412
|
@injectable()
|
|
344
413
|
class Advice:
|
|
345
414
|
# static data
|
|
@@ -381,13 +450,14 @@ class Advice:
|
|
|
381
450
|
|
|
382
451
|
if result is None:
|
|
383
452
|
result = {}
|
|
453
|
+
self.cache[clazz] = result
|
|
384
454
|
|
|
385
455
|
for _, member in inspect.getmembers(clazz, predicate=inspect.isfunction):
|
|
386
456
|
join_points = self.compute_join_points(clazz, member, environment)
|
|
387
457
|
if join_points is not None:
|
|
388
458
|
result[member] = join_points
|
|
389
459
|
|
|
390
|
-
|
|
460
|
+
|
|
391
461
|
|
|
392
462
|
# add around methods
|
|
393
463
|
|
|
@@ -533,10 +603,22 @@ class AdviceProcessor(PostProcessor):
|
|
|
533
603
|
def process(self, instance: object, environment: Environment):
|
|
534
604
|
join_point_dict = self.advice.join_points4(instance, environment)
|
|
535
605
|
|
|
536
|
-
for member,
|
|
606
|
+
for member, join_points in join_point_dict.items():
|
|
537
607
|
Environment.logger.debug("add aspects for %s:%s", type(instance), member.__name__)
|
|
538
608
|
|
|
539
609
|
def wrap(jp):
|
|
540
|
-
|
|
610
|
+
def sync_wrapper(*args, **kwargs):
|
|
611
|
+
return Invocation(member, jp).call(*args, **kwargs)
|
|
612
|
+
|
|
613
|
+
return sync_wrapper
|
|
614
|
+
|
|
615
|
+
def wrap_async(jp):
|
|
616
|
+
async def async_wrapper(*args, **kwargs):
|
|
617
|
+
return await Invocation(member, jp).call_async(*args, **kwargs)
|
|
618
|
+
|
|
619
|
+
return async_wrapper
|
|
541
620
|
|
|
542
|
-
|
|
621
|
+
if inspect.iscoroutinefunction(member):
|
|
622
|
+
setattr(instance, member.__name__, types.MethodType(wrap_async(join_points), instance))
|
|
623
|
+
else:
|
|
624
|
+
setattr(instance, member.__name__, types.MethodType(wrap(join_points), instance))
|