orionis 0.206.0__py3-none-any.whl → 0.208.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.
orionis/framework.py CHANGED
@@ -5,7 +5,7 @@
5
5
  NAME = "orionis"
6
6
 
7
7
  # Current version of the framework
8
- VERSION = "0.206.0"
8
+ VERSION = "0.208.0"
9
9
 
10
10
  # Full name of the author or maintainer of the project
11
11
  AUTHOR = "Raul Mauricio Uñate Castro"
@@ -1,7 +1,8 @@
1
- from typing import Any, Type, Dict, List, Tuple, Callable, Optional, TypeVar, Set
2
- import inspect
3
1
  import abc
4
- from functools import wraps
2
+ import ast
3
+ import inspect
4
+ import types
5
+ from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, TypeVar
5
6
 
6
7
  ABC = TypeVar('ABC', bound=abc.ABC)
7
8
 
@@ -51,7 +52,26 @@ class ReflexionAbstract:
51
52
  Set[str]
52
53
  Set of abstract method names
53
54
  """
54
- return {name for name, _ in self._abstract.__abstractmethods__}
55
+ methods = []
56
+ for method in self._abstract.__abstractmethods__:
57
+ if not isinstance(getattr(self._abstract, method), property):
58
+ methods.append(method)
59
+ return set(methods)
60
+
61
+ def getAbstractProperties(self) -> Set[str]:
62
+ """Get all abstract property names required by the class.
63
+
64
+ Returns
65
+ -------
66
+ Set[str]
67
+ Set of abstract property names
68
+ """
69
+ properties = []
70
+ for name in getattr(self._abstract, '__abstractmethods__', set()):
71
+ attr = getattr(self._abstract, name, None)
72
+ if isinstance(attr, property):
73
+ properties.append(name)
74
+ return set(properties)
55
75
 
56
76
  def getConcreteMethods(self) -> Dict[str, Callable]:
57
77
  """Get all concrete methods implemented in the abstract class.
@@ -88,13 +108,32 @@ class ReflexionAbstract:
88
108
  Returns
89
109
  -------
90
110
  List[str]
91
- List of class method names
111
+ List of class method names, excluding private/protected methods (starting with '_')
112
+
113
+ Notes
114
+ -----
115
+ - Uses inspect.getattr_static to avoid method binding
116
+ - Properly handles both @classmethod decorator and classmethod instances
117
+ - Filters out private/protected methods (starting with '_')
118
+
119
+ Examples
120
+ --------
121
+ >>> class MyAbstract(ABC):
122
+ ... @classmethod
123
+ ... def factory(cls): pass
124
+ ... @classmethod
125
+ ... def _protected_factory(cls): pass
126
+ >>> reflex = ReflexionAbstract(MyAbstract)
127
+ >>> reflex.getClassMethods()
128
+ ['factory']
92
129
  """
93
130
  return [
94
- name for name, member in inspect.getmembers(
95
- self._abstract,
96
- predicate=lambda x: isinstance(x, classmethod))
97
- if not name.startswith('_')
131
+ name for name in dir(self._abstract)
132
+ if not name.startswith('_') and
133
+ isinstance(
134
+ inspect.getattr_static(self._abstract, name),
135
+ (classmethod, types.MethodType)
136
+ )
98
137
  ]
99
138
 
100
139
  def getProperties(self) -> List[str]:
@@ -131,7 +170,31 @@ class ReflexionAbstract:
131
170
  If the method doesn't exist
132
171
  """
133
172
  method = getattr(self._abstract, methodName)
134
- return inspect.signature(method)
173
+ if callable(method):
174
+ return inspect.signature(method)
175
+
176
+ def getPropertySignature(self, propertyName: str) -> inspect.Signature:
177
+ """Get the signature of an abstract property's getter.
178
+
179
+ Parameters
180
+ ----------
181
+ propertyName : str
182
+ Name of the abstract property
183
+
184
+ Returns
185
+ -------
186
+ inspect.Signature
187
+ The getter signature of the abstract property
188
+
189
+ Raises
190
+ ------
191
+ AttributeError
192
+ If the property doesn't exist or is not an abstract property
193
+ """
194
+ attr = getattr(self._abstract, propertyName, None)
195
+ if isinstance(attr, property) and attr.fget is not None:
196
+ return inspect.signature(attr.fget)
197
+ raise AttributeError(f"{propertyName} is not an abstract property or doesn't have a getter.")
135
198
 
