aspyx 1.0.0__py3-none-any.whl → 1.1.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 CHANGED
@@ -1,9 +1,12 @@
1
- from .di import InjectorException, CallableProcessor, LifecycleCallable, Lifecycle, Providers, Environment, ClassInstanceProvider, injectable, factory, environment, inject, create, on_init, on_destroy, inject_environment, Factory, PostProcessor
1
+ """
2
+ This module provides dependency injection and aop capabilities for Python applications.
3
+ """
4
+ from .di import InjectorException, AbstractCallableProcessor, LifecycleCallable, Lifecycle, Providers, Environment, ClassInstanceProvider, injectable, factory, environment, inject, create, on_init, on_running, on_destroy, inject_environment, Factory, PostProcessor
2
5
 
3
6
  # import something from the subpackages, so that teh decorators are executed
4
7
 
5
- from aspyx.di.configuration import ConfigurationManager
6
- from aspyx.di.aop import before
8
+ from .configuration import ConfigurationManager
9
+ from .aop import before
7
10
 
8
11
  imports = [ConfigurationManager, before]
9
12
 
@@ -18,12 +21,13 @@ __all__ = [
18
21
  "create",
19
22
 
20
23
  "on_init",
24
+ "on_running",
21
25
  "on_destroy",
22
26
  "inject_environment",
23
27
  "Factory",
24
28
  "PostProcessor",
25
- "CallableProcessor",
29
+ "AbstractCallableProcessor",
26
30
  "LifecycleCallable",
27
31
  "InjectorException",
28
32
  "Lifecycle"
29
- ]
33
+ ]
aspyx/di/aop/__init__.py CHANGED
@@ -1,3 +1,6 @@
1
+ """
2
+ AOP module
3
+ """
1
4
  from .aop import before, after, classes, around, error, advice, methods, Invocation
2
5
  __all__ = [
3
6
  "before",
@@ -8,4 +11,4 @@ __all__ = [
8
11
  "classes",
9
12
  "methods",
10
13
  "Invocation",
11
- ]
14
+ ]
aspyx/di/aop/aop.py CHANGED
@@ -1,3 +1,6 @@
1
+ """
2
+ This module provides aspect-oriented programming (AOP) capabilities for Python applications.
3
+ """
1
4
  from __future__ import annotations
2
5
 
3
6
  from abc import ABC, abstractmethod
@@ -16,8 +19,8 @@ from aspyx.di import injectable, Providers, ClassInstanceProvider, Environment,
16
19
 
17
20
  class AOPException(Exception):
18
21
  """
19
- Exception raised for errors in the aop logic."""
20
- pass
22
+ Exception raised for errors in the aop logic.
23
+ """
21
24
 
22
25
  class AspectType(Enum):
23
26
  """
@@ -62,6 +65,8 @@ class AspectTarget(ABC):
62
65
  def __init__(self):
63
66
  self._clazz = None
64
67
  self._instance = None
68
+ self._function = None
69
+ self._type = None
65
70
 
66
71
  self.patterns = []
67
72
  self.names = []
@@ -70,12 +75,10 @@ class AspectTarget(ABC):
70
75
 
71
76
  self.other : list[AspectTarget] = []
72
77
 
73
- pass
74
-
75
78
  # abstract
76
79
 
77
80
  def _matches(self, clazz : Type, func):
78
- if not self._matchesSelf(clazz, func):
81
+ if not self._matches_self(clazz, func):
79
82
  for target in self.other:
80
83
  if target._matches(clazz, func):
81
84
  return True
@@ -85,7 +88,7 @@ class AspectTarget(ABC):
85
88
  return True
86
89
 
87
90
  @abstractmethod
88
- def _matchesSelf(self, clazz: Type, func):
91
+ def _matches_self(self, clazz: Type, func):
89
92
  pass
90
93
 
91
94
  # protected
@@ -112,7 +115,7 @@ class AspectTarget(ABC):
112
115
  def decorated_with(self, decorator):
113
116
  self.decorators.append(decorator)
114
117
  return self
115
-
118
+
116
119
  def matches(self, pattern: str):
