orionis 0.205.0__py3-none-any.whl → 0.207.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 +1 -1
- orionis/luminate/support/inspection/reflexion_abstract.py +69 -27
- {orionis-0.205.0.dist-info → orionis-0.207.0.dist-info}/METADATA +1 -1
- {orionis-0.205.0.dist-info → orionis-0.207.0.dist-info}/RECORD +12 -10
- tests/support/inspection/fakes/fake_reflection_abstract.py +218 -0
- tests/support/inspection/test_reflection_abstract.py +229 -0
- tests/support/inspection/test_reflection_instance.py +26 -32
- {orionis-0.205.0.dist-info → orionis-0.207.0.dist-info}/LICENCE +0 -0
- {orionis-0.205.0.dist-info → orionis-0.207.0.dist-info}/WHEEL +0 -0
- {orionis-0.205.0.dist-info → orionis-0.207.0.dist-info}/entry_points.txt +0 -0
- {orionis-0.205.0.dist-info → orionis-0.207.0.dist-info}/top_level.txt +0 -0
- /tests/support/inspection/fakes/{fake_reflection.py → fake_reflection_instance.py} +0 -0
orionis/framework.py
CHANGED
@@ -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
|
-
|
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,10 @@ class ReflexionAbstract:
|
|
51
52
|
Set[str]
|
52
53
|
Set of abstract method names
|
53
54
|
"""
|
54
|
-
|
55
|
+
methods = []
|
56
|
+
for method in self._abstract.__abstractmethods__:
|
57
|
+
methods.append(method)
|
58
|
+
return set(methods)
|
55
59
|
|
56
60
|
def getConcreteMethods(self) -> Dict[str, Callable]:
|
57
61
|
"""Get all concrete methods implemented in the abstract class.
|
@@ -88,13 +92,32 @@ class ReflexionAbstract:
|
|
88
92
|
Returns
|
89
93
|
-------
|
90
94
|
List[str]
|
91
|
-
List of class method names
|
95
|
+
List of class method names, excluding private/protected methods (starting with '_')
|
96
|
+
|
97
|
+
Notes
|
98
|
+
-----
|
99
|
+
- Uses inspect.getattr_static to avoid method binding
|
100
|
+
- Properly handles both @classmethod decorator and classmethod instances
|
101
|
+
- Filters out private/protected methods (starting with '_')
|
102
|
+
|
103
|
+
Examples
|
104
|
+
--------
|
105
|
+
>>> class MyAbstract(ABC):
|
106
|
+
... @classmethod
|
107
|
+
... def factory(cls): pass
|
108
|
+
... @classmethod
|
109
|
+
... def _protected_factory(cls): pass
|
110
|
+
>>> reflex = ReflexionAbstract(MyAbstract)
|
111
|
+
>>> reflex.getClassMethods()
|
112
|
+
['factory']
|
92
113
|
"""
|
93
114
|
return [
|
94
|
-
name for name
|
95
|
-
|
96
|
-
|
97
|
-
|
115
|
+
name for name in dir(self._abstract)
|
116
|
+
if not name.startswith('_') and
|
117
|
+
isinstance(
|
118
|
+
inspect.getattr_static(self._abstract, name),
|
119
|
+
(classmethod, types.MethodType)
|
120
|
+
)
|
98
121
|
]
|
99
122
|
|
100
123
|
def getProperties(self) -> List[str]:
|
@@ -153,7 +176,7 @@ class ReflexionAbstract:
|
|
153
176
|
"""
|
154
177
|
return tuple(
|
155
178
|
base for base in self._abstract.__bases__
|
156
|
-
if inspect.isabstract(base)
|
179
|
+
if inspect.isabstract(base) or issubclass(base, abc.ABC) or isinstance(base, abc.ABCMeta)
|
157
180
|
)
|
158
181
|
|
159
182
|
def getInterfaceMethods(self) -> Dict[str, inspect.Signature]:
|
@@ -220,29 +243,48 @@ class ReflexionAbstract:
|
|
220
243
|
"""
|
221
244
|
return self._abstract.__annotations__
|
222
245
|
|
223
|
-
def getDecorators(self, method_name: str) -> List[
|
224
|
-
"""
|
246
|
+
def getDecorators(self, method_name: str) -> List[str]:
|
247
|
+
"""
|
248
|
+
Get decorators applied to a method.
|
225
249
|
|
226
250
|
Parameters
|
227
251
|
----------
|
228
252
|
method_name : str
|
229
|
-
Name of the method
|
230
|
-
|
231
|
-
Returns
|
232
|
-
-------
|
233
|
-
List[Callable]
|
234
|
-
List of decorator functions
|
253
|
+
Name of the method to inspect
|
235
254
|
"""
|
236
|
-
method = getattr(self._abstract, method_name)
|
237
|
-
|
238
|
-
|
239
|
-
if hasattr(method, '__wrapped__'):
|
240
|
-
# Unwrap decorated functions
|
241
|
-
while hasattr(method, '__wrapped__'):
|
242
|
-
decorators.append(method)
|
243
|
-
method = method.__wrapped__
|
255
|
+
method = getattr(self._abstract, method_name, None)
|
256
|
+
if method is None:
|
257
|
+
return []
|
244
258
|
|
245
|
-
|
259
|
+
try:
|
260
|
+
source = inspect.getsource(self._abstract)
|
261
|
+
except (OSError, TypeError):
|
262
|
+
return []
|
263
|
+
|
264
|
+
tree = ast.parse(source)
|
265
|
+
|
266
|
+
class DecoratorVisitor(ast.NodeVisitor):
|
267
|
+
def __init__(self):
|
268
|
+
self.decorators = []
|
269
|
+
|
270
|
+
def visit_FunctionDef(self, node):
|
271
|
+
if node.name == method_name:
|
272
|
+
for deco in node.decorator_list:
|
273
|
+
if isinstance(deco, ast.Name):
|
274
|
+
self.decorators.append(deco.id)
|
275
|
+
elif isinstance(deco, ast.Call):
|
276
|
+
# handles decorators with arguments like @deco(arg)
|
277
|
+
if isinstance(deco.func, ast.Name):
|
278
|
+
self.decorators.append(deco.func.id)
|
279
|
+
elif isinstance(deco, ast.Attribute):
|
280
|
+
self.decorators.append(deco.attr)
|
281
|
+
# No need to visit deeper
|
282
|
+
return
|
283
|
+
|
284
|
+
visitor = DecoratorVisitor()
|
285
|
+
visitor.visit(tree)
|
286
|
+
|
287
|
+
return visitor.decorators
|
246
288
|
|
247
289
|
def isProtocol(self) -> bool:
|
248
290
|
"""Check if the abstract class is a Protocol.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
orionis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
orionis/console.py,sha256=4gYWxf0fWYgJ4RKwARvnTPh06FL3GJ6SAZ7R2NzOICw,1342
|
3
|
-
orionis/framework.py,sha256=
|
3
|
+
orionis/framework.py,sha256=eb4WxXbyAXkX44A065Y_hEHg-PyA8LWfMluqcfrxYJA,1469
|
4
4
|
orionis/installer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
5
|
orionis/installer/manager.py,sha256=Li4TVziRXWfum02xNG4JHwbnLk-u8xzHjdqKz-D894k,2755
|
6
6
|
orionis/installer/output.py,sha256=7O9qa2xtXMB_4ZvVi-Klneom9YazwygAd_4uYAoxhbU,8548
|
@@ -171,7 +171,7 @@ orionis/luminate/support/inspection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQ
|
|
171
171
|
orionis/luminate/support/inspection/container_integrity.py,sha256=6d9FsGk-Rm1AXgqBS3Nww49dR7n1ptXTTNyGUuBHgNY,10111
|
172
172
|
orionis/luminate/support/inspection/functions.py,sha256=XVDLdygONcfDNlH7CZ6muNdtYHLgNp5RybqC3smL4Y4,6400
|
173
173
|
orionis/luminate/support/inspection/reflection.py,sha256=x_UHBY9pBSKgct13-u1WbhoONqLoGG60OpgoCsKE0AI,20368
|
174
|
-
orionis/luminate/support/inspection/reflexion_abstract.py,sha256=
|
174
|
+
orionis/luminate/support/inspection/reflexion_abstract.py,sha256=pKjLZFAfCHcve39FiIeAyAJiSxKhOWBkMsPub3Sa-RI,9313
|
175
175
|
orionis/luminate/support/inspection/reflexion_concrete.py,sha256=0WOlLeTWLwMeAUReoaJetqlnT1_TxW_jMnbk_yXRR0g,549
|
176
176
|
orionis/luminate/support/inspection/reflexion_concrete_with_abstract.py,sha256=ZuAFoSPkgbOFMIbVR0hvlkKsm1dIpY1_bsXxZxvXcmU,801
|
177
177
|
orionis/luminate/support/inspection/reflexion_instance.py,sha256=k6bpRYjLeTUDqquluYrDZUtBLpLuGe4wm7PMUM8Sz-E,9914
|
@@ -199,12 +199,14 @@ tests/example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
199
199
|
tests/example/test_example.py,sha256=MNYissCEa0mzx1YA2gTiqXRX8r2v_vfB_Ew0jBFmBag,556
|
200
200
|
tests/support/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
201
201
|
tests/support/inspection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
202
|
-
tests/support/inspection/
|
202
|
+
tests/support/inspection/test_reflection_abstract.py,sha256=ntrwbhYdZBWWCuHI0k_Vttd4jclhZ-wLwopb1XhAB_k,8750
|
203
|
+
tests/support/inspection/test_reflection_instance.py,sha256=4aBFeLgOmNvO5rbyd6EFioU4_DgXddV5pL3el23mFtA,6681
|
203
204
|
tests/support/inspection/fakes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
204
|
-
tests/support/inspection/fakes/
|
205
|
-
|
206
|
-
orionis-0.
|
207
|
-
orionis-0.
|
208
|
-
orionis-0.
|
209
|
-
orionis-0.
|
210
|
-
orionis-0.
|
205
|
+
tests/support/inspection/fakes/fake_reflection_abstract.py,sha256=7qtz44brfFzE4oNYi9kIsvdWP79nP2FnzSz-0bU__pg,5045
|
206
|
+
tests/support/inspection/fakes/fake_reflection_instance.py,sha256=G16rZdJWC3L8SGEQkmwktvw4n7IAusIIx9Tm-ZFLcg4,1419
|
207
|
+
orionis-0.207.0.dist-info/LICENCE,sha256=-_4cF2EBKuYVS_SQpy1uapq0oJPUU1vl_RUWSy2jJTo,1111
|
208
|
+
orionis-0.207.0.dist-info/METADATA,sha256=OTZC93qgIgplcgvUxPIBdQtjs_420Y0HUyWXCy4mshU,3003
|
209
|
+
orionis-0.207.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
210
|
+
orionis-0.207.0.dist-info/entry_points.txt,sha256=a_e0faeSqyUCVZd0MqljQ2oaHHdlsz6g9sU_bMqi5zQ,49
|
211
|
+
orionis-0.207.0.dist-info/top_level.txt,sha256=2bdoHgyGZhOtLAXS6Om8OCTmL24dUMC_L1quMe_ETbk,14
|
212
|
+
orionis-0.207.0.dist-info/RECORD,,
|
@@ -0,0 +1,218 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
from typing import Callable
|
3
|
+
from functools import wraps
|
4
|
+
|
5
|
+
def decorator_example(func: Callable) -> Callable:
|
6
|
+
"""Example decorator for testing purposes.
|
7
|
+
|
8
|
+
Parameters
|
9
|
+
----------
|
10
|
+
func : Callable
|
11
|
+
The function to be decorated
|
12
|
+
|
13
|
+
Returns
|
14
|
+
-------
|
15
|
+
Callable
|
16
|
+
The wrapped function
|
17
|
+
|
18
|
+
Notes
|
19
|
+
-----
|
20
|
+
This is a simple identity decorator used for testing decorator detection.
|
21
|
+
"""
|
22
|
+
@wraps(func)
|
23
|
+
def wrapper(*args, **kwargs):
|
24
|
+
return func(*args, **kwargs)
|
25
|
+
return wrapper
|
26
|
+
|
27
|
+
|
28
|
+
def another_decorator(func: Callable) -> Callable:
|
29
|
+
"""Another example decorator for testing multiple decorators.
|
30
|
+
|
31
|
+
Parameters
|
32
|
+
----------
|
33
|
+
func : Callable
|
34
|
+
The function to be decorated
|
35
|
+
|
36
|
+
Returns
|
37
|
+
-------
|
38
|
+
Callable
|
39
|
+
The wrapped function with added prefix
|
40
|
+
|
41
|
+
Examples
|
42
|
+
--------
|
43
|
+
>>> @another_decorator
|
44
|
+
... def test(): return "hello"
|
45
|
+
>>> test()
|
46
|
+
'Decorated: hello'
|
47
|
+
"""
|
48
|
+
@wraps(func)
|
49
|
+
def wrapper(*args, **kwargs):
|
50
|
+
return f"Decorated: {func(*args, **kwargs)}"
|
51
|
+
return wrapper
|
52
|
+
|
53
|
+
|
54
|
+
class FakeAbstractClass(ABC):
|
55
|
+
"""A fake abstract class for testing reflection capabilities.
|
56
|
+
|
57
|
+
This class contains all elements needed to test ReflexionAbstract functionality:
|
58
|
+
- Abstract methods
|
59
|
+
- Concrete methods
|
60
|
+
- Static methods
|
61
|
+
- Class methods
|
62
|
+
- Properties
|
63
|
+
- Decorated methods
|
64
|
+
- Type annotations
|
65
|
+
- Protected/private methods
|
66
|
+
|
67
|
+
Attributes
|
68
|
+
----------
|
69
|
+
class_attr : str
|
70
|
+
A class-level attribute with type annotation
|
71
|
+
_value : float
|
72
|
+
Protected attribute used by computed_property setter
|
73
|
+
"""
|
74
|
+
|
75
|
+
class_attr: str = "class_value"
|
76
|
+
|
77
|
+
@abstractmethod
|
78
|
+
def abstract_method(self, x: int, y: int) -> int:
|
79
|
+
"""Required abstract method.
|
80
|
+
|
81
|
+
Parameters
|
82
|
+
----------
|
83
|
+
x : int
|
84
|
+
First integer parameter
|
85
|
+
y : int
|
86
|
+
Second integer parameter
|
87
|
+
|
88
|
+
Returns
|
89
|
+
-------
|
90
|
+
int
|
91
|
+
The result of some operation
|
92
|
+
|
93
|
+
Notes
|
94
|
+
-----
|
95
|
+
This method must be implemented by concrete subclasses.
|
96
|
+
"""
|
97
|
+
pass
|
98
|
+
|
99
|
+
@abstractmethod
|
100
|
+
def another_abstract(self, text: str) -> str:
|
101
|
+
"""Another required abstract method.
|
102
|
+
|
103
|
+
Parameters
|
104
|
+
----------
|
105
|
+
text : str
|
106
|
+
Input string to process
|
107
|
+
|
108
|
+
Returns
|
109
|
+
-------
|
110
|
+
str
|
111
|
+
Processed string result
|
112
|
+
"""
|
113
|
+
pass
|
114
|
+
|
115
|
+
def concrete_method(self, value: float) -> str:
|
116
|
+
"""Concrete implemented method.
|
117
|
+
|
118
|
+
Parameters
|
119
|
+
----------
|
120
|
+
value : float
|
121
|
+
Numeric value to format
|
122
|
+
|
123
|
+
Returns
|
124
|
+
-------
|
125
|
+
str
|
126
|
+
Formatted string representation
|
127
|
+
"""
|
128
|
+
return f"Value: {value}"
|
129
|
+
|
130
|
+
@staticmethod
|
131
|
+
def static_helper(flag: bool) -> str:
|
132
|
+
"""Static helper method.
|
133
|
+
|
134
|
+
Parameters
|
135
|
+
----------
|
136
|
+
flag : bool
|
137
|
+
Boolean flag to determine output
|
138
|
+
|
139
|
+
Returns
|
140
|
+
-------
|
141
|
+
str
|
142
|
+
"Enabled" if flag is True, "Disabled" otherwise
|
143
|
+
"""
|
144
|
+
return "Enabled" if flag else "Disabled"
|
145
|
+
|
146
|
+
@classmethod
|
147
|
+
def create_instance(cls) -> 'FakeAbstractClass':
|
148
|
+
"""Class method factory.
|
149
|
+
|
150
|
+
Returns
|
151
|
+
-------
|
152
|
+
FakeAbstractClass
|
153
|
+
New instance of the class
|
154
|
+
|
155
|
+
Notes
|
156
|
+
-----
|
157
|
+
This cannot actually instantiate the abstract class, but serves
|
158
|
+
as an example of a class method.
|
159
|
+
"""
|
160
|
+
return cls()
|
161
|
+
|
162
|
+
@property
|
163
|
+
def computed_property(self) -> float:
|
164
|
+
"""Computed property example.
|
165
|
+
|
166
|
+
Returns
|
167
|
+
-------
|
168
|
+
float
|
169
|
+
The value of pi approximation
|
170
|
+
"""
|
171
|
+
return 3.1416
|
172
|
+
|
173
|
+
@computed_property.setter
|
174
|
+
def computed_property(self, value: float):
|
175
|
+
"""Setter for computed property.
|
176
|
+
|
177
|
+
Parameters
|
178
|
+
----------
|
179
|
+
value : float
|
180
|
+
New value to set
|
181
|
+
"""
|
182
|
+
self._value = value
|
183
|
+
|
184
|
+
@decorator_example
|
185
|
+
@another_decorator
|
186
|
+
def decorated_method(self) -> str:
|
187
|
+
"""Method with multiple decorators.
|
188
|
+
|
189
|
+
Returns
|
190
|
+
-------
|
191
|
+
str
|
192
|
+
Always returns "decorated" with decorator transformations
|
193
|
+
|
194
|
+
Notes
|
195
|
+
-----
|
196
|
+
Used to test decorator inspection functionality.
|
197
|
+
"""
|
198
|
+
return "decorated"
|
199
|
+
|
200
|
+
def _protected_method(self) -> str:
|
201
|
+
"""Protected method (should be filtered in results).
|
202
|
+
|
203
|
+
Returns
|
204
|
+
-------
|
205
|
+
str
|
206
|
+
Constant string "protected"
|
207
|
+
"""
|
208
|
+
return "protected"
|
209
|
+
|
210
|
+
def __private_method(self) -> str:
|
211
|
+
"""Private method (should be filtered in results).
|
212
|
+
|
213
|
+
Returns
|
214
|
+
-------
|
215
|
+
str
|
216
|
+
Constant string "private"
|
217
|
+
"""
|
218
|
+
return "private"
|
@@ -0,0 +1,229 @@
|
|
1
|
+
from abc import ABC
|
2
|
+
import unittest
|
3
|
+
from orionis.luminate.support.inspection.reflection import Reflection
|
4
|
+
from orionis.luminate.test.test_output import PrinterInTest
|
5
|
+
from tests.support.inspection.fakes.fake_reflection_abstract import FakeAbstractClass
|
6
|
+
|
7
|
+
class TestReflexionAbstract(unittest.TestCase, PrinterInTest):
|
8
|
+
"""Test cases for ReflexionAbstract using FakeAbstractClass.
|
9
|
+
|
10
|
+
This test suite verifies all functionality of the ReflexionAbstract class
|
11
|
+
using FakeAbstractClass as the test subject.
|
12
|
+
"""
|
13
|
+
|
14
|
+
def testReflectionAbstractExceptionValueError(self):
|
15
|
+
"""Class setup method.
|
16
|
+
|
17
|
+
Initializes the ReflexionAbstract instance with FakeAbstractClass
|
18
|
+
before any tests run.
|
19
|
+
"""
|
20
|
+
with self.assertRaises(ValueError):
|
21
|
+
Reflection.abstract(str)
|
22
|
+
|
23
|
+
def testReflectionAbstractGetClassName(self):
|
24
|
+
"""Test getClassName() method.
|
25
|
+
|
26
|
+
Verifies that:
|
27
|
+
- The returned class name matches exactly
|
28
|
+
- The return type is str
|
29
|
+
"""
|
30
|
+
class_name = Reflection.abstract(FakeAbstractClass).getClassName()
|
31
|
+
self.assertEqual(class_name, "FakeAbstractClass")
|
32
|
+
self.assertIsInstance(class_name, str)
|
33
|
+
|
34
|
+
def testReflectionAbstractGetModuleName(self):
|
35
|
+
"""Test getModuleName() method.
|
36
|
+
|
37
|
+
Verifies that:
|
38
|
+
- The module name is returned
|
39
|
+
- The name is a string
|
40
|
+
"""
|
41
|
+
module_name = Reflection.abstract(FakeAbstractClass).getModuleName()
|
42
|
+
self.assertTrue(module_name == 'tests.support.inspection.fakes.fake_reflection_abstract')
|
43
|
+
self.assertIsInstance(module_name, str)
|
44
|
+
|
45
|
+
def testReflectionAbstractGetAbstractMethods(self):
|
46
|
+
"""Test getAbstractMethods() method.
|
47
|
+
|
48
|
+
Verifies that:
|
49
|
+
- All abstract methods are detected
|
50
|
+
- No concrete methods are included
|
51
|
+
- Return type is correct
|
52
|
+
"""
|
53
|
+
methods = Reflection.abstract(FakeAbstractClass).getAbstractMethods()
|
54
|
+
expected = {'abstract_method', 'another_abstract'}
|
55
|
+
self.assertEqual(methods, expected)
|
56
|
+
self.assertIsInstance(methods, set)
|
57
|
+
|
58
|
+
def testReflectionAbstractGetConcreteMethods(self):
|
59
|
+
"""Test getConcreteMethods() method.
|
60
|
+
|
61
|
+
Verifies that:
|
62
|
+
- Concrete methods are detected
|
63
|
+
- Abstract methods are excluded
|
64
|
+
- Protected/private methods are excluded
|
65
|
+
"""
|
66
|
+
methods = Reflection.abstract(FakeAbstractClass).getConcreteMethods()
|
67
|
+
self.assertIn('static_helper', methods)
|
68
|
+
self.assertIn('concrete_method', methods)
|
69
|
+
self.assertIn('decorated_method', methods)
|
70
|
+
self.assertNotIn('abstract_method', methods)
|
71
|
+
self.assertNotIn('_protected_method', methods)
|
72
|
+
self.assertNotIn('__private_method', methods)
|
73
|
+
|
74
|
+
def testReflectionAbstractGetStaticMethods(self):
|
75
|
+
"""Test getStaticMethods() method.
|
76
|
+
|
77
|
+
Verifies that:
|
78
|
+
- Static methods are detected
|
79
|
+
- Only static methods are included
|
80
|
+
- Protected/private methods are excluded
|
81
|
+
"""
|
82
|
+
static_methods = Reflection.abstract(FakeAbstractClass).getStaticMethods()
|
83
|
+
self.assertIn('static_helper', static_methods)
|
84
|
+
self.assertEqual(len(static_methods), 1)
|
85
|
+
self.assertNotIn('create_instance', static_methods)
|
86
|
+
|
87
|
+
def testReflectionAbstractGetClassMethods(self):
|
88
|
+
"""Test getClassMethods() method.
|
89
|
+
|
90
|
+
Verifies that:
|
91
|
+
- Class methods are detected
|
92
|
+
- Only class methods are included
|
93
|
+
- Protected/private methods are excluded
|
94
|
+
"""
|
95
|
+
class_methods = Reflection.abstract(FakeAbstractClass).getClassMethods()
|
96
|
+
self.assertIn('create_instance', class_methods)
|
97
|
+
self.assertEqual(len(class_methods), 1)
|
98
|
+
self.assertNotIn('static_helper', class_methods)
|
99
|
+
|
100
|
+
def testReflectionAbstractGetProperties(self):
|
101
|
+
"""Test getProperties() method.
|
102
|
+
|
103
|
+
Verifies that:
|
104
|
+
- Properties are detected
|
105
|
+
- Only properties are included
|
106
|
+
- Protected/private properties are excluded
|
107
|
+
"""
|
108
|
+
props = Reflection.abstract(FakeAbstractClass).getProperties()
|
109
|
+
self.assertIn('computed_property', props)
|
110
|
+
self.assertEqual(len(props), 1)
|
111
|
+
|
112
|
+
def testReflectionAbstractGetMethodSignature(self):
|
113
|
+
"""Test getMethodSignature() method.
|
114
|
+
|
115
|
+
Verifies that:
|
116
|
+
- Correct signature is returned
|
117
|
+
- Parameters are properly detected
|
118
|
+
- Return type is properly detected
|
119
|
+
"""
|
120
|
+
sig = Reflection.abstract(FakeAbstractClass).getMethodSignature('abstract_method')
|
121
|
+
params = list(sig.parameters.keys())
|
122
|
+
self.assertEqual(params, ['self', 'x', 'y'])
|
123
|
+
self.assertEqual(sig.return_annotation, int)
|
124
|
+
|
125
|
+
def testReflectionAbstractGetDocstring(self):
|
126
|
+
"""Test getDocstring() method.
|
127
|
+
|
128
|
+
Verifies that:
|
129
|
+
- Docstring is returned
|
130
|
+
- Docstring contains expected content
|
131
|
+
"""
|
132
|
+
doc = Reflection.abstract(FakeAbstractClass).getDocstring()
|
133
|
+
self.assertTrue(doc.startswith("A fake abstract class"))
|
134
|
+
self.assertIsInstance(doc, str)
|
135
|
+
|
136
|
+
def testReflectionAbstractGetBaseAbstractClasses(self):
|
137
|
+
"""Test getBaseAbstractClasses() method.
|
138
|
+
|
139
|
+
Verifies that:
|
140
|
+
- Base abstract classes are detected
|
141
|
+
- Only abstract bases are included
|
142
|
+
"""
|
143
|
+
bases = Reflection.abstract(FakeAbstractClass).getBaseAbstractClasses()
|
144
|
+
self.assertEqual(bases, (ABC,))
|
145
|
+
|
146
|
+
def testReflectionAbstractGetInterfaceMethods(self):
|
147
|
+
"""Test getInterfaceMethods() method.
|
148
|
+
|
149
|
+
Verifies that:
|
150
|
+
- Interface methods are detected
|
151
|
+
- Signatures are correct
|
152
|
+
- Only abstract methods are included
|
153
|
+
"""
|
154
|
+
interface = Reflection.abstract(FakeAbstractClass).getInterfaceMethods()
|
155
|
+
self.assertEqual(len(interface), 2)
|
156
|
+
self.assertIn('abstract_method', interface)
|
157
|
+
sig = interface['abstract_method']
|
158
|
+
self.assertEqual(list(sig.parameters.keys()), ['self', 'x', 'y'])
|
159
|
+
|
160
|
+
def testReflectionAbstractIsSubclassOf(self):
|
161
|
+
"""Test isSubclassOf() method.
|
162
|
+
|
163
|
+
Verifies that:
|
164
|
+
- Correctly identifies abstract base classes
|
165
|
+
- Returns False for non-parent classes
|
166
|
+
"""
|
167
|
+
self.assertTrue(Reflection.abstract(FakeAbstractClass).isSubclassOf(ABC))
|
168
|
+
self.assertTrue(Reflection.abstract(FakeAbstractClass).isSubclassOf(object))
|
169
|
+
|
170
|
+
def testReflectionAbstractGetSourceCode(self):
|
171
|
+
"""Test getSourceCode() method.
|
172
|
+
|
173
|
+
Verifies that:
|
174
|
+
- Source code is returned
|
175
|
+
- Contains class definition
|
176
|
+
"""
|
177
|
+
source = Reflection.abstract(FakeAbstractClass).getSourceCode()
|
178
|
+
self.assertIsNotNone(source)
|
179
|
+
self.assertIn("class FakeAbstractClass(ABC):", source)
|
180
|
+
|
181
|
+
def testReflectionAbstractGetFileLocation(self):
|
182
|
+
"""Test getFileLocation() method.
|
183
|
+
|
184
|
+
Verifies that:
|
185
|
+
- File location is returned
|
186
|
+
- Path ends with .py extension
|
187
|
+
"""
|
188
|
+
location = Reflection.abstract(FakeAbstractClass).getFileLocation()
|
189
|
+
self.assertIsNotNone(location)
|
190
|
+
self.assertTrue('fake_reflection_abstract.py' in location)
|
191
|
+
|
192
|
+
def testReflectionAbstractGetAnnotations(self):
|
193
|
+
"""Test getAnnotations() method.
|
194
|
+
|
195
|
+
Verifies that:
|
196
|
+
- Annotations are detected
|
197
|
+
- Class attributes are included
|
198
|
+
"""
|
199
|
+
annotations = Reflection.abstract(FakeAbstractClass).getAnnotations()
|
200
|
+
self.assertIn('class_attr', annotations)
|
201
|
+
self.assertEqual(annotations['class_attr'], str)
|
202
|
+
|
203
|
+
def testReflectionAbstractGetDecorators(self):
|
204
|
+
"""Test getDecorators() method.
|
205
|
+
|
206
|
+
Verifies that:
|
207
|
+
- Decorators are detected
|
208
|
+
- Correct number of decorators is returned
|
209
|
+
- Decorator order is preserved
|
210
|
+
"""
|
211
|
+
decorators = Reflection.abstract(FakeAbstractClass).getDecorators('decorated_method')
|
212
|
+
for decorator in decorators:
|
213
|
+
self.assertTrue(decorator in ['decorator_example', 'another_decorator'])
|
214
|
+
|
215
|
+
def testReflectionAbstractIsProtocol(self):
|
216
|
+
"""Test isProtocol() method.
|
217
|
+
|
218
|
+
Verifies that:
|
219
|
+
- Correctly identifies non-Protocol classes
|
220
|
+
"""
|
221
|
+
self.assertFalse(Reflection.abstract(FakeAbstractClass).isProtocol())
|
222
|
+
|
223
|
+
def testReflectionAbstractGetRequiredAttributes(self):
|
224
|
+
"""Test getRequiredAttributes() method.
|
225
|
+
|
226
|
+
Verifies that:
|
227
|
+
- Returns empty set for non-Protocol classes
|
228
|
+
"""
|
229
|
+
self.assertEqual(Reflection.abstract(FakeAbstractClass).getRequiredAttributes(), set())
|
@@ -2,40 +2,39 @@ import unittest
|
|
2
2
|
from orionis.luminate.support.inspection.reflection import Reflection
|
3
3
|
from orionis.luminate.support.inspection.reflexion_instance import ReflexionInstance
|
4
4
|
from orionis.luminate.test.test_output import PrinterInTest
|
5
|
-
from tests.support.inspection.fakes.
|
5
|
+
from tests.support.inspection.fakes.fake_reflection_instance import BaseFakeClass, FakeClass
|
6
6
|
|
7
7
|
class TestReflection(unittest.TestCase, PrinterInTest):
|
8
8
|
"""
|
9
9
|
Unit tests for the Reflection class.
|
10
|
-
This class tests the functionality of the Reflection class, ensuring that it correctly handles
|
11
10
|
"""
|
12
11
|
|
13
12
|
def testReflectionInstanceExceptionValueError(self):
|
14
|
-
"""
|
13
|
+
"""Ensure Reflection.instance raises ValueError for invalid types."""
|
15
14
|
with self.assertRaises(ValueError):
|
16
15
|
Reflection.instance(str)
|
17
16
|
|
18
17
|
def testReflectionInstance(self):
|
19
|
-
"""
|
18
|
+
"""Verify Reflection.instance returns an instance of ReflexionInstance."""
|
20
19
|
self.assertIsInstance(Reflection.instance(FakeClass()), ReflexionInstance)
|
21
20
|
|
22
21
|
def testReflectionInstanceGetClassName(self):
|
23
|
-
"""
|
22
|
+
"""Check that getClassName returns the correct class name."""
|
24
23
|
reflex = Reflection.instance(FakeClass())
|
25
24
|
self.assertEqual(reflex.getClassName(), "FakeClass")
|
26
25
|
|
27
26
|
def testReflectionInstanceGetClass(self):
|
28
|
-
"""
|
27
|
+
"""Ensure getClass returns the correct class."""
|
29
28
|
reflex = Reflection.instance(FakeClass())
|
30
29
|
self.assertEqual(reflex.getClass(), FakeClass)
|
31
30
|
|
32
31
|
def testReflectionInstanceGetModuleName(self):
|
33
|
-
"""
|
32
|
+
"""Verify getModuleName returns the correct module name."""
|
34
33
|
reflex = Reflection.instance(FakeClass())
|
35
|
-
self.assertEqual(reflex.getModuleName(), "tests.support.inspection.fakes.
|
34
|
+
self.assertEqual(reflex.getModuleName(), "tests.support.inspection.fakes.fake_reflection_instance")
|
36
35
|
|
37
36
|
def testReflectionInstanceGetAttributes(self):
|
38
|
-
"""
|
37
|
+
"""Check that getAttributes returns all attributes of the class."""
|
39
38
|
reflex = Reflection.instance(FakeClass())
|
40
39
|
attributes = reflex.getAttributes()
|
41
40
|
self.assertTrue("public_attr" in attributes)
|
@@ -43,85 +42,85 @@ class TestReflection(unittest.TestCase, PrinterInTest):
|
|
43
42
|
self.assertTrue("dynamic_attr" in attributes)
|
44
43
|
|
45
44
|
def testReflectionInstanceGetMethods(self):
|
46
|
-
"""
|
45
|
+
"""Ensure getMethods returns all methods of the class."""
|
47
46
|
reflex = Reflection.instance(FakeClass())
|
48
47
|
methods = reflex.getMethods()
|
49
48
|
self.assertTrue("instance_method" in methods)
|
50
49
|
self.assertTrue("class_method" in methods)
|
51
50
|
|
52
51
|
def testReflectionInstanceGetStaticMethods(self):
|
53
|
-
"""
|
52
|
+
"""Verify getStaticMethods returns all static methods of the class."""
|
54
53
|
reflex = Reflection.instance(FakeClass())
|
55
54
|
methods = reflex.getStaticMethods()
|
56
55
|
self.assertTrue("static_method" in methods)
|
57
56
|
|
58
57
|
def testReflectionInstanceGetPropertyNames(self):
|
59
|
-
"""
|
58
|
+
"""Check that getPropertyNames returns all property names."""
|
60
59
|
reflex = Reflection.instance(FakeClass())
|
61
60
|
properties = reflex.getPropertyNames()
|
62
61
|
self.assertTrue("computed_property" in properties)
|
63
62
|
|
64
63
|
def testReflectionInstanceCallMethod(self):
|
65
|
-
"""
|
64
|
+
"""Ensure callMethod correctly invokes a method with arguments."""
|
66
65
|
reflex = Reflection.instance(FakeClass())
|
67
66
|
result = reflex.callMethod("instance_method", 1, 2)
|
68
67
|
self.assertEqual(result, 3)
|
69
68
|
|
70
69
|
def testReflectionInstanceGetMethodSignature(self):
|
71
|
-
"""
|
70
|
+
"""Verify getMethodSignature returns the correct method signature."""
|
72
71
|
reflex = Reflection.instance(FakeClass())
|
73
72
|
signature = reflex.getMethodSignature("instance_method")
|
74
73
|
self.assertEqual(str(signature), "(x: int, y: int) -> int")
|
75
74
|
|
76
75
|
def testReflectionInstanceGetDocstring(self):
|
77
|
-
"""
|
76
|
+
"""Check that getDocstring returns the correct class docstring."""
|
78
77
|
reflex = Reflection.instance(FakeClass())
|
79
78
|
docstring = reflex.getDocstring()
|
80
79
|
self.assertIn("This is a test class for ReflexionInstance", docstring)
|
81
80
|
|
82
81
|
def testReflectionInstanceGetBaseClasses(self):
|
83
|
-
"""
|
82
|
+
"""Ensure getBaseClasses returns the correct base classes."""
|
84
83
|
reflex = Reflection.instance(FakeClass())
|
85
84
|
base_classes = reflex.getBaseClasses()
|
86
85
|
self.assertIn(BaseFakeClass, base_classes)
|
87
86
|
|
88
87
|
def testReflectionInstanceIsInstanceOf(self):
|
89
|
-
"""
|
88
|
+
"""Verify isInstanceOf checks inheritance correctly."""
|
90
89
|
reflex = Reflection.instance(FakeClass())
|
91
90
|
self.assertTrue(reflex.isInstanceOf(BaseFakeClass))
|
92
91
|
|
93
92
|
def testReflectionInstanceGetSourceCode(self):
|
94
|
-
"""
|
93
|
+
"""Check that getSourceCode returns the class source code."""
|
95
94
|
reflex = Reflection.instance(FakeClass())
|
96
95
|
source_code = reflex.getSourceCode()
|
97
96
|
self.assertIn("class FakeClass(BaseFakeClass):", source_code)
|
98
97
|
|
99
98
|
def testReflectionInstanceGetFileLocation(self):
|
100
|
-
"""
|
99
|
+
"""Ensure getFileLocation returns the correct file path."""
|
101
100
|
reflex = Reflection.instance(FakeClass())
|
102
101
|
file_location = reflex.getFileLocation()
|
103
|
-
self.assertIn("
|
102
|
+
self.assertIn("fake_reflection_instance.py", file_location)
|
104
103
|
|
105
104
|
def testReflectionInstanceGetAnnotations(self):
|
106
|
-
"""
|
105
|
+
"""Verify getAnnotations returns the correct class annotations."""
|
107
106
|
reflex = Reflection.instance(FakeClass())
|
108
107
|
annotations = reflex.getAnnotations()
|
109
108
|
self.assertEqual("{'class_attr': <class 'str'>}", str(annotations))
|
110
109
|
|
111
110
|
def testReflectionInstanceHasAttribute(self):
|
112
|
-
"""
|
111
|
+
"""Check that hasAttribute correctly identifies attributes."""
|
113
112
|
reflex = Reflection.instance(FakeClass())
|
114
113
|
self.assertTrue(reflex.hasAttribute("public_attr"))
|
115
114
|
self.assertFalse(reflex.hasAttribute("non_existent_attr"))
|
116
115
|
|
117
116
|
def testReflectionInstanceGetAttribute(self):
|
118
|
-
"""
|
117
|
+
"""Ensure getAttribute retrieves the correct attribute value."""
|
119
118
|
reflex = Reflection.instance(FakeClass())
|
120
119
|
attr_value = reflex.getAttribute("public_attr")
|
121
120
|
self.assertEqual(attr_value, 42)
|
122
121
|
|
123
122
|
def testReflectionInstanceGetCallableMembers(self):
|
124
|
-
"""
|
123
|
+
"""Verify getCallableMembers returns all callable members."""
|
125
124
|
reflex = Reflection.instance(FakeClass())
|
126
125
|
callable_members = reflex.getCallableMembers()
|
127
126
|
self.assertIn("instance_method", callable_members)
|
@@ -129,19 +128,14 @@ class TestReflection(unittest.TestCase, PrinterInTest):
|
|
129
128
|
self.assertIn("static_method", callable_members)
|
130
129
|
|
131
130
|
def testReflectionInstanceSetAttribute(self):
|
132
|
-
"""
|
133
|
-
|
134
|
-
# Create a new macro function
|
135
|
-
def myMacro(cls:FakeClass, num):
|
131
|
+
"""Check that setAttribute correctly sets a new attribute."""
|
132
|
+
def myMacro(cls: FakeClass, num):
|
136
133
|
return cls.instance_method(10, 12) + num
|
137
134
|
|
138
|
-
# Create an instance of FakeClass and set the macro as an attribute
|
139
135
|
reflex = Reflection.instance(FakeClass())
|
140
136
|
reflex.setAttribute("myMacro", myMacro)
|
141
137
|
|
142
|
-
# Check if the macro was set correctly
|
143
138
|
self.assertTrue(reflex.hasAttribute("myMacro"))
|
144
139
|
|
145
|
-
# Call the macro method and check the result
|
146
140
|
result = reflex.callMethod("myMacro", reflex._instance, 3)
|
147
|
-
self.assertEqual(result, 25)
|
141
|
+
self.assertEqual(result, 25)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|