aspyx 1.4.0__py3-none-any.whl → 1.5.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.

@@ -5,8 +5,10 @@ including their methods, decorators, and type hints. It supports caching for per
5
5
  from __future__ import annotations
6
6
 
7
7
  import inspect
8
- from inspect import signature, getmembers
8
+ from inspect import signature
9
9
  import threading
10
+ from types import FunctionType
11
+
10
12
  from typing import Callable, get_type_hints, Type, Dict, Optional
11
13
  from weakref import WeakKeyDictionary
12
14
 
@@ -25,27 +27,64 @@ class DecoratorDescriptor:
25
27
  self.args = args
26
28
 
27
29
  def __str__(self):
28
- return f"@{self.decorator.__name__}({','.join(self.args)})"
30
+ return f"@{self.decorator.__name__}({', '.join(map(str, self.args))})"
29
31
 
30
32
  class Decorators:
31
33
  """
32
34
  Utility class that caches decorators ( Python does not have a feature for this )
33
35
  """
34
36
  @classmethod
35
- def add(cls, func, decorator: Callable, *args):
36
- decorators = getattr(func, '__decorators__', None)
37
+ def add(cls, func_or_class, decorator: Callable, *args):
38
+ """
39
+ Remember the decorator
40
+ Args:
41
+ func_or_class: a function or class
42
+ decorator: the decorator
43
+ *args: any arguments supplied to the decorator
44
+ """
45
+ decorators = getattr(func_or_class, '__decorators__', None)
37
46
  if decorators is None:
38
- setattr(func, '__decorators__', [DecoratorDescriptor(decorator, *args)])
47
+ setattr(func_or_class, '__decorators__', [DecoratorDescriptor(decorator, *args)])
39
48
  else:
40
49
  decorators.append(DecoratorDescriptor(decorator, *args))
41
50
 
42
51
  @classmethod
43
- def has_decorator(cls, func, callable: Callable) -> bool:
44
- return any(decorator.decorator is callable for decorator in Decorators.get(func))
52
+ def has_decorator(cls, func_or_class, callable: Callable) -> bool:
53
+ """
54
+ Return True, if the function or class is decorated with the decorator
55
+ Args:
56
+ func_or_class: a function or class
57
+ callable: the decorator
58
+
59
+ Returns:
60
+ bool: the result
61
+ """
62
+ return any(decorator.decorator is callable for decorator in Decorators.get(func_or_class))
45
63
 
46
64
  @classmethod
47
- def get(cls, func) -> list[DecoratorDescriptor]:
48
- return getattr(func, '__decorators__', [])
65
+ def get_decorator(cls, func_or_class, callable: Callable) -> DecoratorDescriptor:
66
+ return next((decorator for decorator in Decorators.get_all(func_or_class) if decorator.decorator is callable), None)
67
+
68
+ @classmethod
69
+ def get_all(cls, func_or_class) -> list[DecoratorDescriptor]:
70
+ return getattr(func_or_class, '__decorators__', [])
71
+
72
+ @classmethod
73
+ def get(cls, func_or_class) -> list[DecoratorDescriptor]:
74
+ """
75
+ return the list of decorators associated with the given function or class
76
+ Args:
77
+ func_or_class: the function or class
78
+
79
+ Returns:
80
+ list[DecoratorDescriptor]: the list
81
+ """
82
+ if inspect.ismethod(func_or_class):
83
+ func_or_class = func_or_class.__func__ # unwrap bound method
84
+
85
+ #return getattr(func_or_class, '__decorators__', []) will return inherited as well
86
+ return func_or_class.__dict__.get('__decorators__', [])
87
+
49
88
 
50
89
  class TypeDescriptor:
51
90
  """
@@ -79,30 +118,45 @@ class TypeDescriptor:
79
118
  def get_name(self) -> str:
80
119
  """
81
120
  return the method name
82
- :return: the method name
121
+
122
+ Returns:
123
+ str: the method name
83
124
  """
84
125
  return self.method.__name__
85
126
 
86
127
  def get_doc(self, default = "") -> str:
87
128
  """
88
129
  return the method docstring