136
199
  def getDocstring(self) -> Optional[str]:
137
200
  """Get the docstring of the abstract class.
@@ -153,7 +216,7 @@ class ReflexionAbstract:
153
216
  """
154
217
  return tuple(
155
218
  base for base in self._abstract.__bases__
156
- if inspect.isabstract(base)
219
+ if inspect.isabstract(base) or issubclass(base, abc.ABC) or isinstance(base, abc.ABCMeta)
157
220
  )
158
221
 
159
222
  def getInterfaceMethods(self) -> Dict[str, inspect.Signature]:
@@ -220,29 +283,48 @@ class ReflexionAbstract:
220
283
  """
221
284
  return self._abstract.__annotations__
222
285
 
223
- def getDecorators(self, method_name: str) -> List[Callable]:
224
- """Get decorators applied to a method.
286
+ def getDecorators(self, method_name: str) -> List[str]:
287
+ """
288
+ Get decorators applied to a method.
225
289
 
226
290
  Parameters
227
291
  ----------
228
292
  method_name : str
229
- Name of the method
230
-
231
- Returns
232
- -------
233
- List[Callable]
234
- List of decorator functions
293
+ Name of the method to inspect
235
294
  """
236
- method = getattr(self._abstract, method_name)
237
- decorators = []
295
+ method = getattr(self._abstract, method_name, None)
296
+ if method is None:
297
+ return []
238
298
 
239
- if hasattr(method, '__wrapped__'):
240
- # Unwrap decorated functions
241
- while hasattr(method, '__wrapped__'):
242
- decorators.append(method)
243
- method = method.__wrapped__
244
-
245
- return decorators
299
+ try:
300
+ source = inspect.getsource(self._abstract)
301
+ except (OSError, TypeError):
302
+ return []
303
+
304
+ tree = ast.parse(source)
305
+
306
+ class DecoratorVisitor(ast.NodeVisitor):
307
+ def __init__(self):
308
+ self.decorators = []
309
+
310
+ def visit_FunctionDef(self, node):
311
+ if node.name == method_name:
312
+ for deco in node.decorator_list:
313
+ if isinstance(deco, ast.Name):
314
+ self.decorators.append(deco.id)
315
+ elif isinstance(deco, ast.Call):
316
+ # handles decorators with arguments like @deco(arg)
317
+ if isinstance(deco.func, ast.Name):
318
+ self.decorators.append(deco.func.id)
319
+ elif isinstance(deco, ast.Attribute):
320
+ self.decorators.append(deco.attr)
321
+ # No need to visit deeper
322
+ return
323
+
324
+ visitor = DecoratorVisitor()
325
+ visitor.visit(tree)
326
+
327
+ return visitor.decorators
246
328
 
247
329
  def isProtocol(self) -> bool:
248
330
  """Check if the abstract class is a Protocol.
@@ -198,7 +198,37 @@ class ReflexionInstance:
198
198
  '(x, y)'
199
199
  """
200
200
  method = getattr(self._instance, methodName)
201
- return inspect.signature(method)
201
+ if callable(method):
202
+ return inspect.signature(method)
203
+
204
+ def getPropertySignature(self, propertyName: str) -> inspect.Signature:
205
+ """Get the signature of a property getter.
206
+
207
+ Parameters
208
+ ----------
209
+ propertyName : str
210
+ Name of the property
211
+
212
+ Returns
213
+ -------
214
+ inspect.Signature
215
+ The property's getter method signature
216
+
217
+ Raises
218
+ ------
219
+ AttributeError
220
+ If the property doesn't exist or is not a property
221
+
222
+ Examples
223
+ --------
224
+ >>> sig = reflex.getPropertySignature('config')
225
+ >>> str(sig)
226
+ '(self)'
227
+ """
228
+ attr = getattr(type(self._instance), propertyName, None)
229
+ if isinstance(attr, property) and attr.fget is not None:
230
+ return inspect.signature(attr.fget)
231
+ raise AttributeError(f"{propertyName} is not a property or doesn't have a getter.")
202
232
 
203
233
  def getDocstring(self) -> Optional[str]:
204
234
  """Get the docstring of the instance's class.