aspyx 1.6.0__py3-none-any.whl → 1.6.1__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/configuration/configuration.py +0 -3
- aspyx/di/configuration/env_configuration_source.py +0 -5
- aspyx/di/configuration/yaml_configuration_source.py +0 -2
- aspyx/di/di.py +15 -7
- {aspyx-1.6.0.dist-info → aspyx-1.6.1.dist-info}/METADATA +24 -63
- {aspyx-1.6.0.dist-info → aspyx-1.6.1.dist-info}/RECORD +8 -8
- {aspyx-1.6.0.dist-info → aspyx-1.6.1.dist-info}/WHEEL +0 -0
- {aspyx-1.6.0.dist-info → aspyx-1.6.1.dist-info}/licenses/LICENSE +0 -0
aspyx/di/di.py
CHANGED
|
@@ -8,6 +8,7 @@ import logging
|
|
|
8
8
|
import importlib
|
|
9
9
|
import pkgutil
|
|
10
10
|
import sys
|
|
11
|
+
import time
|
|
11
12
|
|
|
12
13
|
from abc import abstractmethod, ABC
|
|
13
14
|
from enum import Enum
|
|
@@ -405,12 +406,10 @@ class ClassInstanceProvider(InstanceProvider):
|
|
|
405
406
|
# check constructor
|
|
406
407
|
|
|
407
408
|
init = TypeDescriptor.for_type(self.type).get_method("__init__")
|
|
408
|
-
if init is None:
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
for param in init.param_types:
|
|
413
|
-
types.append(param)
|
|
409
|
+
if init is not None:
|
|
410
|
+
self.params = len(init.param_types)
|
|
411
|
+
for param in init.param_types:
|
|
412
|
+
types.append(param)
|
|
414
413
|
|
|
415
414
|
# check @inject
|
|
416
415
|
|
|
@@ -976,7 +975,7 @@ class Environment:
|
|
|
976
975
|
"""
|
|
977
976
|
|
|
978
977
|
def add_provider(type: Type, provider: AbstractInstanceProvider):
|
|
979
|
-
Environment.logger.
|
|
978
|
+
Environment.logger.info("\tadd provider %s for %s", provider, type)
|
|
980
979
|
|
|
981
980
|
self.providers[type] = provider
|
|
982
981
|
|
|
@@ -989,6 +988,8 @@ class Environment:
|
|
|
989
988
|
if self.parent is None and env is not Boot:
|
|
990
989
|
self.parent = Boot.get_environment() # inherit environment including its manged instances!
|
|
991
990
|
|
|
991
|
+
start = time.perf_counter()
|
|
992
|
+
|
|
992
993
|
self.features = features
|
|
993
994
|
self.providers: Dict[Type, AbstractInstanceProvider] = {}
|
|
994
995
|
self.instances = []
|
|
@@ -1138,6 +1139,13 @@ class Environment:
|
|
|
1138
1139
|
for instance in self.instances:
|
|
1139
1140
|
self.execute_processors(Lifecycle.ON_RUNNING, instance)
|
|
1140
1141
|
|
|
1142
|
+
# done
|
|
1143
|
+
|
|
1144
|
+
end = time.perf_counter()
|
|
1145
|
+
|
|
1146
|
+
Environment.logger.info("created environment for class %s in %s ms, created %s instances", env.__qualname__, 1000 * (end - start), len(self.instances))
|
|
1147
|
+
|
|
1148
|
+
|
|
1141
1149
|
def is_registered_type(self, type: Type) -> bool:
|
|
1142
1150
|
provider = self.providers.get(type, None)
|
|
1143
1151
|
return provider is not None and not isinstance(provider, AmbiguousProvider)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aspyx
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.1
|
|
4
4
|
Summary: A DI and AOP library for Python
|
|
5
5
|
Author-email: Andreas Ernst <andreas.ernst7@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -117,9 +117,6 @@ from aspyx.di import injectable, on_init, on_destroy, module, Environment
|
|
|
117
117
|
|
|
118
118
|
@injectable()
|
|
119
119
|
class Foo:
|
|
120
|
-
def __init__(self):
|
|
121
|
-
pass
|
|
122
|
-
|
|
123
120
|
def hello(self, msg: str):
|
|
124
121
|
print(f"hello {msg}")
|
|
125
122
|
|
|
@@ -138,9 +135,7 @@ class Bar:
|
|
|
138
135
|
|
|
139
136
|
@module()
|
|
140
137
|
class SampleModule:
|
|
141
|
-
|
|
142
|
-
pass
|
|
143
|
-
|
|
138
|
+
pass
|
|
144
139
|
|
|
145
140
|
# create environment
|
|
146
141
|
|
|
@@ -148,7 +143,7 @@ environment = Environment(SampleModule)
|
|
|
148
143
|
|
|
149
144
|
# fetch an instance
|
|
150
145
|
|
|
151
|
-
bar =
|
|
146
|
+
bar = environment.get(Bar)
|
|
152
147
|
|
|
153
148
|
bar.foo.hello("world")
|
|
154
149
|
```
|
|
@@ -206,10 +201,7 @@ class Foo:
|
|
|
206
201
|
def __init__(self):
|
|
207
202
|
pass
|
|
208
203
|
```
|
|
209
|
-
|
|
210
|
-
All referenced types will be injected by the environment.
|
|
211
|
-
|
|
212
|
-
Only eligible types are allowed, of course!
|
|
204
|
+
If the class defines a constructor, all parameters - which are expected to be registered as well - will be injected automatically.
|
|
213
205
|
|
|
214
206
|
The decorator accepts the keyword arguments
|
|
215
207
|
- `eager : boolean`
|
|
@@ -235,9 +227,6 @@ Classes that implement the `Factory` base class and are annotated with `@factory
|
|
|
235
227
|
```python
|
|
236
228
|
@factory()
|
|
237
229
|
class TestFactory(Factory[Foo]):
|
|
238
|
-
def __init__(self):
|
|
239
|
-
pass
|
|
240
|
-
|
|
241
230
|
def create(self) -> Foo:
|
|
242
231
|
return Foo()
|
|
243
232
|
```
|
|
@@ -252,9 +241,6 @@ Any `injectable` can define methods decorated with `@create()`, that will create
|
|
|
252
241
|
```python
|
|
253
242
|
@injectable()
|
|
254
243
|
class Foo:
|
|
255
|
-
def __init__(self):
|
|
256
|
-
pass
|
|
257
|
-
|
|
258
244
|
@create(scope="request")
|
|
259
245
|
def create(self) -> Baz:
|
|
260
246
|
return Baz()
|
|
@@ -290,8 +276,7 @@ constructor type argument called `module`.
|
|
|
290
276
|
```python
|
|
291
277
|
@module()
|
|
292
278
|
class SampleModule:
|
|
293
|
-
|
|
294
|
-
pass
|
|
279
|
+
pass
|
|
295
280
|
```
|
|
296
281
|
|
|
297
282
|
A module is a regular injectable class decorated with `@module` that controls the discovery of injectable classes, by filtering classes according to their module location relative to this class.
|
|
@@ -311,13 +296,11 @@ By adding the parameter `features: list[str]`, it is possible to filter injectab
|
|
|
311
296
|
@injectable()
|
|
312
297
|
@conditional(requires_feature("dev"))
|
|
313
298
|
class DevOnly:
|
|
314
|
-
|
|
315
|
-
pass
|
|
299
|
+
pass
|
|
316
300
|
|
|
317
301
|
@module()
|
|
318
302
|
class SampleModule():
|
|
319
|
-
|
|
320
|
-
pass
|
|
303
|
+
pass
|
|
321
304
|
|
|
322
305
|
environment = Environment(SampleModule, features=["dev"])
|
|
323
306
|
```
|
|
@@ -329,8 +312,7 @@ By adding an `imports: list[Type]` parameter, specifying other module types, it
|
|
|
329
312
|
```python
|
|
330
313
|
@module()
|
|
331
314
|
class SampleModule(imports=[OtherModule]):
|
|
332
|
-
|
|
333
|
-
pass
|
|
315
|
+
pass
|
|
334
316
|
```
|
|
335
317
|
|
|
336
318
|
Another possibility is to add a parent environment as an `Environment` constructor parameter
|
|
@@ -392,11 +374,8 @@ Different decorators are implemented, that call methods with computed values
|
|
|
392
374
|
```python
|
|
393
375
|
@injectable()
|
|
394
376
|
class Foo:
|
|
395
|
-
def __init__(self):
|
|
396
|
-
pass
|
|
397
|
-
|
|
398
377
|
@inject_environment()
|
|
399
|
-
def
|
|
378
|
+
def set_environment(self, env: Environment):
|
|
400
379
|
...
|
|
401
380
|
|
|
402
381
|
@inject()
|
|
@@ -586,9 +565,6 @@ A handy decorator `@synchronized` in combination with the respective advice is i
|
|
|
586
565
|
```python
|
|
587
566
|
@injectable()
|
|
588
567
|
class Foo:
|
|
589
|
-
def __init__(self):
|
|
590
|
-
pass
|
|
591
|
-
|
|
592
568
|
@synchronized()
|
|
593
569
|
def execute_synchronized(self):
|
|
594
570
|
...
|
|
@@ -601,9 +577,6 @@ It is possible to inject configuration values, by decorating methods with `@inje
|
|
|
601
577
|
```python
|
|
602
578
|
@injectable()
|
|
603
579
|
class Foo:
|
|
604
|
-
def __init__(self):
|
|
605
|
-
pass
|
|
606
|
-
|
|
607
580
|
@inject_value("HOME")
|
|
608
581
|
def inject_home(self, os: str):
|
|
609
582
|
...
|
|
@@ -615,13 +588,13 @@ Configuration values are managed centrally using a `ConfigurationManager`, which
|
|
|
615
588
|
|
|
616
589
|
```python
|
|
617
590
|
class ConfigurationSource(ABC):
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
...
|
|
591
|
+
@inject()
|
|
592
|
+
def set_manager(self, manager: ConfigurationManager):
|
|
593
|
+
manager._register(self)
|
|
622
594
|
|
|
623
595
|
@abstractmethod
|
|
624
596
|
def load(self) -> dict:
|
|
597
|
+
pass
|
|
625
598
|
```
|
|
626
599
|
|
|
627
600
|
The `load` method is able to return a tree-like structure by returning a `dict`.
|
|
@@ -670,11 +643,6 @@ Typically you create the required configuration sources in an environment class,
|
|
|
670
643
|
```python
|
|
671
644
|
@module()
|
|
672
645
|
class SampleModule:
|
|
673
|
-
# constructor
|
|
674
|
-
|
|
675
|
-
def __init__(self):
|
|
676
|
-
pass
|
|
677
|
-
|
|
678
646
|
@create()
|
|
679
647
|
def create_env_source(self) -> EnvConfigurationSource:
|
|
680
648
|
return EnvConfigurationSource()
|
|
@@ -733,7 +701,7 @@ def transactional(scope):
|
|
|
733
701
|
The class `ExceptionManager` is used to collect dynamic handlers for specific exceptions and is able to dispatch to the concrete functions
|
|
734
702
|
given a specific exception.
|
|
735
703
|
|
|
736
|
-
The handlers are declared by annoting a class with `@exception_handler` and decorating specific methods with `@
|
|
704
|
+
The handlers are declared by annoting a class with `@exception_handler` and decorating specific methods with `@catch`
|
|
737
705
|
|
|
738
706
|
**Example**:
|
|
739
707
|
|
|
@@ -745,11 +713,6 @@ class DerivedException(Exception):
|
|
|
745
713
|
|
|
746
714
|
@module()
|
|
747
715
|
class SampleModule:
|
|
748
|
-
# constructor
|
|
749
|
-
|
|
750
|
-
def __init__(self):
|
|
751
|
-
pass
|
|
752
|
-
|
|
753
716
|
@create()
|
|
754
717
|
def create_exception_manager(self) -> ExceptionManager:
|
|
755
718
|
return ExceptionManager()
|
|
@@ -758,19 +721,16 @@ class SampleModule:
|
|
|
758
721
|
@injectable()
|
|
759
722
|
@exception_handler()
|
|
760
723
|
class TestExceptionHandler:
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
@handle()
|
|
765
|
-
def handle_derived_exception(self, exception: DerivedException):
|
|
724
|
+
@catch()
|
|
725
|
+
def catch_derived_exception(self, exception: DerivedException):
|
|
766
726
|
ExceptionManager.proceed()
|
|
767
727
|
|
|
768
|
-
@
|
|
769
|
-
def
|
|
728
|
+
@catch()
|
|
729
|
+
def catch_exception(self, exception: Exception):
|
|
770
730
|
pass
|
|
771
731
|
|
|
772
|
-
@
|
|
773
|
-
def
|
|
732
|
+
@catch()
|
|
733
|
+
def catch_base_exception(self, exception: BaseException):
|
|
774
734
|
pass
|
|
775
735
|
|
|
776
736
|
|
|
@@ -798,9 +758,6 @@ Together with a simple around advice we can now add exception handling to any me
|
|
|
798
758
|
```python
|
|
799
759
|
@injectable()
|
|
800
760
|
class Service:
|
|
801
|
-
def __init__(self):
|
|
802
|
-
pass
|
|
803
|
-
|
|
804
761
|
def throw(self):
|
|
805
762
|
raise DerivedException()
|
|
806
763
|
|
|
@@ -843,3 +800,7 @@ class ExceptionAdvice:
|
|
|
843
800
|
**1.4.1**
|
|
844
801
|
|
|
845
802
|
- mkdocs
|
|
803
|
+
|
|
804
|
+
**1.6.1**
|
|
805
|
+
|
|
806
|
+
- default constructors not requires anymore
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
aspyx/__init__.py,sha256=MsSFjiLMLJZ7QhUPpVBWKiyDnCzryquRyr329NoCACI,2
|
|
2
2
|
aspyx/di/__init__.py,sha256=AGVU2VBWQyBxSssvbk_GOKrYWIYtcmSoIlupz-Oqxi4,1138
|
|
3
|
-
aspyx/di/di.py,sha256=
|
|
3
|
+
aspyx/di/di.py,sha256=HgmLl84s3FLKUs6UO5ULzLcwuyDIzo0Ev8WrPQm3INg,44821
|
|
4
4
|
aspyx/di/aop/__init__.py,sha256=rn6LSpzFtUOlgaBATyhLRWBzFmZ6XoVKA9B8SgQzYEI,746
|
|
5
5
|
aspyx/di/aop/aop.py,sha256=y300DG713Gcn97CdTKuBdFL2jaS5ouW6J0azZk0Byws,19181
|
|
6
6
|
aspyx/di/configuration/__init__.py,sha256=flM9A79J2wfA5I8goQbxs4tTqYustR9tn_9s0YO2WJQ,484
|
|
7
|
-
aspyx/di/configuration/configuration.py,sha256=
|
|
8
|
-
aspyx/di/configuration/env_configuration_source.py,sha256=
|
|
9
|
-
aspyx/di/configuration/yaml_configuration_source.py,sha256=
|
|
7
|
+
aspyx/di/configuration/configuration.py,sha256=GVk_oGi7H0COBD_q__ZydIXyl7PgxvwW2Lplr-t44ck,4337
|
|
8
|
+
aspyx/di/configuration/env_configuration_source.py,sha256=mVZXRTBn-zbkqGMV9Yn5EZsae4MlpAzc8nVozXaVwnE,1375
|
|
9
|
+
aspyx/di/configuration/yaml_configuration_source.py,sha256=FmtM3-Xi1waxurdI5NVWUNTCcrv6q_azk5XniOL0Pg0,522
|
|
10
10
|
aspyx/di/threading/__init__.py,sha256=qrWdaq7MewQ2UmZy4J0Dn6BhY-ahfiG3xsv-EHqoqSE,191
|
|
11
11
|
aspyx/di/threading/synchronized.py,sha256=6JOg5BXWrRIS5nRPH9iWR7T-kUglO4qWBQpLwhy99pI,1325
|
|
12
12
|
aspyx/exception/__init__.py,sha256=HfK0kk1Tcw9QaUYgIyMeBFDAIE83pkTrIGYUnoKJXPE,231
|
|
@@ -21,7 +21,7 @@ aspyx/util/__init__.py,sha256=B7QK3alguZqExBFGzx-OpHpYeoIc3ZGAL7pJnq8NNvI,352
|
|
|
21
21
|
aspyx/util/logger.py,sha256=Hti5JyajdPXlf_1jvVT3e6Gf9eLyAsIVJRdNBMahbJs,608
|
|
22
22
|
aspyx/util/serialization.py,sha256=BRsg-2S7E3IukJqxZGm7FvjTvV5d6rcyrpJT3aKoVmM,4252
|
|
23
23
|
aspyx/util/stringbuilder.py,sha256=a-0T4YEXSJFUuQ3ztKN1ZPARkh8dIGMSkNEEJHRN7dc,856
|
|
24
|
-
aspyx-1.6.
|
|
25
|
-
aspyx-1.6.
|
|
26
|
-
aspyx-1.6.
|
|
27
|
-
aspyx-1.6.
|
|
24
|
+
aspyx-1.6.1.dist-info/METADATA,sha256=H7d-mtHxb57xtVyxbvcz2385TvqslMxGHXzCtbDxdk8,26017
|
|
25
|
+
aspyx-1.6.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
26
|
+
aspyx-1.6.1.dist-info/licenses/LICENSE,sha256=n4jfx_MNj7cBtPhhI7MCoB_K35cj1icP9yJ4Rh4vlvY,1070
|
|
27
|
+
aspyx-1.6.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|