89
- :param default: the default if no docstring is found
90
- :return: the docstring
130
+
131
+ Args:
132
+ default: the default if no docstring is found
133
+
134
+ Returns:
135
+ str: the docstring
91
136
  """
92
137
  return self.method.__doc__ or default
93
138
 
94
139
  def is_async(self) -> bool:
95
140
  """
96
141
  return true if the method is asynchronous
97
- :return: async flag
142
+
143
+ Returns:
144
+ bool: async flag
98
145
  """
99
146
  return inspect.iscoroutinefunction(self.method)
100
147
 
148
+ def get_decorators(self) -> list[DecoratorDescriptor]:
149
+ return self.decorators
150
+
101
151
  def get_decorator(self, decorator: Callable) -> Optional[DecoratorDescriptor]:
102
152
  """
103
153
  return the DecoratorDescriptor - if any - associated with the passed Callable
104
- :param decorator:
105
- :return: the DecoratorDescriptor or None
154
+
155
+ Args:
156
+ decorator: the decorator
157
+
158
+ Returns:
159
+ Optional[DecoratorDescriptor]: the DecoratorDescriptor or None
106
160
  """
107
161
  for dec in self.decorators:
108
162
  if dec.decorator is decorator:
@@ -113,8 +167,12 @@ class TypeDescriptor:
113
167
  def has_decorator(self, decorator: Callable) -> bool:
114
168
  """
115
169
  return True if the method is decorated with the decorator
116
- :param decorator: the decorator callable
117
- :return: True if the method is decorated with the decorator
170
+
171
+ Args:
172
+ decorator: the decorator callable
173
+
174
+ Returns:
175
+ bool: True if the method is decorated with the decorator
118
176
  """
119
177
  for dec in self.decorators:
120
178
  if dec.decorator is decorator:
@@ -172,10 +230,16 @@ class TypeDescriptor:
172
230
  # internal
173
231
 
174
232
  def _get_local_members(self, cls):
233
+ #return [
234
+ # (name, value)
235
+ # for name, value in getmembers(cls, predicate=inspect.isfunction)
236
+ # if name in cls.__dict__
237
+ #]
238
+
175
239
  return [
176
- (name, value)
177
- for name, value in getmembers(cls, predicate=inspect.isfunction)
178
- if name in cls.__dict__
240
+ (name, attr)
241
+ for name, attr in cls.__dict__.items()
242
+ if isinstance(attr, FunctionType)
179
243
  ]
180
244
 
181
245
  # public
@@ -1,5 +1,5 @@
1
1
  """
2
- threading utilities
2
+ A module with threading related utilities
3
3
  """
4
4
  from .thread_local import ThreadLocal
5
5
 
@@ -22,7 +22,9 @@ class ThreadLocal(Generic[T]):
22
22
  def get(self) -> Optional[T]:
23
23
  """
24
24
  return the current value or invoke the optional factory to compute one
25
- :return: the value associated with the current thread
25
+
26
+ Returns:
27
+ Optional[T]: the value associated with the current thread
26
28
  """
27
29
  if not hasattr(self.local, "value"):
28
30
  if self.factory is not None:
@@ -35,7 +37,9 @@ class ThreadLocal(Generic[T]):
35
37
  def set(self, value: T) -> None:
36
38
  """
37
39
  set a value in the current thread
38
- :param value: the value
40
+
41
+ Args:
42
+ value: the value
39
43
  """
40
44
  self.local.value = value
41
45
 
@@ -17,8 +17,12 @@ class StringBuilder:
17
17
  def append(self, s: str) -> "StringBuilder":
18
18
  """
19
19
  append a string to the end of the string builder