117
120
  """
118
121
  Matches the target against a pattern.
@@ -130,17 +133,10 @@ class ClassAspectTarget(AspectTarget):
130
133
  __slots__ = [
131
134
  ]
132
135
 
133
- # constructor
134
-
135
- def __init__(self):
136
- super().__init__()
137
-
138
- pass
139
-
140
136
  # public
141
137
 
142
- def _matchesSelf(self, clazz : Type, func):
143
- classDescriptor = TypeDescriptor.for_type(clazz)
138
+ def _matches_self(self, clazz : Type, func):
139
+ class_descriptor = TypeDescriptor.for_type(clazz)
144
140
  #descriptor = TypeDescriptor.for_type(func)
145
141
  # type
146
142
 
@@ -151,7 +147,7 @@ class ClassAspectTarget(AspectTarget):
151
147
  # decorators
152
148
 
153
149
  if len(self.decorators) > 0:
154
- if next((decorator for decorator in self.decorators if classDescriptor.has_decorator(decorator)), None) is None:
150
+ if next((decorator for decorator in self.decorators if class_descriptor.has_decorator(decorator)), None) is None:
155
151
  return False
156
152
 
157
153
  # names
@@ -159,7 +155,7 @@ class ClassAspectTarget(AspectTarget):
159
155
  if len(self.names) > 0:
160
156
  if next((name for name in self.names if name == clazz.__name__), None) is None:
161
157
  return False
162
-
158
+
163
159
  # patterns
164
160
 
165
161
  if len(self.patterns) > 0:
@@ -167,36 +163,20 @@ class ClassAspectTarget(AspectTarget):
167
163
  return False
168
164
 
169
165
  return True
170
-
171
- # fluent
172
166
 
167
+ # fluent
173
168
 
174
-
175
169
  class MethodAspectTarget(AspectTarget):
176
170
  # properties
177
171
 
178
- __slots__ = [
179
- "_clazz",
180
- "_instance",
181
- "_type",
182
- "_function",
183
- "names",
184
- "patterns",
185
- "types",
186
- "decorators",
187
- ]
188
-
189
- # constructor
190
-
191
- def __init__(self):
192
- super().__init__()
172
+ __slots__ = [ ]
193
173
 
194
174
  # public
195
175
 
196
- def _matchesSelf(self, clazz : Type, func):
176
+ def _matches_self(self, clazz : Type, func):
197
177
  descriptor = TypeDescriptor.for_type(clazz)
198
178
 
199
- methodDescriptor = descriptor.get_method(func.__name__)
179
+ method_descriptor = descriptor.get_method(func.__name__)
200
180
 
201
181
  # type
202
182
 
@@ -207,7 +187,7 @@ class MethodAspectTarget(AspectTarget):
207
187
  # decorators
208
188
 
209
189
  if len(self.decorators) > 0:
210
- if next((decorator for decorator in self.decorators if methodDescriptor.has_decorator(decorator)), None) is None:
190
+ if next((decorator for decorator in self.decorators if method_descriptor.has_decorator(decorator)), None) is None:
211
191
  return False
212
192
 
213
193
  # names
@@ -215,13 +195,13 @@ class MethodAspectTarget(AspectTarget):
215
195
  if len(self.names) > 0:
216
196
  if next((name for name in self.names if name == func.__name__), None) is None:
217
197
  return False
218
-
198
+
219
199
  # patterns
220
200
 
221
201
  if len(self.patterns) > 0:
222
202
  if next((pattern for pattern in self.patterns if re.fullmatch(pattern, func.__name__) is not None), None) is None:
223
203
  return False
224
-
204
+
225
205
  # yipee
226
206
 
227
207
  return True
@@ -267,7 +247,7 @@ class FunctionJoinPoint(JoinPoint):
267
247
  self.func = func
268
248
 
269
249
  def call(self, invocation: 'Invocation'):
270
- invocation.currentJoinPoint = self
250
+ invocation.current_join_point = self
271
251
 
272
252
  return self.func(self.instance, invocation)
273
253
 
@@ -278,7 +258,7 @@ class MethodJoinPoint(FunctionJoinPoint):
278
258
  super().__init__(instance, func, None)
279
259
 
280
260
  def call(self, invocation: 'Invocation'):
281
- invocation.currentJoinPoint = self
261
+ invocation.current_join_point = self
282
262
 
283
263
  return self.func(*invocation.args, **invocation.kwargs)
284
264
 
@@ -302,20 +282,20 @@ class Invocation:
302
282
  "kwargs",
303
283
  "result",
304
284
  "exception",
305
- "joinPoints",
306
- "currentJoinPoint",
285
+ "join_points",
286
+ "current_join_point",
307
287
  ]
308
288
 
309
289
  # constructor
310
290
 
311
- def __init__(self, func, joinPoints: JoinPoints):
291
+ def __init__(self, func, join_points: JoinPoints):
312
292
  self.func = func
313
293
  self.args : list[object] = []
314
294
  self.kwargs = None
315
295
  self.result = None
316
296
  self.exception = None
317
- self.joinPoints = joinPoints
318
- self.currentJoinPoint = None
297
+ self.join_points = join_points
298
+ self.current_join_point = None
319
299
 
320
300
  def call(self, *args, **kwargs):
321
301
  # remember args
@@ -325,28 +305,28 @@ class Invocation:
325
305
 
326
306
  # run all before
327
307
 
328
- for joinPoint in self.joinPoints.before:
329
- joinPoint.call(self)
308
+ for join_point in self.join_points.before:
309
+ join_point.call(self)
330
310
 
331
311
  # run around's with the method being the last aspect!
332
312
 
333
313
  try:
334
- self.result = self.joinPoints.around[0].call(self) # will follow the proceed chain
314
+ self.result = self.join_points.around[0].call(self) # will follow the proceed chain
335
315
 
336
316
  except Exception as e:
337
317
  self.exception = e
338
- for joinPoint in self.joinPoints.error:
339
- joinPoint.call(self)
318
+ for join_point in self.join_points.error:
319
+ join_point.call(self)
340
320
 
341
321
  # run all before
342
322
 
343
- for joinPoint in self.joinPoints.after:
344
- joinPoint.call(self)
323
+ for join_point in self.join_points.after:
324
+ join_point.call(self)
345
325
 
346
326
  if self.exception is not None:
347
327
  raise self.exception # rethrow the error
348
- else:
349
- return self.result
328
+
329
+ return self.result
350
330
 
351
331
  def proceed(self, *args, **kwargs):
352
332
  """
