orionis 0.200.0__py3-none-any.whl → 0.202.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/container/container_integrity.py +56 -1
- orionis/luminate/facades/tests/tests_facade.py +1 -1
- orionis/luminate/support/inspection/container_integrity.py +292 -0
- orionis/luminate/support/inspection/functions.py +235 -0
- orionis/luminate/support/inspection/reflection.py +649 -0
- orionis/luminate/support/inspection/reflexion_abstract.py +23 -0
- orionis/luminate/support/inspection/reflexion_concrete.py +24 -0
- orionis/luminate/support/inspection/reflexion_concrete_with_abstract.py +31 -0
- orionis/luminate/support/inspection/reflexion_instance.py +364 -0
- orionis/luminate/support/inspection/reflexion_instance_with_abstract.py +309 -0
- orionis/luminate/support/inspection/reflexion_module.py +19 -0
- orionis/luminate/support/inspection/reflexion_module_with_classname.py +22 -0
- orionis/luminate/test/{exception.py → test_exception.py} +1 -2
- orionis/luminate/test/test_result.py +30 -0
- orionis/luminate/test/test_status.py +22 -0
- orionis/luminate/test/tests.py +67 -0
- orionis/luminate/test/unit_test.py +276 -56
- {orionis-0.200.0.dist-info → orionis-0.202.0.dist-info}/METADATA +1 -1
- {orionis-0.200.0.dist-info → orionis-0.202.0.dist-info}/RECORD +26 -14
- tests/main.py +0 -0
- tests/tools/class_example.py +0 -50
- tests/tools/test_reflection.py +0 -128
- {tests/tools → orionis/luminate/support/inspection}/__init__.py +0 -0
- {orionis-0.200.0.dist-info → orionis-0.202.0.dist-info}/LICENCE +0 -0
- {orionis-0.200.0.dist-info → orionis-0.202.0.dist-info}/WHEEL +0 -0
- {orionis-0.200.0.dist-info → orionis-0.202.0.dist-info}/entry_points.txt +0 -0
- {orionis-0.200.0.dist-info → orionis-0.202.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
from typing import Type, TypeVar
|
2
|
+
import abc
|
3
|
+
|
4
|
+
T = TypeVar('T')
|
5
|
+
ABC = TypeVar('ABC', bound=abc.ABC)
|
6
|
+
|
7
|
+
|
8
|
+
class ReflexionConcreteWithAbstract:
|
9
|
+
"""A reflection object encapsulating a concrete class and its abstract parent.
|
10
|
+
|
11
|
+
Parameters
|
12
|
+
----------
|
13
|
+
concrete : Type[T]
|
14
|
+
The concrete class being reflected upon
|
15
|
+
abstract : Type[ABC]
|
16
|
+
The abstract parent class
|
17
|
+
|
18
|
+
Attributes
|
19
|
+
----------
|
20
|
+
_concrete : Type[T]
|
21
|
+
The encapsulated concrete class
|
22
|
+
_abstract : Type[ABC]
|
23
|
+
The encapsulated abstract parent class
|
24
|
+
"""
|
25
|
+
|
26
|
+
def __init__(self, concrete: Type[T], abstract: Type[ABC]) -> None:
|
27
|
+
"""Initialize with the concrete class and abstract parent."""
|
28
|
+
self._concrete = concrete
|
29
|
+
self._abstract = abstract
|
30
|
+
|
31
|
+
|
@@ -0,0 +1,364 @@
|
|
1
|
+
from typing import Any, Type, Dict, List, Tuple, Callable, Optional
|
2
|
+
import inspect
|
3
|
+
|
4
|
+
class ReflexionInstance:
|
5
|
+
"""A reflection object encapsulating a class instance.
|
6
|
+
|
7
|
+
Parameters
|
8
|
+
----------
|
9
|
+
instance : Any
|
10
|
+
The instance being reflected upon
|
11
|
+
|
12
|
+
Attributes
|
13
|
+
----------
|
14
|
+
_instance : Any
|
15
|
+
The encapsulated instance
|
16
|
+
"""
|
17
|
+
|
18
|
+
def __init__(self, instance: Any) -> None:
|
19
|
+
"""Initialize with the instance to reflect upon."""
|
20
|
+
self._instance = instance
|
21
|
+
|
22
|
+
def getClassName(self) -> str:
|
23
|
+
"""Get the name of the instance's class.
|
24
|
+
|
25
|
+
Returns
|
26
|
+
-------
|
27
|
+
str
|
28
|
+
The name of the class
|
29
|
+
|
30
|
+
Examples
|
31
|
+
--------
|
32
|
+
>>> obj = SomeClass()
|
33
|
+
>>> reflex = ReflexionInstance(obj)
|
34
|
+
>>> reflex.getClassName()
|
35
|
+
'SomeClass'
|
36
|
+
"""
|
37
|
+
return self._instance.__class__.__name__
|
38
|
+
|
39
|
+
def getClass(self) -> Type:
|
40
|
+
"""Get the class of the instance.
|
41
|
+
|
42
|
+
Returns
|
43
|
+
-------
|
44
|
+
Type
|
45
|
+
The class object of the instance
|
46
|
+
|
47
|
+
Examples
|
48
|
+
--------
|
49
|
+
>>> reflex.getClass() is SomeClass
|
50
|
+
True
|
51
|
+
"""
|
52
|
+
return self._instance.__class__
|
53
|
+
|
54
|
+
def getModuleName(self) -> str:
|
55
|
+
"""Get the name of the module where the class is defined.
|
56
|
+
|
57
|
+
Returns
|
58
|
+
-------
|
59
|
+
str
|
60
|
+
The module name
|
61
|
+
|
62
|
+
Examples
|
63
|
+
--------
|
64
|
+
>>> reflex.getModuleName()
|
65
|
+
'some_module'
|
66
|
+
"""
|
67
|
+
return self._instance.__class__.__module__
|
68
|
+
|
69
|
+
def getAttributes(self) -> Dict[str, Any]:
|
70
|
+
"""Get all attributes of the instance.
|
71
|
+
|
72
|
+
Returns
|
73
|
+
-------
|
74
|
+
Dict[str, Any]
|
75
|
+
Dictionary of attribute names and their values
|
76
|
+
|
77
|
+
Examples
|
78
|
+
--------
|
79
|
+
>>> reflex.getAttributes()
|
80
|
+
{'attr1': value1, 'attr2': value2}
|
81
|
+
"""
|
82
|
+
return vars(self._instance)
|
83
|
+
|
84
|
+
def getMethods(self) -> List[str]:
|
85
|
+
"""Get all method names of the instance.
|
86
|
+
|
87
|
+
Returns
|
88
|
+
-------
|
89
|
+
List[str]
|
90
|
+
List of method names
|
91
|
+
|
92
|
+
Examples
|
93
|
+
--------
|
94
|
+
>>> reflex.getMethods()
|
95
|
+
['method1', 'method2']
|
96
|
+
"""
|
97
|
+
return [name for name, _ in inspect.getmembers(
|
98
|
+
self._instance,
|
99
|
+
predicate=inspect.ismethod
|
100
|
+
)]
|
101
|
+
|
102
|
+
def getPropertyNames(self) -> List[str]:
|
103
|
+
"""Get all property names of the instance.
|
104
|
+
|
105
|
+
Returns
|
106
|
+
-------
|
107
|
+
List[str]
|
108
|
+
List of property names
|
109
|
+
|
110
|
+
Examples
|
111
|
+
--------
|
112
|
+
>>> reflex.getPropertyNames()
|
113
|
+
['prop1', 'prop2']
|
114
|
+
"""
|
115
|
+
return [name for name, _ in inspect.getmembers(
|
116
|
+
self._instance.__class__,
|
117
|
+
lambda x: isinstance(x, property)
|
118
|
+
)]
|
119
|
+
|
120
|
+
def callMethod(self, methodName: str, *args: Any, **kwargs: Any) -> Any:
|
121
|
+
"""Call a method on the instance.
|
122
|
+
|
123
|
+
Parameters
|
124
|
+
----------
|
125
|
+
methodName : str
|
126
|
+
Name of the method to call
|
127
|
+
*args : Any
|
128
|
+
Positional arguments for the method
|
129
|
+
**kwargs : Any
|
130
|
+
Keyword arguments for the method
|
131
|
+
|
132
|
+
Returns
|
133
|
+
-------
|
134
|
+
Any
|
135
|
+
The return value of the method
|
136
|
+
|
137
|
+
Raises
|
138
|
+
------
|
139
|
+
AttributeError
|
140
|
+
If the method doesn't exist
|
141
|
+
|
142
|
+
Examples
|
143
|
+
--------
|
144
|
+
>>> reflex.callMethod('calculate', 2, 3)
|
145
|
+
5
|
146
|
+
"""
|
147
|
+
method = getattr(self._instance, methodName)
|
148
|
+
return method(*args, **kwargs)
|
149
|
+
|
150
|
+
def getMethodSignature(self, methodName: str) -> inspect.Signature:
|
151
|
+
"""Get the signature of a method.
|
152
|
+
|
153
|
+
Parameters
|
154
|
+
----------
|
155
|
+
methodName : str
|
156
|
+
Name of the method
|
157
|
+
|
158
|
+
Returns
|
159
|
+
-------
|
160
|
+
inspect.Signature
|
161
|
+
The method signature
|
162
|
+
|
163
|
+
Raises
|
164
|
+
------
|
165
|
+
AttributeError
|
166
|
+
If the method doesn't exist
|
167
|
+
|
168
|
+
Examples
|
169
|
+
--------
|
170
|
+
>>> sig = reflex.getMethodSignature('calculate')
|
171
|
+
>>> str(sig)
|
172
|
+
'(x, y)'
|
173
|
+
"""
|
174
|
+
method = getattr(self._instance, methodName)
|
175
|
+
return inspect.signature(method)
|
176
|
+
|
177
|
+
def getDocstring(self) -> Optional[str]:
|
178
|
+
"""Get the docstring of the instance's class.
|
179
|
+
|
180
|
+
Returns
|
181
|
+
-------
|
182
|
+
Optional[str]
|
183
|
+
The class docstring, or None if not available
|
184
|
+
|
185
|
+
Examples
|
186
|
+
--------
|
187
|
+
>>> reflex.getDocstring()
|
188
|
+
'This class does something important.'
|
189
|
+
"""
|
190
|
+
return self._instance.__class__.__doc__
|
191
|
+
|
192
|
+
def getBaseClasses(self) -> Tuple[Type, ...]:
|
193
|
+
"""Get the base classes of the instance's class.
|
194
|
+
|
195
|
+
Returns
|
196
|
+
-------
|
197
|
+
Tuple[Type, ...]
|
198
|
+
Tuple of base classes
|
199
|
+
|
200
|
+
Examples
|
201
|
+
--------
|
202
|
+
>>> reflex.getBaseClasses()
|
203
|
+
(<class 'object'>,)
|
204
|
+
"""
|
205
|
+
return self._instance.__class__.__bases__
|
206
|
+
|
207
|
+
def isInstanceOf(self, cls: Type) -> bool:
|
208
|
+
"""Check if the instance is of a specific class.
|
209
|
+
|
210
|
+
Parameters
|
211
|
+
----------
|
212
|
+
cls : Type
|
213
|
+
The class to check against
|
214
|
+
|
215
|
+
Returns
|
216
|
+
-------
|
217
|
+
bool
|
218
|
+
True if the instance is of the specified class
|
219
|
+
|
220
|
+
Examples
|
221
|
+
--------
|
222
|
+
>>> reflex.isInstanceOf(SomeClass)
|
223
|
+
True
|
224
|
+
"""
|
225
|
+
return isinstance(self._instance, cls)
|
226
|
+
|
227
|
+
def getSourceCode(self) -> Optional[str]:
|
228
|
+
"""Get the source code of the instance's class.
|
229
|
+
|
230
|
+
Returns
|
231
|
+
-------
|
232
|
+
Optional[str]
|
233
|
+
The source code if available, None otherwise
|
234
|
+
|
235
|
+
Examples
|
236
|
+
--------
|
237
|
+
>>> print(reflex.getSourceCode())
|
238
|
+
class SomeClass:
|
239
|
+
def __init__(self):
|
240
|
+
...
|
241
|
+
"""
|
242
|
+
try:
|
243
|
+
return inspect.getsource(self._instance.__class__)
|
244
|
+
except (TypeError, OSError):
|
245
|
+
return None
|
246
|
+
|
247
|
+
def getFileLocation(self) -> Optional[str]:
|
248
|
+
"""Get the file location where the class is defined.
|
249
|
+
|
250
|
+
Returns
|
251
|
+
-------
|
252
|
+
Optional[str]
|
253
|
+
The file path if available, None otherwise
|
254
|
+
|
255
|
+
Examples
|
256
|
+
--------
|
257
|
+
>>> reflex.getFileLocation()
|
258
|
+
'/path/to/module.py'
|
259
|
+
"""
|
260
|
+
try:
|
261
|
+
return inspect.getfile(self._instance.__class__)
|
262
|
+
except (TypeError, OSError):
|
263
|
+
return None
|
264
|
+
|
265
|
+
def getAnnotations(self) -> Dict[str, Any]:
|
266
|
+
"""Get type annotations of the class.
|
267
|
+
|
268
|
+
Returns
|
269
|
+
-------
|
270
|
+
Dict[str, Any]
|
271
|
+
Dictionary of attribute names and their type annotations
|
272
|
+
|
273
|
+
Examples
|
274
|
+
--------
|
275
|
+
>>> reflex.getAnnotations()
|
276
|
+
{'name': str, 'value': int}
|
277
|
+
"""
|
278
|
+
return self._instance.__class__.__annotations__
|
279
|
+
|
280
|
+
def hasAttribute(self, name: str) -> bool:
|
281
|
+
"""Check if the instance has a specific attribute.
|
282
|
+
|
283
|
+
Parameters
|
284
|
+
----------
|
285
|
+
name : str
|
286
|
+
The attribute name to check
|
287
|
+
|
288
|
+
Returns
|
289
|
+
-------
|
290
|
+
bool
|
291
|
+
True if the attribute exists
|
292
|
+
|
293
|
+
Examples
|
294
|
+
--------
|
295
|
+
>>> reflex.hasAttribute('important_attr')
|
296
|
+
True
|
297
|
+
"""
|
298
|
+
return hasattr(self._instance, name)
|
299
|
+
|
300
|
+
def getAttribute(self, name: str) -> Any:
|
301
|
+
"""Get an attribute value by name.
|
302
|
+
|
303
|
+
Parameters
|
304
|
+
----------
|
305
|
+
name : str
|
306
|
+
The attribute name
|
307
|
+
|
308
|
+
Returns
|
309
|
+
-------
|
310
|
+
Any
|
311
|
+
The attribute value
|
312
|
+
|
313
|
+
Raises
|
314
|
+
------
|
315
|
+
AttributeError
|
316
|
+
If the attribute doesn't exist
|
317
|
+
|
318
|
+
Examples
|
319
|
+
--------
|
320
|
+
>>> reflex.getAttribute('count')
|
321
|
+
42
|
322
|
+
"""
|
323
|
+
return getattr(self._instance, name)
|
324
|
+
|
325
|
+
def setAttribute(self, name: str, value: Any) -> None:
|
326
|
+
"""Set an attribute value.
|
327
|
+
|
328
|
+
Parameters
|
329
|
+
----------
|
330
|
+
name : str
|
331
|
+
The attribute name
|
332
|
+
value : Any
|
333
|
+
The value to set
|
334
|
+
|
335
|
+
Raises
|
336
|
+
------
|
337
|
+
AttributeError
|
338
|
+
If the attribute is read-only
|
339
|
+
|
340
|
+
Examples
|
341
|
+
--------
|
342
|
+
>>> reflex.setAttribute('count', 100)
|
343
|
+
"""
|
344
|
+
setattr(self._instance, name, value)
|
345
|
+
|
346
|
+
def getCallableMembers(self) -> Dict[str, Callable]:
|
347
|
+
"""Get all callable members (methods) of the instance.
|
348
|
+
|
349
|
+
Returns
|
350
|
+
-------
|
351
|
+
Dict[str, Callable]
|
352
|
+
Dictionary of method names and their callable objects
|
353
|
+
|
354
|
+
Examples
|
355
|
+
--------
|
356
|
+
>>> reflex.getCallableMembers()
|
357
|
+
{'calculate': <bound method SomeClass.calculate>, ...}
|
358
|
+
"""
|
359
|
+
return {
|
360
|
+
name: member for name, member in inspect.getmembers(
|
361
|
+
self._instance,
|
362
|
+
callable
|
363
|
+
) if not name.startswith('__')
|
364
|
+
}
|
@@ -0,0 +1,309 @@
|
|
1
|
+
from typing import Any, Type, Dict, List, Tuple, Callable, Optional, Set, TypeVar
|
2
|
+
import inspect
|
3
|
+
import abc
|
4
|
+
|
5
|
+
T = TypeVar('T')
|
6
|
+
ABC = TypeVar('ABC', bound=abc.ABC)
|
7
|
+
|
8
|
+
class ReflexionInstanceWithAbstract:
|
9
|
+
"""A reflection object encapsulating a class instance and its abstract parent.
|
10
|
+
|
11
|
+
This class provides methods to inspect both the concrete instance and its
|
12
|
+
abstract parent class, including their relationships and implementations.
|
13
|
+
|
14
|
+
Parameters
|
15
|
+
----------
|
16
|
+
instance : Any
|
17
|
+
The instance being reflected upon
|
18
|
+
abstract : Type[ABC]
|
19
|
+
The abstract parent class
|
20
|
+
|
21
|
+
Attributes
|
22
|
+
----------
|
23
|
+
_instance : Any
|
24
|
+
The encapsulated instance
|
25
|
+
_abstract : Type[ABC]
|
26
|
+
The encapsulated abstract parent class
|
27
|
+
"""
|
28
|
+
|
29
|
+
def __init__(self, instance: Any, abstract: Type[ABC]) -> None:
|
30
|
+
"""Initialize with the instance and abstract parent."""
|
31
|
+
self._instance = instance
|
32
|
+
self._abstract = abstract
|
33
|
+
|
34
|
+
def getClassName(self) -> str:
|
35
|
+
"""Get the name of the instance's class.
|
36
|
+
|
37
|
+
Returns
|
38
|
+
-------
|
39
|
+
str
|
40
|
+
The name of the concrete class
|
41
|
+
"""
|
42
|
+
return self._instance.__class__.__name__
|
43
|
+
|
44
|
+
def getAbstractClassName(self) -> str:
|
45
|
+
"""Get the name of the abstract parent class.
|
46
|
+
|
47
|
+
Returns
|
48
|
+
-------
|
49
|
+
str
|
50
|
+
The name of the abstract class
|
51
|
+
"""
|
52
|
+
return self._abstract.__name__
|
53
|
+
|
54
|
+
def getImplementationStatus(self) -> Dict[str, bool]:
|
55
|
+
"""Check which abstract methods are implemented.
|
56
|
+
|
57
|
+
Returns
|
58
|
+
-------
|
59
|
+
Dict[str, bool]
|
60
|
+
Dictionary mapping abstract method names to implementation status
|
61
|
+
"""
|
62
|
+
abstract_methods = getattr(self._abstract, '__abstractmethods__', set())
|
63
|
+
return {
|
64
|
+
method: method in dir(self._instance)
|
65
|
+
for method in abstract_methods
|
66
|
+
}
|
67
|
+
|
68
|
+
def getMissingImplementations(self) -> Set[str]:
|
69
|
+
"""Get abstract methods not implemented by the concrete class.
|
70
|
+
|
71
|
+
Returns
|
72
|
+
-------
|
73
|
+
Set[str]
|
74
|
+
Set of abstract method names not implemented
|
75
|
+
"""
|
76
|
+
abstract_methods = getattr(self._abstract, '__abstractmethods__', set())
|
77
|
+
return abstract_methods - set(dir(self._instance))
|
78
|
+
|
79
|
+
def isProperImplementation(self) -> bool:
|
80
|
+
"""Check if the instance properly implements all abstract methods.
|
81
|
+
|
82
|
+
Returns
|
83
|
+
-------
|
84
|
+
bool
|
85
|
+
True if all abstract methods are implemented, False otherwise
|
86
|
+
"""
|
87
|
+
return len(self.getMissingImplementations()) == 0
|
88
|
+
|
89
|
+
def getAbstractMethods(self) -> Set[str]:
|
90
|
+
"""Get all abstract methods from the parent class.
|
91
|
+
|
92
|
+
Returns
|
93
|
+
-------
|
94
|
+
Set[str]
|
95
|
+
Set of abstract method names
|
96
|
+
"""
|
97
|
+
return getattr(self._abstract, '__abstractmethods__', set())
|
98
|
+
|
99
|
+
def getConcreteMethods(self) -> List[str]:
|
100
|
+
"""Get all concrete methods of the instance.
|
101
|
+
|
102
|
+
Returns
|
103
|
+
-------
|
104
|
+
List[str]
|
105
|
+
List of method names implemented by the instance
|
106
|
+
"""
|
107
|
+
return [name for name, _ in inspect.getmembers(
|
108
|
+
self._instance,
|
109
|
+
predicate=inspect.ismethod
|
110
|
+
)]
|
111
|
+
|
112
|
+
def getOverriddenMethods(self) -> Dict[str, Tuple[Type, Type]]:
|
113
|
+
"""Get methods that override abstract ones with their signatures.
|
114
|
+
|
115
|
+
Returns
|
116
|
+
-------
|
117
|
+
Dict[str, Tuple[Type, Type]]
|
118
|
+
Dictionary mapping method names to tuples of
|
119
|
+
(abstract_signature, concrete_signature)
|
120
|
+
"""
|
121
|
+
overridden = {}
|
122
|
+
abstract_methods = self.getAbstractMethods()
|
123
|
+
|
124
|
+
for method in abstract_methods:
|
125
|
+
if hasattr(self._instance, method):
|
126
|
+
abstract_sig = inspect.signature(getattr(self._abstract, method))
|
127
|
+
concrete_sig = inspect.signature(getattr(self._instance, method))
|
128
|
+
overridden[method] = (abstract_sig, concrete_sig)
|
129
|
+
|
130
|
+
return overridden
|
131
|
+
|
132
|
+
def checkSignatureCompatibility(self) -> Dict[str, bool]:
|
133
|
+
"""Check if implemented methods match abstract signatures.
|
134
|
+
|
135
|
+
Returns
|
136
|
+
-------
|
137
|
+
Dict[str, bool]
|
138
|
+
Dictionary mapping method names to compatibility status
|
139
|
+
"""
|
140
|
+
compatibility = {}
|
141
|
+
overridden = self.getOverriddenMethods()
|
142
|
+
|
143
|
+
for method, (abstract_sig, concrete_sig) in overridden.items():
|
144
|
+
compatibility[method] = (
|
145
|
+
abstract_sig.parameters == concrete_sig.parameters and
|
146
|
+
abstract_sig.return_annotation == concrete_sig.return_annotation
|
147
|
+
)
|
148
|
+
|
149
|
+
return compatibility
|
150
|
+
|
151
|
+
def getAbstractProperties(self) -> Set[str]:
|
152
|
+
"""Get all abstract properties from the parent class.
|
153
|
+
|
154
|
+
Returns
|
155
|
+
-------
|
156
|
+
Set[str]
|
157
|
+
Set of abstract property names
|
158
|
+
"""
|
159
|
+
return {
|
160
|
+
name for name, member in inspect.getmembers(
|
161
|
+
self._abstract,
|
162
|
+
lambda x: isinstance(x, property) and
|
163
|
+
name in getattr(self._abstract, '__abstractmethods__', set())
|
164
|
+
)
|
165
|
+
}
|
166
|
+
|
167
|
+
def getInstanceAttributes(self) -> Dict[str, Any]:
|
168
|
+
"""Get all attributes of the concrete instance.
|
169
|
+
|
170
|
+
Returns
|
171
|
+
-------
|
172
|
+
Dict[str, Any]
|
173
|
+
Dictionary of attribute names and their values
|
174
|
+
"""
|
175
|
+
return vars(self._instance)
|
176
|
+
|
177
|
+
def getAbstractClassDocstring(self) -> Optional[str]:
|
178
|
+
"""Get the docstring of the abstract parent class.
|
179
|
+
|
180
|
+
Returns
|
181
|
+
-------
|
182
|
+
Optional[str]
|
183
|
+
The abstract class docstring, or None if not available
|
184
|
+
"""
|
185
|
+
return self._abstract.__doc__
|
186
|
+
|
187
|
+
def getConcreteClassDocstring(self) -> Optional[str]:
|
188
|
+
"""Get the docstring of the concrete instance's class.
|
189
|
+
|
190
|
+
Returns
|
191
|
+
-------
|
192
|
+
Optional[str]
|
193
|
+
The concrete class docstring, or None if not available
|
194
|
+
"""
|
195
|
+
return self._instance.__class__.__doc__
|
196
|
+
|
197
|
+
def getAbstractClassModule(self) -> str:
|
198
|
+
"""Get the module name where the abstract class is defined.
|
199
|
+
|
200
|
+
Returns
|
201
|
+
-------
|
202
|
+
str
|
203
|
+
The module name of the abstract class
|
204
|
+
"""
|
205
|
+
return self._abstract.__module__
|
206
|
+
|
207
|
+
def getConcreteClassModule(self) -> str:
|
208
|
+
"""Get the module name where the concrete class is defined.
|
209
|
+
|
210
|
+
Returns
|
211
|
+
-------
|
212
|
+
str
|
213
|
+
The module name of the concrete class
|
214
|
+
"""
|
215
|
+
return self._instance.__class__.__module__
|
216
|
+
|
217
|
+
def isDirectSubclass(self) -> bool:
|
218
|
+
"""Check if the concrete class directly inherits from the abstract class.
|
219
|
+
|
220
|
+
Returns
|
221
|
+
-------
|
222
|
+
bool
|
223
|
+
True if direct subclass, False otherwise
|
224
|
+
"""
|
225
|
+
return self._abstract in self._instance.__class__.__bases__
|
226
|
+
|
227
|
+
def getAbstractClassHierarchy(self) -> List[Type]:
|
228
|
+
"""Get the inheritance hierarchy of the abstract class.
|
229
|
+
|
230
|
+
Returns
|
231
|
+
-------
|
232
|
+
List[Type]
|
233
|
+
List of classes in the inheritance hierarchy
|
234
|
+
"""
|
235
|
+
return inspect.getmro(self._abstract)
|
236
|
+
|
237
|
+
def getConcreteClassHierarchy(self) -> List[Type]:
|
238
|
+
"""Get the inheritance hierarchy of the concrete class.
|
239
|
+
|
240
|
+
Returns
|
241
|
+
-------
|
242
|
+
List[Type]
|
243
|
+
List of classes in the inheritance hierarchy
|
244
|
+
"""
|
245
|
+
return inspect.getmro(self._instance.__class__)
|
246
|
+
|
247
|
+
def getCommonBaseClasses(self) -> List[Type]:
|
248
|
+
"""Get base classes common to both abstract and concrete classes.
|
249
|
+
|
250
|
+
Returns
|
251
|
+
-------
|
252
|
+
List[Type]
|
253
|
+
List of common base classes
|
254
|
+
"""
|
255
|
+
abstract_bases = set(inspect.getmro(self._abstract))
|
256
|
+
concrete_bases = set(inspect.getmro(self._instance.__class__))
|
257
|
+
return list(abstract_bases & concrete_bases - {self._abstract, object})
|
258
|
+
|
259
|
+
def getAbstractClassSource(self) -> Optional[str]:
|
260
|
+
"""Get the source code of the abstract class.
|
261
|
+
|
262
|
+
Returns
|
263
|
+
-------
|
264
|
+
Optional[str]
|
265
|
+
The source code if available, None otherwise
|
266
|
+
"""
|
267
|
+
try:
|
268
|
+
return inspect.getsource(self._abstract)
|
269
|
+
except (TypeError, OSError):
|
270
|
+
return None
|
271
|
+
|
272
|
+
def getConcreteClassSource(self) -> Optional[str]:
|
273
|
+
"""Get the source code of the concrete class.
|
274
|
+
|
275
|
+
Returns
|
276
|
+
-------
|
277
|
+
Optional[str]
|
278
|
+
The source code if available, None otherwise
|
279
|
+
"""
|
280
|
+
try:
|
281
|
+
return inspect.getsource(self._instance.__class__)
|
282
|
+
except (TypeError, OSError):
|
283
|
+
return None
|
284
|
+
|
285
|
+
def getAbstractClassFile(self) -> Optional[str]:
|
286
|
+
"""Get the file location of the abstract class definition.
|
287
|
+
|
288
|
+
Returns
|
289
|
+
-------
|
290
|
+
Optional[str]
|
291
|
+
The file path if available, None otherwise
|
292
|
+
"""
|
293
|
+
try:
|
294
|
+
return inspect.getfile(self._abstract)
|
295
|
+
except (TypeError, OSError):
|
296
|
+
return None
|
297
|
+
|
298
|
+
def getConcreteClassFile(self) -> Optional[str]:
|
299
|
+
"""Get the file location of the concrete class definition.
|
300
|
+
|
301
|
+
Returns
|
302
|
+
-------
|
303
|
+
Optional[str]
|
304
|
+
The file path if available, None otherwise
|
305
|
+
"""
|
306
|
+
try:
|
307
|
+
return inspect.getfile(self._instance.__class__)
|
308
|
+
except (TypeError, OSError):
|
309
|
+
return None
|