20
- :param s: the string
21
- :return: self
20
+
21
+ Args:
22
+ s (str): the string
23
+
24
+ Returns:
25
+ StringBuilder: self
22
26
  """
23
27
  self._parts.append(str(s))
24
28
 
@@ -0,0 +1,33 @@
1
+ Metadata-Version: 2.4
2
+ Name: aspyx
3
+ Version: 1.5.0
4
+ Summary: A DI and AOP library for Python
5
+ Author-email: Andreas Ernst <andreas.ernst7@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Andreas Ernst
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ License-File: LICENSE
28
+ Requires-Python: >=3.9
29
+ Requires-Dist: python-dotenv~=1.1.0
30
+ Requires-Dist: pyyaml~=6.0.2
31
+ Description-Content-Type: text/markdown
32
+
33
+ aspyx
@@ -0,0 +1,24 @@
1
+ aspyx/__init__.py,sha256=MsSFjiLMLJZ7QhUPpVBWKiyDnCzryquRyr329NoCACI,2
2
+ aspyx/di/__init__.py,sha256=AGVU2VBWQyBxSssvbk_GOKrYWIYtcmSoIlupz-Oqxi4,1138
3
+ aspyx/di/di.py,sha256=MN9I-KIAgBQYakctEZQH3W1_jjsc7pgGyeLt7eJr0yY,46539
4
+ aspyx/di/aop/__init__.py,sha256=rn6LSpzFtUOlgaBATyhLRWBzFmZ6XoVKA9B8SgQzYEI,746
5
+ aspyx/di/aop/aop.py,sha256=Cn-fqFW6PznVDM38fPX7mqlSpjGKMsgpJRBSYBv59xY,18403
6
+ aspyx/di/configuration/__init__.py,sha256=flM9A79J2wfA5I8goQbxs4tTqYustR9tn_9s0YO2WJQ,484
7
+ aspyx/di/configuration/configuration.py,sha256=cXW40bPXiUZ9hUtBoZkSATT3nLrDPWsSqxtgASIBQaM,4375
8
+ aspyx/di/configuration/env_configuration_source.py,sha256=FXPvREzq2ZER6_GG5xdpx154TQQDxZVf7LW7cvaylAk,1446
9
+ aspyx/di/configuration/yaml_configuration_source.py,sha256=NDl3SeoLMNVlzHgfP-Ysvhco1tRew_zFnBL5gGy2WRk,550
10
+ aspyx/di/threading/__init__.py,sha256=qrWdaq7MewQ2UmZy4J0Dn6BhY-ahfiG3xsv-EHqoqSE,191
11
+ aspyx/di/threading/synchronized.py,sha256=BQ9PjMQUJsF5r-qWaDgvqg3AvFm_R9QZdKB49EkoelQ,1263
12
+ aspyx/exception/__init__.py,sha256=OZwv-C3ZHD0Eg1rohCQMj575WLJ7lfYuk6PZD6sh1MA,211
13
+ aspyx/exception/exception_manager.py,sha256=tv0nb0b2CFPiYWK6wwH9yI8hSc--9Xz9_xQVBwU42wc,5228
14
+ aspyx/reflection/__init__.py,sha256=r2sNJrfHDpuqaIYu4fTYsoo046gpgn4VTd7bsS3mQJY,282
15
+ aspyx/reflection/proxy.py,sha256=9zqzmK2HGGx7LxdiBw8MfKRNT8H03h_0I6Y972eKFH8,2582
16
+ aspyx/reflection/reflection.py,sha256=HYzbzExG7jzdHG_AggrRxy9yte6Cl192dPsJBRl785Y,8939
17
+ aspyx/threading/__init__.py,sha256=3clmbCDP37GPan3dWtxTQvpg0Ti4aFzruAbUClkHGi0,147
18
+ aspyx/threading/thread_local.py,sha256=86dNtbA4k2B-rNUUnZgn3_pU0DAojgLrRnh8RL6zf1E,1196
19
+ aspyx/util/__init__.py,sha256=8H2yKkXu3nkRGeTerb8ialzKGfvzUx44XUWFUYcYuQM,125
20
+ aspyx/util/stringbuilder.py,sha256=a-0T4YEXSJFUuQ3ztKN1ZPARkh8dIGMSkNEEJHRN7dc,856
21
+ aspyx-1.5.0.dist-info/METADATA,sha256=dm6A8H-_qsn1NDzfFFG2AYclm7Bj6BbLdgtbuVRR6HY,1540
22
+ aspyx-1.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
+ aspyx-1.5.0.dist-info/licenses/LICENSE,sha256=n4jfx_MNj7cBtPhhI7MCoB_K35cj1icP9yJ4Rh4vlvY,1070
24
+ aspyx-1.5.0.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-