orionis 0.304.0__py3-none-any.whl → 0.306.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/metadata/framework.py +1 -1
- orionis/services/introspection/modules/{reflection_instance.py → reflection_module.py} +1 -1
- orionis/services/introspection/reflection.py +90 -0
- orionis/{services → support}/standard/std.py +2 -2
- orionis/test/{facade/test_suite.py → test_suite.py} +1 -2
- orionis/unittesting.py +1 -1
- {orionis-0.304.0.dist-info → orionis-0.306.0.dist-info}/METADATA +1 -1
- {orionis-0.304.0.dist-info → orionis-0.306.0.dist-info}/RECORD +28 -65
- tests/{services → support}/standard/test_services_std.py +3 -3
- tests/{services → support}/wrapper/test_services_wrapper_docdict.py +2 -2
- orionis/support/abstracts/entities/abstract_class_attributes.py +0 -37
- orionis/support/abstracts/reflect_abstract.py +0 -556
- orionis/support/helpers/functions.py +0 -285
- orionis/support/introspection/container_integrity.py +0 -292
- orionis/support/introspection/contracts/__init__.py +0 -0
- orionis/support/introspection/contracts/reflection.py +0 -187
- orionis/support/introspection/contracts/reflexion_abstract.py +0 -264
- orionis/support/introspection/helpers/__init__.py +0 -0
- orionis/support/introspection/helpers/functions.py +0 -281
- orionis/support/introspection/instances/__init__.py +0 -0
- orionis/support/introspection/instances/contracts/__init__.py +0 -0
- orionis/support/introspection/instances/contracts/reflection_instance.py +0 -649
- orionis/support/introspection/instances/entities/__init__.py +0 -0
- orionis/support/introspection/instances/reflection_instance.py +0 -758
- orionis/support/introspection/reflect_decorators.py +0 -335
- orionis/support/introspection/reflection.py +0 -216
- orionis/support/introspection/reflexion_concrete.py +0 -276
- orionis/support/introspection/reflexion_concrete_with_abstract.py +0 -185
- orionis/support/introspection/reflexion_instance_with_abstract.py +0 -230
- orionis/support/introspection/reflexion_module.py +0 -19
- orionis/support/introspection/reflexion_module_with_classname.py +0 -22
- orionis/support/reflection.py +0 -216
- orionis/test/facade/__init__.py +0 -0
- orionis/test/facade/contracts/__init__.py +0 -0
- orionis/test/facade/contracts/test_suite.py +0 -25
- tests/services/standard/__init__.py +0 -0
- tests/services/wrapper/__init__.py +0 -0
- tests/support/inspection/__init__.py +0 -0
- tests/support/inspection/fakes/__init__.py +0 -0
- tests/support/inspection/fakes/fake_reflect_abstract.py +0 -276
- tests/support/inspection/fakes/fake_reflection_concrete.py +0 -44
- tests/support/inspection/fakes/fake_reflection_concrete_with_abstract.py +0 -78
- tests/support/inspection/fakes/fake_reflection_instance_with_abstract.py +0 -45
- tests/support/inspection/test_reflect_abstract.py +0 -334
- tests/support/inspection/test_reflect_instance.py +0 -288
- tests/support/inspection/test_reflection_concrete.py +0 -142
- tests/support/inspection/test_reflection_concrete_with_abstract.py +0 -87
- tests/support/inspection/test_reflection_instance_with_abstract.py +0 -79
- /orionis/services/introspection/modules/contracts/{reflection_instance.py → reflection_module.py} +0 -0
- /orionis/{services → support}/standard/__init__.py +0 -0
- /orionis/{services → support}/standard/contracts/__init__.py +0 -0
- /orionis/{services → support}/standard/contracts/std.py +0 -0
- /orionis/{services → support}/standard/exceptions/__init__.py +0 -0
- /orionis/{services → support}/standard/exceptions/std_value_exception.py +0 -0
- /orionis/{services → support}/wrapper/__init__.py +0 -0
- /orionis/{services → support}/wrapper/dicts/__init__.py +0 -0
- /orionis/{services → support}/wrapper/dicts/dot_dict.py +0 -0
- {orionis-0.304.0.dist-info → orionis-0.306.0.dist-info}/WHEEL +0 -0
- {orionis-0.304.0.dist-info → orionis-0.306.0.dist-info}/licenses/LICENCE +0 -0
- {orionis-0.304.0.dist-info → orionis-0.306.0.dist-info}/top_level.txt +0 -0
- {orionis-0.304.0.dist-info → orionis-0.306.0.dist-info}/zip-safe +0 -0
- {orionis/support/abstracts → tests/services/inspection/reflection}/__init__.py +0 -0
- {orionis/support/abstracts/entities → tests/services/inspection/reflection/mock}/__init__.py +0 -0
- /tests/{support/inspection/fakes → services/inspection/reflection/mock}/fake_reflect_instance.py +0 -0
- {orionis/support/helpers → tests/support/standard}/__init__.py +0 -0
- {orionis/support/introspection → tests/support/wrapper}/__init__.py +0 -0
@@ -1,276 +0,0 @@
|
|
1
|
-
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, TypeVar
|
2
|
-
import inspect
|
3
|
-
|
4
|
-
T = TypeVar('T')
|
5
|
-
|
6
|
-
class ReflexionConcrete:
|
7
|
-
"""A reflection object encapsulating a concrete class.
|
8
|
-
|
9
|
-
Parameters
|
10
|
-
----------
|
11
|
-
concrete : Type[T]
|
12
|
-
The concrete class being reflected upon
|
13
|
-
|
14
|
-
Attributes
|
15
|
-
----------
|
16
|
-
_concrete : Type[T]
|
17
|
-
The encapsulated concrete class
|
18
|
-
"""
|
19
|
-
|
20
|
-
def __init__(self, concrete: Type[T]) -> None:
|
21
|
-
"""Initialize with the concrete class."""
|
22
|
-
self._concrete = concrete
|
23
|
-
|
24
|
-
def getClassName(self) -> str:
|
25
|
-
"""Get the name of the concrete class.
|
26
|
-
|
27
|
-
Returns
|
28
|
-
-------
|
29
|
-
str
|
30
|
-
The name of the class
|
31
|
-
"""
|
32
|
-
return self._concrete.__name__
|
33
|
-
|
34
|
-
def getClass(self) -> Type:
|
35
|
-
"""Get the class of the instance.
|
36
|
-
|
37
|
-
Returns
|
38
|
-
-------
|
39
|
-
Type
|
40
|
-
The class object of the instance
|
41
|
-
|
42
|
-
Examples
|
43
|
-
--------
|
44
|
-
>>> reflex.getClass() is SomeClass
|
45
|
-
True
|
46
|
-
"""
|
47
|
-
return self._concrete
|
48
|
-
|
49
|
-
def getModuleName(self) -> str:
|
50
|
-
"""Get the name of the module where the class is defined.
|
51
|
-
|
52
|
-
Returns
|
53
|
-
-------
|
54
|
-
str
|
55
|
-
The module name
|
56
|
-
"""
|
57
|
-
return self._concrete.__module__
|
58
|
-
|
59
|
-
def getAttributes(self) -> Dict[str, Any]:
|
60
|
-
"""Get all class-level attributes.
|
61
|
-
|
62
|
-
Returns
|
63
|
-
-------
|
64
|
-
Dict[str, Any]
|
65
|
-
Dictionary of attribute names and their values
|
66
|
-
"""
|
67
|
-
return {
|
68
|
-
k: v for k, v in vars(self._concrete).items()
|
69
|
-
if not callable(v) and not isinstance(v, staticmethod) and not isinstance(v, classmethod) and not k.startswith('_') and not isinstance(v, property)
|
70
|
-
}
|
71
|
-
|
72
|
-
def getMethods(self) -> List[str]:
|
73
|
-
"""Get all method names of the class.
|
74
|
-
|
75
|
-
Returns
|
76
|
-
-------
|
77
|
-
List[str]
|
78
|
-
List of method names
|
79
|
-
"""
|
80
|
-
return [
|
81
|
-
name for name, member in inspect.getmembers(self._concrete, predicate=inspect.isfunction)
|
82
|
-
if not name.startswith('_')
|
83
|
-
]
|
84
|
-
|
85
|
-
def getStaticMethods(self) -> List[str]:
|
86
|
-
"""Get all static method names of the class.
|
87
|
-
|
88
|
-
Returns
|
89
|
-
-------
|
90
|
-
List[str]
|
91
|
-
List of static method names, excluding private methods
|
92
|
-
"""
|
93
|
-
return [
|
94
|
-
name for name in dir(self._concrete)
|
95
|
-
if not name.startswith('_') and isinstance(inspect.getattr_static(self._concrete, name), staticmethod)
|
96
|
-
]
|
97
|
-
|
98
|
-
def getPropertyNames(self) -> List[str]:
|
99
|
-
"""Get all property names of the class.
|
100
|
-
|
101
|
-
Returns
|
102
|
-
-------
|
103
|
-
List[str]
|
104
|
-
List of property names
|
105
|
-
"""
|
106
|
-
return [
|
107
|
-
name for name, val in vars(self._concrete).items()
|
108
|
-
if isinstance(val, property)
|
109
|
-
]
|
110
|
-
|
111
|
-
def getMethodSignature(self, methodName: str) -> inspect.Signature:
|
112
|
-
"""Get the signature of a class method.
|
113
|
-
|
114
|
-
Parameters
|
115
|
-
----------
|
116
|
-
methodName : str
|
117
|
-
Name of the method
|
118
|
-
|
119
|
-
Returns
|
120
|
-
-------
|
121
|
-
inspect.Signature
|
122
|
-
The method signature
|
123
|
-
|
124
|
-
Raises
|
125
|
-
------
|
126
|
-
AttributeError
|
127
|
-
If the method doesn't exist
|
128
|
-
"""
|
129
|
-
method = getattr(self._concrete, methodName)
|
130
|
-
if callable(method):
|
131
|
-
return inspect.signature(method)
|
132
|
-
raise AttributeError(f"{methodName} is not a valid method.")
|
133
|
-
|
134
|
-
def getPropertySignature(self, propertyName: str) -> inspect.Signature:
|
135
|
-
"""Get the signature of a property getter.
|
136
|
-
|
137
|
-
Parameters
|
138
|
-
----------
|
139
|
-
propertyName : str
|
140
|
-
Name of the property
|
141
|
-
|
142
|
-
Returns
|
143
|
-
-------
|
144
|
-
inspect.Signature
|
145
|
-
The property's getter method signature
|
146
|
-
|
147
|
-
Raises
|
148
|
-
------
|
149
|
-
AttributeError
|
150
|
-
If the property doesn't exist or is not a property
|
151
|
-
"""
|
152
|
-
attr = getattr(self._concrete, propertyName, None)
|
153
|
-
if isinstance(attr, property) and attr.fget is not None:
|
154
|
-
return inspect.signature(attr.fget)
|
155
|
-
raise AttributeError(f"{propertyName} is not a property or doesn't have a getter.")
|
156
|
-
|
157
|
-
def getDocstring(self) -> Optional[str]:
|
158
|
-
"""Get the docstring of the class.
|
159
|
-
|
160
|
-
Returns
|
161
|
-
-------
|
162
|
-
Optional[str]
|
163
|
-
The class docstring, or None if not available
|
164
|
-
"""
|
165
|
-
return self._concrete.__doc__
|
166
|
-
|
167
|
-
def getBaseClasses(self) -> Tuple[Type, ...]:
|
168
|
-
"""Get the base classes of the class.
|
169
|
-
|
170
|
-
Returns
|
171
|
-
-------
|
172
|
-
Tuple[Type, ...]
|
173
|
-
Tuple of base classes
|
174
|
-
"""
|
175
|
-
return self._concrete.__bases__
|
176
|
-
|
177
|
-
def isSubclassOf(self, cls: Type) -> bool:
|
178
|
-
"""Check if the concrete class is a subclass of another.
|
179
|
-
|
180
|
-
Parameters
|
181
|
-
----------
|
182
|
-
cls : Type
|
183
|
-
The parent class to check against
|
184
|
-
|
185
|
-
Returns
|
186
|
-
-------
|
187
|
-
bool
|
188
|
-
True if the concrete class is a subclass of the given class
|
189
|
-
"""
|
190
|
-
return issubclass(self._concrete, cls)
|
191
|
-
|
192
|
-
def getSourceCode(self) -> Optional[str]:
|
193
|
-
"""Get the source code of the class.
|
194
|
-
|
195
|
-
Returns
|
196
|
-
-------
|
197
|
-
Optional[str]
|
198
|
-
The source code if available, None otherwise
|
199
|
-
"""
|
200
|
-
try:
|
201
|
-
return inspect.getsource(self._concrete)
|
202
|
-
except (TypeError, OSError):
|
203
|
-
return None
|
204
|
-
|
205
|
-
def getFileLocation(self) -> Optional[str]:
|
206
|
-
"""Get the file location where the class is defined.
|
207
|
-
|
208
|
-
Returns
|
209
|
-
-------
|
210
|
-
Optional[str]
|
211
|
-
The file path if available, None otherwise
|
212
|
-
"""
|
213
|
-
try:
|
214
|
-
return inspect.getfile(self._concrete)
|
215
|
-
except (TypeError, OSError):
|
216
|
-
return None
|
217
|
-
|
218
|
-
def getAnnotations(self) -> Dict[str, Any]:
|
219
|
-
"""Get type annotations of the class.
|
220
|
-
|
221
|
-
Returns
|
222
|
-
-------
|
223
|
-
Dict[str, Any]
|
224
|
-
Dictionary of attribute names and their type annotations
|
225
|
-
"""
|
226
|
-
return getattr(self._concrete, '__annotations__', {})
|
227
|
-
|
228
|
-
def hasAttribute(self, name: str) -> bool:
|
229
|
-
"""Check if the class has a specific attribute.
|
230
|
-
|
231
|
-
Parameters
|
232
|
-
----------
|
233
|
-
name : str
|
234
|
-
The attribute name to check
|
235
|
-
|
236
|
-
Returns
|
237
|
-
-------
|
238
|
-
bool
|
239
|
-
True if the attribute exists
|
240
|
-
"""
|
241
|
-
return hasattr(self._concrete, name)
|
242
|
-
|
243
|
-
def getAttribute(self, name: str) -> Any:
|
244
|
-
"""Get a class attribute by name.
|
245
|
-
|
246
|
-
Parameters
|
247
|
-
----------
|
248
|
-
name : str
|
249
|
-
The attribute name
|
250
|
-
|
251
|
-
Returns
|
252
|
-
-------
|
253
|
-
Any
|
254
|
-
The attribute value
|
255
|
-
|
256
|
-
Raises
|
257
|
-
------
|
258
|
-
AttributeError
|
259
|
-
If the attribute doesn't exist
|
260
|
-
"""
|
261
|
-
return getattr(self._concrete, name)
|
262
|
-
|
263
|
-
def getCallableMembers(self) -> Dict[str, Callable]:
|
264
|
-
"""Get all callable members (functions/methods) of the class.
|
265
|
-
|
266
|
-
Returns
|
267
|
-
-------
|
268
|
-
Dict[str, Callable]
|
269
|
-
Dictionary of method names and their callable objects
|
270
|
-
"""
|
271
|
-
return {
|
272
|
-
name: member for name, member in inspect.getmembers(
|
273
|
-
self._concrete,
|
274
|
-
callable
|
275
|
-
) if not name.startswith('__')
|
276
|
-
}
|
@@ -1,185 +0,0 @@
|
|
1
|
-
import abc
|
2
|
-
import inspect
|
3
|
-
from typing import Any, Dict, List, Tuple, Type, TypeVar, Union
|
4
|
-
from orionis.support.introspection.abstracts.reflect_abstract import ReflexionAbstract
|
5
|
-
from orionis.support.introspection.reflexion_concrete import ReflexionConcrete
|
6
|
-
|
7
|
-
T = TypeVar('T')
|
8
|
-
ABC = TypeVar('ABC', bound=abc.ABC)
|
9
|
-
|
10
|
-
class ReflexionConcreteWithAbstract:
|
11
|
-
"""Advanced reflection tool for analyzing concrete classes against abstract bases.
|
12
|
-
|
13
|
-
Allows static analysis of class definitions to verify compatibility
|
14
|
-
and adherence to interface contracts without instantiation.
|
15
|
-
|
16
|
-
Parameters
|
17
|
-
----------
|
18
|
-
concrete : Type[T]
|
19
|
-
The concrete class to inspect
|
20
|
-
abstract : Type[ABC]
|
21
|
-
The abstract base class/interface being implemented
|
22
|
-
|
23
|
-
Attributes
|
24
|
-
----------
|
25
|
-
_concrete : Type[T]
|
26
|
-
The concrete class being analyzed
|
27
|
-
_abstract : Type[ABC]
|
28
|
-
The abstract base class/interface
|
29
|
-
_concrete_reflexion : ReflexionConcrete
|
30
|
-
Reflection helper for the concrete class
|
31
|
-
_abstract_reflexion : ReflexionAbstract
|
32
|
-
Reflection helper for the abstract class
|
33
|
-
"""
|
34
|
-
|
35
|
-
def __init__(self, concrete: Type[T], abstract: Type[ABC]) -> None:
|
36
|
-
self._concrete = concrete
|
37
|
-
self._abstract = abstract
|
38
|
-
self._concrete_reflexion = ReflexionConcrete(concrete)
|
39
|
-
self._abstract_reflexion = ReflexionAbstract(abstract)
|
40
|
-
|
41
|
-
@property
|
42
|
-
def concrete(self) -> ReflexionConcrete:
|
43
|
-
"""Access the concrete class reflection helper."""
|
44
|
-
return self._concrete_reflexion
|
45
|
-
|
46
|
-
@property
|
47
|
-
def abstract(self) -> ReflexionAbstract:
|
48
|
-
"""Access the abstract class reflection helper."""
|
49
|
-
return self._abstract_reflexion
|
50
|
-
|
51
|
-
def getImplementationAnalysis(self) -> Dict[str, Dict[str, Union[bool, str, inspect.Signature]]]:
|
52
|
-
"""Comprehensive analysis of implementation compliance."""
|
53
|
-
analysis = {}
|
54
|
-
|
55
|
-
abstract_methods = self._abstract_reflexion.getAbstractMethods()
|
56
|
-
for method in abstract_methods:
|
57
|
-
entry = {
|
58
|
-
'implemented': False,
|
59
|
-
'abstract_signature': None,
|
60
|
-
'concrete_signature': None,
|
61
|
-
'signature_match': False,
|
62
|
-
'type': 'method'
|
63
|
-
}
|
64
|
-
|
65
|
-
if hasattr(self._concrete, method):
|
66
|
-
entry['implemented'] = True
|
67
|
-
abstract_sig = self._abstract_reflexion.getMethodSignature(method)
|
68
|
-
concrete_sig = self._concrete_reflexion.getMethodSignature(method)
|
69
|
-
|
70
|
-
entry.update({
|
71
|
-
'abstract_signature': abstract_sig,
|
72
|
-
'concrete_signature': concrete_sig,
|
73
|
-
'signature_match': (
|
74
|
-
abstract_sig.parameters == concrete_sig.parameters and
|
75
|
-
abstract_sig.return_annotation == concrete_sig.return_annotation
|
76
|
-
)
|
77
|
-
})
|
78
|
-
|
79
|
-
analysis[method] = entry
|
80
|
-
|
81
|
-
abstract_properties = self._abstract_reflexion.getAbstractProperties()
|
82
|
-
for prop in abstract_properties:
|
83
|
-
entry = {
|
84
|
-
'implemented': False,
|
85
|
-
'abstract_signature': None,
|
86
|
-
'concrete_signature': None,
|
87
|
-
'signature_match': False,
|
88
|
-
'type': 'property'
|
89
|
-
}
|
90
|
-
|
91
|
-
if hasattr(self._concrete, prop):
|
92
|
-
entry['implemented'] = True
|
93
|
-
abstract_sig = self._abstract_reflexion.getPropertySignature(prop)
|
94
|
-
concrete_sig = self._concrete_reflexion.getPropertySignature(prop)
|
95
|
-
|
96
|
-
entry.update({
|
97
|
-
'abstract_signature': abstract_sig,
|
98
|
-
'concrete_signature': concrete_sig,
|
99
|
-
'signature_match': (
|
100
|
-
abstract_sig.parameters == concrete_sig.parameters and
|
101
|
-
abstract_sig.return_annotation == concrete_sig.return_annotation
|
102
|
-
)
|
103
|
-
})
|
104
|
-
|
105
|
-
analysis[prop] = entry
|
106
|
-
|
107
|
-
return analysis
|
108
|
-
|
109
|
-
def validateImplementation(self) -> Tuple[bool, Dict[str, List[str]]]:
|
110
|
-
"""Validate the implementation against the abstract base."""
|
111
|
-
issues = {
|
112
|
-
'missing': [],
|
113
|
-
'signature_mismatch': [],
|
114
|
-
'type_mismatch': []
|
115
|
-
}
|
116
|
-
|
117
|
-
analysis = self.getImplementationAnalysis()
|
118
|
-
for name, data in analysis.items():
|
119
|
-
if not data['implemented']:
|
120
|
-
issues['missing'].append(name)
|
121
|
-
elif not data['signature_match']:
|
122
|
-
issues['signature_mismatch'].append(name)
|
123
|
-
abstract_return = data['abstract_signature'].return_annotation
|
124
|
-
concrete_return = data['concrete_signature'].return_annotation
|
125
|
-
if abstract_return != concrete_return and abstract_return is not inspect.Parameter.empty:
|
126
|
-
issues['type_mismatch'].append(name)
|
127
|
-
|
128
|
-
is_valid = not any(issues.values())
|
129
|
-
return (is_valid, issues)
|
130
|
-
|
131
|
-
def getImplementationCoverage(self) -> float:
|
132
|
-
"""Calculate the percentage of abstract methods/properties implemented."""
|
133
|
-
analysis = self.getImplementationAnalysis()
|
134
|
-
total = len(analysis) * 2
|
135
|
-
implemented = 0
|
136
|
-
for item in analysis.values():
|
137
|
-
if item['implemented']:
|
138
|
-
implemented += 2 if item['signature_match'] else 1
|
139
|
-
return implemented / total if total else 0.0
|
140
|
-
|
141
|
-
def getNonInheritedImplementation(self) -> Dict[str, Any]:
|
142
|
-
"""Get implementation details for methods, properties, and attributes not inherited from the abstract base."""
|
143
|
-
concrete_members = set(dir(self._concrete))
|
144
|
-
base_members = set(dir(self._abstract))
|
145
|
-
|
146
|
-
non_inherited_methods = [
|
147
|
-
name for name in concrete_members
|
148
|
-
if callable(getattr(self._concrete, name, None)) and name not in base_members
|
149
|
-
]
|
150
|
-
|
151
|
-
non_inherited_properties = [
|
152
|
-
name for name in concrete_members
|
153
|
-
if isinstance(getattr(self._concrete, name, None), property) and name not in base_members
|
154
|
-
]
|
155
|
-
|
156
|
-
non_inherited_attributes = {
|
157
|
-
name: getattr(self._concrete, name, None)
|
158
|
-
for name in concrete_members
|
159
|
-
if (
|
160
|
-
not callable(getattr(self._concrete, name, None)) and
|
161
|
-
not isinstance(getattr(self._concrete, name, None), property) and
|
162
|
-
name not in base_members
|
163
|
-
)
|
164
|
-
}
|
165
|
-
|
166
|
-
return {
|
167
|
-
'methods': non_inherited_methods,
|
168
|
-
'properties': non_inherited_properties,
|
169
|
-
'attributes': non_inherited_attributes
|
170
|
-
}
|
171
|
-
|
172
|
-
def getHierarchyAnalysis(self) -> Dict[str, List[str]]:
|
173
|
-
"""Analyze the class hierarchy relationships."""
|
174
|
-
concrete_hierarchy = [cls.__name__ for cls in inspect.getmro(self._concrete)]
|
175
|
-
abstract_hierarchy = [cls.__name__ for cls in inspect.getmro(self._abstract)]
|
176
|
-
|
177
|
-
concrete_bases = set(inspect.getmro(self._concrete))
|
178
|
-
abstract_bases = set(inspect.getmro(self._abstract))
|
179
|
-
common = concrete_bases & abstract_bases - {self._abstract, object}
|
180
|
-
|
181
|
-
return {
|
182
|
-
'concrete_hierarchy': concrete_hierarchy,
|
183
|
-
'abstract_hierarchy': abstract_hierarchy,
|
184
|
-
'common_ancestors': [cls.__name__ for cls in common]
|
185
|
-
}
|
@@ -1,230 +0,0 @@
|
|
1
|
-
import abc
|
2
|
-
import inspect
|
3
|
-
from typing import Any, Dict, List, Tuple, Type, TypeVar, Union
|
4
|
-
from orionis.support.introspection.abstracts.reflect_abstract import ReflexionAbstract
|
5
|
-
from orionis.support.introspection.instances.reflection_instance import ReflectionInstance
|
6
|
-
|
7
|
-
T = TypeVar('T')
|
8
|
-
ABC = TypeVar('ABC', bound=abc.ABC)
|
9
|
-
|
10
|
-
class ReflexionInstanceWithAbstract:
|
11
|
-
"""Advanced reflection tool for analyzing concrete implementations against abstract bases.
|
12
|
-
|
13
|
-
Combines inspection of both concrete instances and their abstract parent classes,
|
14
|
-
providing detailed comparison and compatibility analysis.
|
15
|
-
|
16
|
-
Parameters
|
17
|
-
----------
|
18
|
-
instance : Any
|
19
|
-
The concrete instance to inspect
|
20
|
-
abstract : Type[ABC]
|
21
|
-
The abstract base class/interface being implemented
|
22
|
-
|
23
|
-
Attributes
|
24
|
-
----------
|
25
|
-
_instance : Any
|
26
|
-
The concrete instance being analyzed
|
27
|
-
_abstract : Type[ABC]
|
28
|
-
The abstract base class/interface
|
29
|
-
_concrete_reflexion : ReflexionInstance
|
30
|
-
Reflection helper for the concrete instance
|
31
|
-
_abstract_reflexion : ReflexionAbstract
|
32
|
-
Reflection helper for the abstract class
|
33
|
-
"""
|
34
|
-
|
35
|
-
def __init__(self, instance: Any, abstract: Type[ABC]) -> None:
|
36
|
-
self._instance = instance
|
37
|
-
self._abstract = abstract
|
38
|
-
self._concrete_reflexion = ReflectionInstance(instance)
|
39
|
-
self._abstract_reflexion = ReflexionAbstract(abstract)
|
40
|
-
|
41
|
-
@property
|
42
|
-
def concrete(self) -> ReflectionInstance:
|
43
|
-
"""Access the concrete instance reflection helper."""
|
44
|
-
return self._concrete_reflexion
|
45
|
-
|
46
|
-
@property
|
47
|
-
def abstract(self) -> ReflexionAbstract:
|
48
|
-
"""Access the abstract class reflection helper."""
|
49
|
-
return self._abstract_reflexion
|
50
|
-
|
51
|
-
def getImplementationAnalysis(self) -> Dict[str, Dict[str, Union[bool, str, inspect.Signature]]]:
|
52
|
-
"""Comprehensive analysis of implementation compliance.
|
53
|
-
|
54
|
-
Returns
|
55
|
-
-------
|
56
|
-
Dict[str, Dict[str, Union[bool, str, inspect.Signature]]]
|
57
|
-
Detailed analysis including:
|
58
|
-
- 'implemented': Whether method is implemented
|
59
|
-
- 'signature_match': Whether signatures match
|
60
|
-
- 'abstract_signature': Signature from abstract class
|
61
|
-
- 'concrete_signature': Signature from concrete class
|
62
|
-
"""
|
63
|
-
analysis = {}
|
64
|
-
abstract_methods = self._abstract_reflexion.getAbstractMethods()
|
65
|
-
for method in abstract_methods:
|
66
|
-
entry = {
|
67
|
-
'implemented': False,
|
68
|
-
'abstract_signature': None,
|
69
|
-
'concrete_signature': None,
|
70
|
-
'signature_match': False,
|
71
|
-
'type' : 'method'
|
72
|
-
}
|
73
|
-
|
74
|
-
if hasattr(self._instance, method):
|
75
|
-
entry['implemented'] = True
|
76
|
-
abstract_sig = self._abstract_reflexion.getMethodSignature(method)
|
77
|
-
concrete_sig = self._concrete_reflexion.getMethodSignature(method)
|
78
|
-
|
79
|
-
entry.update({
|
80
|
-
'abstract_signature': abstract_sig,
|
81
|
-
'concrete_signature': concrete_sig,
|
82
|
-
'signature_match': (
|
83
|
-
abstract_sig.parameters == concrete_sig.parameters and
|
84
|
-
abstract_sig.return_annotation == concrete_sig.return_annotation
|
85
|
-
)
|
86
|
-
})
|
87
|
-
|
88
|
-
analysis[method] = entry
|
89
|
-
|
90
|
-
abstract_properties = self._abstract_reflexion.getAbstractProperties()
|
91
|
-
for prop in abstract_properties:
|
92
|
-
entry = {
|
93
|
-
'implemented': False,
|
94
|
-
'abstract_signature': None,
|
95
|
-
'concrete_signature': None,
|
96
|
-
'signature_match': False,
|
97
|
-
'type' : 'property'
|
98
|
-
}
|
99
|
-
|
100
|
-
if hasattr(self._instance, prop):
|
101
|
-
entry['implemented'] = True
|
102
|
-
abstract_sig = self._abstract_reflexion.getPropertySignature(prop)
|
103
|
-
concrete_sig = self._concrete_reflexion.getPropertySignature(prop)
|
104
|
-
|
105
|
-
entry.update({
|
106
|
-
'abstract_signature': abstract_sig,
|
107
|
-
'concrete_signature': concrete_sig,
|
108
|
-
'signature_match': (
|
109
|
-
abstract_sig.parameters == concrete_sig.parameters and
|
110
|
-
abstract_sig.return_annotation == concrete_sig.return_annotation
|
111
|
-
)
|
112
|
-
})
|
113
|
-
|
114
|
-
analysis[prop] = entry
|
115
|
-
|
116
|
-
return analysis
|
117
|
-
|
118
|
-
def getNonInheritedImplementation(self) -> Dict[str, Any]:
|
119
|
-
"""Get implementation details for methods, properties, and attributes not inherited from other parents.
|
120
|
-
|
121
|
-
Returns
|
122
|
-
-------
|
123
|
-
Dict[str, Any]
|
124
|
-
Dictionary containing:
|
125
|
-
- 'methods': List of non-inherited method names
|
126
|
-
- 'properties': List of non-inherited property names
|
127
|
-
- 'attributes': Dict of non-inherited attributes
|
128
|
-
"""
|
129
|
-
# Get all members from concrete class (non-inherited methods, properties, and attributes)
|
130
|
-
concrete_members = set(dir(self._instance.__class__))
|
131
|
-
|
132
|
-
# Get members from the abstract class (base class)
|
133
|
-
base_members = set(dir(self._abstract))
|
134
|
-
|
135
|
-
# Filter out inherited members (methods, properties, and attributes)
|
136
|
-
non_inherited_methods = [
|
137
|
-
name for name in concrete_members
|
138
|
-
if callable(getattr(self._instance.__class__, name)) and name not in base_members
|
139
|
-
]
|
140
|
-
|
141
|
-
non_inherited_properties = [
|
142
|
-
name for name in concrete_members
|
143
|
-
if isinstance(getattr(self._instance.__class__, name, None), property) and name not in base_members
|
144
|
-
]
|
145
|
-
|
146
|
-
non_inherited_attributes = {
|
147
|
-
name: getattr(self._instance.__class__, name)
|
148
|
-
for name in concrete_members
|
149
|
-
if not callable(getattr(self._instance.__class__, name)) and not isinstance(getattr(self._instance.__class__, name, None), property) and name not in base_members
|
150
|
-
}
|
151
|
-
|
152
|
-
return {
|
153
|
-
'methods': non_inherited_methods,
|
154
|
-
'properties': non_inherited_properties,
|
155
|
-
'attributes': non_inherited_attributes
|
156
|
-
}
|
157
|
-
|
158
|
-
def validateImplementation(self) -> Tuple[bool, Dict[str, List[str]]]:
|
159
|
-
"""Validate the implementation against the abstract base.
|
160
|
-
|
161
|
-
Returns
|
162
|
-
-------
|
163
|
-
Tuple[bool, Dict[str, List[str]]]
|
164
|
-
- First element: True if fully valid implementation
|
165
|
-
- Second element: Dictionary of issues by category:
|
166
|
-
* 'missing': Missing required methods
|
167
|
-
* 'signature_mismatch': Methods with signature mismatches
|
168
|
-
* 'type_mismatch': Methods with return type mismatches
|
169
|
-
"""
|
170
|
-
issues = {
|
171
|
-
'missing': [],
|
172
|
-
'signature_mismatch': [],
|
173
|
-
'type_mismatch': []
|
174
|
-
}
|
175
|
-
|
176
|
-
analysis = self.getImplementationAnalysis()
|
177
|
-
for method, data in analysis.items():
|
178
|
-
if not data['implemented']:
|
179
|
-
issues['missing'].append(method)
|
180
|
-
elif not data['signature_match']:
|
181
|
-
issues['signature_mismatch'].append(method)
|
182
|
-
# Check specifically for return type mismatch
|
183
|
-
abstract_return = data['abstract_signature'].return_annotation
|
184
|
-
concrete_return = data['concrete_signature'].return_annotation
|
185
|
-
if abstract_return != concrete_return and abstract_return is not inspect.Parameter.empty:
|
186
|
-
issues['type_mismatch'].append(method)
|
187
|
-
|
188
|
-
is_valid = not any(issues.values())
|
189
|
-
return (is_valid, issues)
|
190
|
-
|
191
|
-
def getHierarchyAnalysis(self) -> Dict[str, List[str]]:
|
192
|
-
"""Analyze the class hierarchy relationships.
|
193
|
-
|
194
|
-
Returns
|
195
|
-
-------
|
196
|
-
Dict[str, List[str]]
|
197
|
-
Dictionary containing:
|
198
|
-
- 'concrete_hierarchy': List of class names in concrete hierarchy
|
199
|
-
- 'abstract_hierarchy': List of class names in abstract hierarchy
|
200
|
-
- 'common_ancestors': List of common ancestor class names
|
201
|
-
"""
|
202
|
-
concrete_hierarchy = [cls.__name__ for cls in inspect.getmro(self._instance.__class__)]
|
203
|
-
abstract_hierarchy = [cls.__name__ for cls in inspect.getmro(self._abstract)]
|
204
|
-
|
205
|
-
concrete_bases = set(inspect.getmro(self._instance.__class__))
|
206
|
-
abstract_bases = set(inspect.getmro(self._abstract))
|
207
|
-
common = concrete_bases & abstract_bases - {self._abstract, object}
|
208
|
-
|
209
|
-
return {
|
210
|
-
'concrete_hierarchy': concrete_hierarchy,
|
211
|
-
'abstract_hierarchy': abstract_hierarchy,
|
212
|
-
'common_ancestors': [cls.__name__ for cls in common]
|
213
|
-
}
|
214
|
-
|
215
|
-
def getImplementationCoverage(self) -> float:
|
216
|
-
"""Calculate the percentage of abstract methods implemented.
|
217
|
-
|
218
|
-
Returns
|
219
|
-
-------
|
220
|
-
float
|
221
|
-
Implementation coverage percentage (0.0 to 1.0)
|
222
|
-
"""
|
223
|
-
attr = self.getImplementationAnalysis()
|
224
|
-
attr_len = len(attr) * 2
|
225
|
-
attr_implemented = 0
|
226
|
-
for method in attr.values():
|
227
|
-
if method.get('implemented'):
|
228
|
-
attr_implemented += 2 if method.get('signature_match') else 1
|
229
|
-
|
230
|
-
return attr_implemented / attr_len if attr_len > 0 else 0.0
|