@@ -358,7 +338,7 @@ class Invocation:
358
338
 
359
339
  # next one please...
360
340
 
361
- return self.currentJoinPoint.next.call(self)
341
+ return self.current_join_point.next.call(self)
362
342
 
363
343
  @injectable()
364
344
  class Advice:
@@ -374,7 +354,7 @@ class Advice:
374
354
  # constructor
375
355
 
376
356
  def __init__(self):
377
- self.cache : Dict[Type, Dict[Callable,JoinPoints]] = dict()
357
+ self.cache : Dict[Type, Dict[Callable,JoinPoints]] = {}
378
358
  self.lock = threading.RLock()
379
359
 
380
360
  # methods
@@ -391,7 +371,7 @@ class Advice:
391
371
 
392
372
  return aspects
393
373
 
394
- def joinPoints4(self, instance, environment: Environment) -> Dict[Callable,JoinPoints]:
374
+ def join_points4(self, instance, environment: Environment) -> Dict[Callable,JoinPoints]:
395
375
  clazz = type(instance)
396
376
 
397
377
  result = self.cache.get(clazz, None)
@@ -400,18 +380,18 @@ class Advice:
400
380
  result = self.cache.get(clazz, None)
401
381
 
402
382
  if result is None:
403
- result = dict()
383
+ result = {}
404
384
 
405
- for name, member in inspect.getmembers(clazz, predicate=inspect.isfunction):
406
- joinPoints = self.computeJoinPoints(clazz, member, environment)
407
- if joinPoints is not None:
408
- result[member] = joinPoints
385
+ for _, member in inspect.getmembers(clazz, predicate=inspect.isfunction):
386
+ join_points = self.compute_join_points(clazz, member, environment)
387
+ if join_points is not None:
388
+ result[member] = join_points
409
389
 
