aspyx 1.0.0__py3-none-any.whl → 1.0.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/__init__.py +4 -1
- aspyx/di/aop/__init__.py +4 -1
- aspyx/di/aop/aop.py +56 -76
- aspyx/di/configuration/__init__.py +4 -1
- aspyx/di/configuration/configuration.py +20 -15
- aspyx/di/di.py +98 -113
- aspyx/reflection/__init__.py +4 -1
- aspyx/reflection/proxy.py +10 -7
- aspyx/reflection/reflection.py +29 -21
- {aspyx-1.0.0.dist-info → aspyx-1.0.1.dist-info}/METADATA +94 -33
- aspyx-1.0.1.dist-info/RECORD +14 -0
- aspyx-1.0.0.dist-info/RECORD +0 -14
- {aspyx-1.0.0.dist-info → aspyx-1.0.1.dist-info}/WHEEL +0 -0
- {aspyx-1.0.0.dist-info → aspyx-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {aspyx-1.0.0.dist-info → aspyx-1.0.1.dist-info}/top_level.txt +0 -0
aspyx/reflection/reflection.py
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides a TypeDescriptor class that allows introspection of Python classes,
|
|
3
|
+
including their methods, decorators, and type hints. It supports caching for performance
|
|
4
|
+
"""
|
|
1
5
|
from __future__ import annotations
|
|
2
6
|
|
|
3
7
|
import inspect
|
|
@@ -5,6 +9,7 @@ from inspect import signature, getmembers
|
|
|
5
9
|
from typing import Callable, get_type_hints, Type, Dict, Optional
|
|
6
10
|
from weakref import WeakKeyDictionary
|
|
7
11
|
|
|
12
|
+
|
|
8
13
|
class DecoratorDescriptor:
|
|
9
14
|
__slots__ = [
|
|
10
15
|
"decorator",
|
|
@@ -39,25 +44,25 @@ class TypeDescriptor:
|
|
|
39
44
|
self.clazz = cls
|
|
40
45
|
self.method = method
|
|
41
46
|
self.decorators: list[DecoratorDescriptor] = Decorators.get(method)
|
|
42
|
-
self.
|
|
47
|
+
self.param_types : list[Type] = []
|
|
43
48
|
|
|
44
49
|
type_hints = get_type_hints(method)
|
|
45
50
|
sig = signature(method)
|
|
46
51
|
|
|
47
|
-
for name,
|
|
52
|
+
for name, _ in sig.parameters.items():
|
|
48
53
|
if name != 'self':
|
|
49
|
-
self.
|
|
54
|
+
self.param_types.append(type_hints.get(name, object))
|
|
50
55
|
|
|
51
|
-
self.
|
|
56
|
+
self.return_type = type_hints.get('return', None)
|
|
52
57
|
|
|
53
|
-
def get_decorator(self, decorator):
|
|
58
|
+
def get_decorator(self, decorator) -> Optional[DecoratorDescriptor]:
|
|
54
59
|
for dec in self.decorators:
|
|
55
60
|
if dec.decorator is decorator:
|
|
56
61
|
return dec
|
|
57
62
|
|
|
58
63
|
return None
|
|
59
64
|
|
|
60
|
-
def has_decorator(self, decorator):
|
|
65
|
+
def has_decorator(self, decorator) -> bool:
|
|
61
66
|
for dec in self.decorators:
|
|
62
67
|
if dec.decorator is decorator:
|
|
63
68
|
return True
|
|
@@ -67,8 +72,6 @@ class TypeDescriptor:
|
|
|
67
72
|
def __str__(self):
|
|
68
73
|
return f"Method({self.method.__name__})"
|
|
69
74
|
|
|
70
|
-
# class methods
|
|
71
|
-
|
|
72
75
|
# class properties
|
|
73
76
|
|
|
74
77
|
_cache = WeakKeyDictionary()
|
|
@@ -81,6 +84,7 @@ class TypeDescriptor:
|
|
|
81
84
|
if descriptor is None:
|
|
82
85
|
descriptor = TypeDescriptor(clazz)
|
|
83
86
|
cls._cache[clazz] = descriptor
|
|
87
|
+
|
|
84
88
|
return descriptor
|
|
85
89
|
|
|
86
90
|
# constructor
|
|
@@ -88,27 +92,25 @@ class TypeDescriptor:
|
|
|
88
92
|
def __init__(self, cls):
|
|
89
93
|
self.cls = cls
|
|
90
94
|
self.decorators = Decorators.get(cls)
|
|
91
|
-
self.methods: Dict[str, TypeDescriptor.MethodDescriptor] =
|
|
92
|
-
self.
|
|
95
|
+
self.methods: Dict[str, TypeDescriptor.MethodDescriptor] = {}
|
|
96
|
+
self.local_methods: Dict[str, TypeDescriptor.MethodDescriptor] = {}
|
|
93
97
|
|
|
94
98
|
# check superclasses
|
|
95
99
|
|
|
96
|
-
self.
|
|
100
|
+
self.super_types = [TypeDescriptor.for_type(x) for x in cls.__bases__ if not x is object]
|
|
97
101
|
|
|
98
|
-
for
|
|
99
|
-
self.methods = self.methods |
|
|
102
|
+
for super_type in self.super_types:
|
|
103
|
+
self.methods = self.methods | super_type.methods
|
|
100
104
|
|
|
101
105
|
# methods
|
|
102
106
|
|
|
103
107
|
for name, member in self._get_local_members(cls):
|
|
104
108
|
method = TypeDescriptor.MethodDescriptor(cls, member)
|
|
105
|
-
self.
|
|
109
|
+
self.local_methods[name] = method
|
|
106
110
|
self.methods[name] = method
|
|
107
111
|
|
|
108
112
|
# internal
|
|
109
113
|
|
|
110
|
-
#isinstance(attr, classmethod)
|
|
111
|
-
|
|
112
114
|
def _get_local_members(self, cls):
|
|
113
115
|
return [
|
|
114
116
|
(name, value)
|
|
@@ -127,13 +129,19 @@ class TypeDescriptor:
|
|
|
127
129
|
|
|
128
130
|
def has_decorator(self, decorator) -> bool:
|
|
129
131
|
for dec in self.decorators:
|
|
130
|
-
if dec.decorator
|
|
132
|
+
if dec.decorator is decorator:
|
|
131
133
|
return True
|
|
132
134
|
|
|
133
135
|
return False
|
|
134
136
|
|
|
135
|
-
def
|
|
136
|
-
|
|
137
|
+
def get_methods(self, local = False) -> list[TypeDescriptor.MethodDescriptor]:
|
|
138
|
+
if local:
|
|
139
|
+
return list(self.local_methods.values())
|
|
140
|
+
else:
|
|
141
|
+
return list(self.methods.values())
|
|
137
142
|
|
|
138
|
-
def get_method(self, name) -> Optional[MethodDescriptor]:
|
|
139
|
-
|
|
143
|
+
def get_method(self, name: str, local = False) -> Optional[TypeDescriptor.MethodDescriptor]:
|
|
144
|
+
if local:
|
|
145
|
+
return self.local_methods.get(name, None)
|
|
146
|
+
else:
|
|
147
|
+
return self.methods.get(name, None)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aspyx
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.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
|
|
@@ -25,7 +25,7 @@ License: MIT License
|
|
|
25
25
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
26
|
SOFTWARE.
|
|
27
27
|
|
|
28
|
-
Requires-Python: >=3.
|
|
28
|
+
Requires-Python: >=3.9
|
|
29
29
|
Description-Content-Type: text/markdown
|
|
30
30
|
License-File: LICENSE
|
|
31
31
|
Dynamic: license-file
|
|
@@ -34,11 +34,13 @@ Dynamic: license-file
|
|
|
34
34
|
|
|
35
35
|

|
|
36
36
|

|
|
37
|
-
|
|
37
|
+

|
|
38
|
+

|
|
38
39
|
|
|
39
40
|
## Table of Contents
|
|
40
41
|
|
|
41
42
|
- [Introduction](#aspyx)
|
|
43
|
+
- [Installation](#installation)
|
|
42
44
|
- [Registration](#registration)
|
|
43
45
|
- [Class](#class)
|
|
44
46
|
- [Class Factory](#class-factory)
|
|
@@ -53,6 +55,7 @@ Dynamic: license-file
|
|
|
53
55
|
- [Custom scopes](#custom-scopes)
|
|
54
56
|
- [AOP](#aop)
|
|
55
57
|
- [Configuration](#configuration)
|
|
58
|
+
- [Reflection](#reflection)
|
|
56
59
|
|
|
57
60
|
# Introduction
|
|
58
61
|
|
|
@@ -71,12 +74,13 @@ The following features are supported
|
|
|
71
74
|
- container instances that relate to environment classes and manage the lifecylce of related objects
|
|
72
75
|
- hierarchical environments
|
|
73
76
|
|
|
77
|
+
The library is thread-safe!
|
|
78
|
+
|
|
74
79
|
Let's look at a simple example
|
|
75
80
|
|
|
76
81
|
```python
|
|
77
82
|
from aspyx.di import injectable, on_init, on_destroy, environment, Environment
|
|
78
83
|
|
|
79
|
-
|
|
80
84
|
@injectable()
|
|
81
85
|
class Foo:
|
|
82
86
|
def __init__(self):
|
|
@@ -85,13 +89,12 @@ class Foo:
|
|
|
85
89
|
def hello(msg: str):
|
|
86
90
|
print(f"hello {msg}")
|
|
87
91
|
|
|
88
|
-
|
|
89
92
|
@injectable() # eager and singleton by default
|
|
90
93
|
class Bar:
|
|
91
94
|
def __init__(self, foo: Foo): # will inject the Foo dependency
|
|
92
95
|
self.foo = foo
|
|
93
96
|
|
|
94
|
-
@on_init() # a lifecycle callback called
|
|
97
|
+
@on_init() # a lifecycle callback called after the constructor and all possible injections
|
|
95
98
|
def init(self):
|
|
96
99
|
...
|
|
97
100
|
|
|
@@ -101,41 +104,40 @@ class Bar:
|
|
|
101
104
|
|
|
102
105
|
@environment()
|
|
103
106
|
class SampleEnvironment:
|
|
104
|
-
# constructor
|
|
105
|
-
|
|
106
107
|
def __init__(self):
|
|
107
108
|
pass
|
|
108
109
|
|
|
109
|
-
|
|
110
110
|
# go, forrest
|
|
111
111
|
|
|
112
|
-
environment = SampleEnvironment
|
|
112
|
+
environment = Environment(SampleEnvironment)
|
|
113
113
|
|
|
114
114
|
bar = env.get(Bar)
|
|
115
|
-
|
|
115
|
+
|
|
116
|
+
bar.foo.hello("world")
|
|
116
117
|
```
|
|
117
118
|
|
|
118
|
-
The concepts should be pretty familiar
|
|
119
|
+
The concepts should be pretty familiar as well as the names which are a combination of Spring and Angular names :-)
|
|
119
120
|
|
|
120
121
|
Let's add some aspects...
|
|
121
122
|
|
|
122
123
|
```python
|
|
124
|
+
|
|
123
125
|
@advice
|
|
124
126
|
class SampleAdvice:
|
|
125
|
-
def __init__(self):
|
|
127
|
+
def __init__(self): # could inject additional stuff
|
|
126
128
|
pass
|
|
127
129
|
|
|
128
130
|
@before(methods().named("hello").of_type(Foo))
|
|
129
|
-
def
|
|
131
|
+
def call_before(self, invocation: Invocation):
|
|
130
132
|
print("before Foo.hello(...)")
|
|
131
133
|
|
|
132
134
|
@error(methods().named("hello").of_type(Foo))
|
|
133
|
-
def
|
|
135
|
+
def call_error(self, invocation: Invocation):
|
|
134
136
|
print("error Foo.hello(...)")
|
|
135
137
|
print(invocation.exception)
|
|
136
138
|
|
|
137
139
|
@around(methods().named("hello"))
|
|
138
|
-
def
|
|
140
|
+
def call_around(self, invocation: Invocation):
|
|
139
141
|
print("around Foo.hello()")
|
|
140
142
|
|
|
141
143
|
return invocation.proceed()
|
|
@@ -150,6 +152,14 @@ The invocation parameter stores the complete context of the current execution, w
|
|
|
150
152
|
|
|
151
153
|
Let's look at the details
|
|
152
154
|
|
|
155
|
+
# Installation
|
|
156
|
+
|
|
157
|
+
`pip install aspyx`
|
|
158
|
+
|
|
159
|
+
The library is tested with Python version > 3.8
|
|
160
|
+
|
|
161
|
+
Ready to go...
|
|
162
|
+
|
|
153
163
|
# Registration
|
|
154
164
|
|
|
155
165
|
Different mechanisms are available that make classes eligible for injection
|
|
@@ -171,12 +181,14 @@ All referenced types will be injected by the environemnt.
|
|
|
171
181
|
|
|
172
182
|
Only eligible types are allowed, of course!
|
|
173
183
|
|
|
184
|
+
The decorator accepts the keyword arguments
|
|
185
|
+
- `eager : boolean`
|
|
186
|
+
if `True`, the container will create the instances automatically while booting the environment. This is the default.
|
|
187
|
+
- `scope: str`
|
|
188
|
+
the name of a scope which will determine how often instances will be created.
|
|
189
|
+
`singleton` will create it only once - per environment -, while `request` will recreate it on every injection request. The default is `singleton`
|
|
174
190
|
|
|
175
|
-
|
|
176
|
-
- `eager=True` if `True`, the container will create the instances automatically while booting the environment
|
|
177
|
-
- `scope="singleton"` defines how often instances will be created. `singleton` will create it only once - per environment -, while `request` will recreate it on every injection request
|
|
178
|
-
|
|
179
|
-
Other scopes can be defined. Please check the corresponding chapter.
|
|
191
|
+
Other scopes - e.g. session related scopes - can be defined dynamically. Please check the corresponding chapter.
|
|
180
192
|
|
|
181
193
|
## Class Factory
|
|
182
194
|
|
|
@@ -386,17 +398,17 @@ class SampleAdvice:
|
|
|
386
398
|
pass
|
|
387
399
|
|
|
388
400
|
@before(methods().named("hello").of_type(Foo))
|
|
389
|
-
def
|
|
401
|
+
def call_before(self, invocation: Invocation):
|
|
390
402
|
# arguments: invocation.args
|
|
391
403
|
print("before Foo.hello(...)")
|
|
392
404
|
|
|
393
405
|
@error(methods().named("hello").of_type(Foo))
|
|
394
|
-
def
|
|
406
|
+
def call_error(self, invocation: Invocation):
|
|
395
407
|
print("error Foo.hello(...)")
|
|
396
408
|
print(invocation.exception)
|
|
397
409
|
|
|
398
410
|
@around(methods().named("hello"))
|
|
399
|
-
def
|
|
411
|
+
def call_around(self, invocation: Invocation):
|
|
400
412
|
print("around Foo.hello()")
|
|
401
413
|
|
|
402
414
|
return invocation.proceed() # will leave a result in invocation.result or invocation.exception in case of an exception
|
|
@@ -417,7 +429,7 @@ All methods are expected to hava single `Invocation` parameter, that stores, the
|
|
|
417
429
|
It is essential for `around` methods to call `proceed()` on the invocation, which will call the next around method in the chain and finally the original method.
|
|
418
430
|
If the `proceed` is called with parameters, they will replace the original parameters!
|
|
419
431
|
|
|
420
|
-
The
|
|
432
|
+
The argument list to the corresponding decorators control, how aspects are associated with which methods.
|
|
421
433
|
A fluent interface is used describe the mapping.
|
|
422
434
|
The parameters restrict either methods or classes and are constructed by a call to either `methods()` or `classes()`.
|
|
423
435
|
|
|
@@ -431,7 +443,20 @@ Both add the fluent methods:
|
|
|
431
443
|
- `decorated_with(type: Type)`
|
|
432
444
|
defines decorators on methods or classes
|
|
433
445
|
|
|
434
|
-
The fluent methods `named`, `matches` and `of_type` can be called multiple
|
|
446
|
+
The fluent methods `named`, `matches` and `of_type` can be called multiple times!
|
|
447
|
+
|
|
448
|
+
**Example**:
|
|
449
|
+
|
|
450
|
+
```python
|
|
451
|
+
@injectable()
|
|
452
|
+
class TransactionAdvice:
|
|
453
|
+
def __init__(self):
|
|
454
|
+
pass
|
|
455
|
+
|
|
456
|
+
@around(methods().decorated_with(transactional), classes().decorated_with(transactional))
|
|
457
|
+
def establish_transaction(self, invocation: Invocation):
|
|
458
|
+
...
|
|
459
|
+
```
|
|
435
460
|
|
|
436
461
|
# Configuration
|
|
437
462
|
|
|
@@ -452,10 +477,11 @@ This concept relies on a central object `ConfigurationManager` that stores the o
|
|
|
452
477
|
|
|
453
478
|
```python
|
|
454
479
|
class ConfigurationSource(ABC):
|
|
455
|
-
def __init__(self
|
|
456
|
-
manager._register(self)
|
|
480
|
+
def __init__(self):
|
|
457
481
|
pass
|
|
458
482
|
|
|
483
|
+
...
|
|
484
|
+
|
|
459
485
|
@abstractmethod
|
|
460
486
|
def load(self) -> dict:
|
|
461
487
|
pass
|
|
@@ -467,14 +493,12 @@ As a default environment variables are already supported.
|
|
|
467
493
|
|
|
468
494
|
Other sources can be added dynamically by just registering them.
|
|
469
495
|
|
|
496
|
+
**Example**:
|
|
470
497
|
```python
|
|
471
498
|
@injectable()
|
|
472
499
|
class SampleConfigurationSource(ConfigurationSource):
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
def __init__(self, manager: ConfigurationManager):
|
|
476
|
-
super().__init__(manager)
|
|
477
|
-
|
|
500
|
+
def __init__(self):
|
|
501
|
+
super().__init__()
|
|
478
502
|
|
|
479
503
|
def load(self) -> dict:
|
|
480
504
|
return {
|
|
@@ -487,6 +511,43 @@ class SampleConfigurationSource(ConfigurationSource):
|
|
|
487
511
|
}
|
|
488
512
|
```
|
|
489
513
|
|
|
514
|
+
# Reflection
|
|
515
|
+
|
|
516
|
+
As the library heavily relies on type introspection of classes and methods, a utility class `TypeDescriptor` is available that covers type information on classes.
|
|
517
|
+
|
|
518
|
+
After beeing instatiated with
|
|
519
|
+
|
|
520
|
+
```python
|
|
521
|
+
TypeDescriptor.for_type(<type>)
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
it offers the methods
|
|
525
|
+
- `get_methods(local=False)`
|
|
526
|
+
- `get_method(name: str, local=False)`
|
|
527
|
+
- `has_decorator(decorator) -> bool`
|
|
528
|
+
- `get_decorator(decorator)`
|
|
529
|
+
|
|
530
|
+
The returned method descriptors offer:
|
|
531
|
+
- `param_types`
|
|
532
|
+
- `return_type`
|
|
533
|
+
- `has_decorator(decorator)`
|
|
534
|
+
- `get_decorator(decorator)`
|
|
535
|
+
|
|
536
|
+
The management of decorators in turn relies on another utility class `Decorators` that caches decorators.
|
|
537
|
+
|
|
538
|
+
Whenver you define a custom decorator, you will need to register it accordingly.
|
|
539
|
+
|
|
540
|
+
**Example**:
|
|
541
|
+
```python
|
|
542
|
+
def transactional():
|
|
543
|
+
def decorator(func):
|
|
544
|
+
Decorators.add(func, transactional)
|
|
545
|
+
return func
|
|
546
|
+
|
|
547
|
+
return decorator
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
|
|
490
551
|
|
|
491
552
|
|
|
492
553
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
aspyx/di/__init__.py,sha256=G13Cz1MMElBKNWsrhgTEIvhmIKj5MX4uqK_Apke4w8I,897
|
|
2
|
+
aspyx/di/di.py,sha256=elT3XJokxYxPJ9mx528MAU-pmm9lIZF8_AXKGkjyhBo,31014
|
|
3
|
+
aspyx/di/aop/__init__.py,sha256=nOABex49zSyMZ2w1ezwX3Q3yrOcQRSDjDtSj0DwKVbQ,233
|
|
4
|
+
aspyx/di/aop/aop.py,sha256=1RUgijk8RsiXWTizfNQX1IfHF7b96kCPdUgahX_J4Io,14457
|
|
5
|
+
aspyx/di/configuration/__init__.py,sha256=Zw7h-OlbJD7LyJvzkgyF0EmVqra6oN_Pt0HuUdjTPTA,249
|
|
6
|
+
aspyx/di/configuration/configuration.py,sha256=dHYoM3jC43QeDVlT6-mGDj05Sz6-Nm91LNE2TfQT1UU,5740
|
|
7
|
+
aspyx/reflection/__init__.py,sha256=r2sNJrfHDpuqaIYu4fTYsoo046gpgn4VTd7bsS3mQJY,282
|
|
8
|
+
aspyx/reflection/proxy.py,sha256=zJ6Psd6zWfFABdrKOf4cULt3gibyqCRdcR6z8WKIkzE,1982
|
|
9
|
+
aspyx/reflection/reflection.py,sha256=NkBK94kjJ7rQpPsK4mzHzX5TLSlWRM3mbNVzkwOZo4o,4379
|
|
10
|
+
aspyx-1.0.1.dist-info/licenses/LICENSE,sha256=n4jfx_MNj7cBtPhhI7MCoB_K35cj1icP9yJ4Rh4vlvY,1070
|
|
11
|
+
aspyx-1.0.1.dist-info/METADATA,sha256=69OakKuzM1UK0YTgH-y6-473YWhylxQvt8v993WsqiU,16798
|
|
12
|
+
aspyx-1.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
13
|
+
aspyx-1.0.1.dist-info/top_level.txt,sha256=A_ZwhBY_ybIgjZlztd44eaOrWqkJAndiqjGlbJ3tR_I,6
|
|
14
|
+
aspyx-1.0.1.dist-info/RECORD,,
|
aspyx-1.0.0.dist-info/RECORD
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
aspyx/di/__init__.py,sha256=US6i6s94TIpk4eiRFKYm9JB0NnU9F_3RAoIoXa-OnTI,800
|
|
2
|
-
aspyx/di/di.py,sha256=IdMNkPmMaVhRNr8heE8msGO3KYEc69pf2pjcJ8_rp4E,31169
|
|
3
|
-
aspyx/di/aop/__init__.py,sha256=2mv6o38HHoBzF_nx8rsrvuOlUlNgYITmNRcQJVT2Bk8,213
|
|
4
|
-
aspyx/di/aop/aop.py,sha256=stgSLSBpOd9XV_qo7KEazinq8Ul_csWbCx1w30dioWw,14647
|
|
5
|
-
aspyx/di/configuration/__init__.py,sha256=YgUk1bHVYq1EJ9W4D_CJ9ZM-3kje-vzPNMxBdUm0Vlg,211
|
|
6
|
-
aspyx/di/configuration/configuration.py,sha256=6EG2kf2v5pk9fTeCQUD5j6Jo5v00CFd5Nz7qXyYmxKw,5725
|
|
7
|
-
aspyx/reflection/__init__.py,sha256=jZAjw5NDrtXENmlBsQ0u9MobcNkfEuT0Oey8IWNYh34,204
|
|
8
|
-
aspyx/reflection/proxy.py,sha256=Re643BJAgbQjmDXO5JAvj4mu3RTpe_HF3TcFQ1euArg,1910
|
|
9
|
-
aspyx/reflection/reflection.py,sha256=LIUu-SxA_GJ1JurbQKTrvMUrE05OOcXxXOu65zRWubw,4004
|
|
10
|
-
aspyx-1.0.0.dist-info/licenses/LICENSE,sha256=n4jfx_MNj7cBtPhhI7MCoB_K35cj1icP9yJ4Rh4vlvY,1070
|
|
11
|
-
aspyx-1.0.0.dist-info/METADATA,sha256=3AuH9LBUHpPfxu9BcmawTaaJIHTBWwHuFpP_gBasyh0,15227
|
|
12
|
-
aspyx-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
13
|
-
aspyx-1.0.0.dist-info/top_level.txt,sha256=A_ZwhBY_ybIgjZlztd44eaOrWqkJAndiqjGlbJ3tR_I,6
|
|
14
|
-
aspyx-1.0.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|