410
390
  self.cache[clazz] = result
411
391
 
412
392
  # add around methods
413
393
 
414
- value = dict()
394
+ value = {}
415
395
 
416
396
  for key, cjp in result.items():
417
397
  jp = JoinPoints(
@@ -432,7 +412,7 @@ class Advice:
432
412
 
433
413
  return value
434
414
 
435
- def computeJoinPoints(self, clazz, member, environment: Environment) -> Optional[JoinPoints]:
415
+ def compute_join_points(self, clazz, member, environment: Environment) -> Optional[JoinPoints]:
436
416
  befores = self.collect(clazz, member, AspectType.BEFORE, environment)
437
417
  arounds = self.collect(clazz, member, AspectType.AROUND, environment)
438
418
  afters = self.collect(clazz, member, AspectType.AFTER, environment)
@@ -448,9 +428,9 @@ class Advice:
448
428
  else:
449
429
  return None
450
430
 
451
- def sanityCheck(clazz: Type, name: str):
431
+ def sanity_check(clazz: Type, name: str):
452
432
  m = TypeDescriptor.for_type(clazz).get_method(name)
453
- if len(m.paramTypes) != 1 or m.paramTypes[0] != Invocation:
433
+ if len(m.param_types) != 1 or m.param_types[0] != Invocation:
454
434
  raise AOPException(f"Method {clazz.__name__}.{name} expected to have one parameter of type Invocation")
455
435
 
456
436
  # decorators
@@ -469,7 +449,7 @@ def advice(cls):
469
449
  if decorator is not None:
470
450
  target = decorator.args[0]
471
451
  target._clazz = cls
472
- sanityCheck(cls, name)
452
+ sanity_check(cls, name)
473
453
  Advice.targets.append(target)
474
454
 
475
455
  return cls
@@ -477,13 +457,13 @@ def advice(cls):
477
457
 
478
458
  # decorators
479
459
 
480
- def _register(decorator, targets: list[AspectTarget], func, aspectType: AspectType):
460
+ def _register(decorator, targets: list[AspectTarget], func, aspect_type: AspectType):
481
461
  target = targets[0]
482
462
 
483
463
  for i in range(1, len(targets)):
484
464
  target._add(targets[i])
485
465
 
486
- target.function(func).type(aspectType)
466
+ target.function(func).type(aspect_type)
487
467
 
488
468
  Decorators.add(func, decorator, target)
489
469
 
@@ -551,12 +531,12 @@ class AdviceProcessor(PostProcessor):
551
531
  # implement
552
532
 
553
533
  def process(self, instance: object, environment: Environment):
554
- joinPointDict = self.advice.joinPoints4(instance, environment)
534
+ join_point_dict = self.advice.join_points4(instance, environment)
555
535
 
556
- for member, joinPoints in joinPointDict.items():
557
- Environment.logger.debug(f"add aspects for {type(instance)}:{member.__name__}")
536
+ for member, join_points in join_point_dict.items():
537
+ Environment.logger.debug("add aspects for %s:%s", type(instance), member.__name__)
558
538
 
559
539
  def wrap(jp):
560
540
  return lambda *args, **kwargs: Invocation(member, jp).call(*args, **kwargs)
561
541
 
562
- setattr(instance, member.__name__, types.MethodType(wrap(joinPoints), instance))
542
+ setattr(instance, member.__name__, types.MethodType(wrap(join_points), instance))
@@ -1,3 +1,6 @@
1
+ """
2
+ Configuration value handling
3
+ """
1
4
  from .configuration import ConfigurationManager, ConfigurationSource, EnvConfigurationSource, value
2
5
 
3
6
  __all__ = [
@@ -5,4 +8,4 @@ __all__ = [
5
8
  "ConfigurationSource",
6
9
  "EnvConfigurationSource",
7
10
  "value"
8
- ]
11
+ ]
@@ -1,3 +1,6 @@
1
+ """
2
+ Configuration handling module.
3
+ """
1
4
  from __future__ import annotations
2
5
 
3
6
  from abc import ABC, abstractmethod
@@ -5,8 +8,8 @@ import os
5
8
  from typing import Optional, Type, TypeVar
6
9
  from dotenv import load_dotenv
7
10
 
8
- from aspyx.di import injectable, Environment, CallableProcessor, LifecycleCallable, Lifecycle, environment
9
- from aspyx.di.di import order
11
+ from aspyx.di import injectable, Environment, LifecycleCallable, Lifecycle
12
+ from aspyx.di.di import order, inject
10
13
  from aspyx.reflection import Decorators, DecoratorDescriptor, TypeDescriptor
11
14
 
12
15
  T = TypeVar("T")
@@ -15,7 +18,6 @@ class ConfigurationException(Exception):
15
18
  """
16
19
  Exception raised for errors in the configuration logic.
17
20
  """
18
- pass
19
21
 
20
22
  @injectable()
21
23
  class ConfigurationManager:
@@ -30,7 +32,7 @@ class ConfigurationManager:
30
32
 
31
33
  def __init__(self):
32
34
  self.sources = []
33
- self._data = dict()
35
+ self._data = {}
34
36
  self.coercions = {
35
37
  int: int,
36
38
  float: float,
@@ -82,17 +84,17 @@ class ConfigurationManager:
82
84
  current = current[key]
83
85
 
84
86
  return current
85
-
87
+
86
88
  v = resolve_value(path, default)
87
89
 
88
90
  if isinstance(v, type):
89
91
  return v
90
-
92
+
91
93
  if type in self.coercions:
92
94
  try:
93
95
  return self.coercions[type](v)
94
- except Exception:
95
- raise ConfigurationException(f"error during coercion to {type}")
96
+ except Exception as e:
97
+ raise ConfigurationException(f"error during coercion to {type}") from e
96
98
  else:
97
99
  raise ConfigurationException(f"unknown coercion to {type}")
98
100
 
@@ -104,15 +106,18 @@ class ConfigurationSource(ABC):
104
106
 
105
107
  __slots__ = []
106
108
 
107
- def __init__(self, manager: ConfigurationManager):
108
- manager._register(self)
109
+ def __init__(self):
109
110
  pass
110
111
 
112
+ @inject()
113
+ def set_manager(self, manager: ConfigurationManager):
114
+ manager._register(self)
115
+
111
116
  @abstractmethod
112
117
  def load(self) -> dict:
113
118
  """
114
- return the configuration values of this source as a dictionary."""
115
- pass
119
+ return the configuration values of this source as a dictionary.
120
+ """
116
121
 
117
122
  @injectable()
118
123
  class EnvConfigurationSource(ConfigurationSource):
@@ -124,8 +129,8 @@ class EnvConfigurationSource(ConfigurationSource):
124
129
 
125
130
  # constructor
126
131
 
127
- def __init__(self, manager: ConfigurationManager):
128
- super().__init__(manager)
132
+ def __init__(self):
133
+ super().__init__()
129
134
 
130
135
  load_dotenv()
131
136
 
@@ -183,10 +188,10 @@ def value(key: str, default=None):
183
188
  @injectable()
184
189
  @order(9)
185
190
  class ConfigurationLifecycleCallable(LifecycleCallable):
186
- def __init__(self, processor: CallableProcessor, manager: ConfigurationManager):
187
- super().__init__(value, processor, Lifecycle.ON_INIT)
191
+ def __init__(self, manager: ConfigurationManager):
192
+ super().__init__(value, Lifecycle.ON_INJECT)
188
193
 
189
194
  self.manager = manager
190
195
 
191
196
  def args(self, decorator: DecoratorDescriptor, method: TypeDescriptor.MethodDescriptor, environment: Environment):
192
- return [self.manager.get(decorator.args[0], method.paramTypes[0], decorator.args[1])]
197
+ return [self.manager.get(decorator.args[0], method.param_types[0], decorator.args[1])]