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.
Files changed (66) hide show
  1. orionis/metadata/framework.py +1 -1
  2. orionis/services/introspection/modules/{reflection_instance.py → reflection_module.py} +1 -1
  3. orionis/services/introspection/reflection.py +90 -0
  4. orionis/{services → support}/standard/std.py +2 -2
  5. orionis/test/{facade/test_suite.py → test_suite.py} +1 -2
  6. orionis/unittesting.py +1 -1
  7. {orionis-0.304.0.dist-info → orionis-0.306.0.dist-info}/METADATA +1 -1
  8. {orionis-0.304.0.dist-info → orionis-0.306.0.dist-info}/RECORD +28 -65
  9. tests/{services → support}/standard/test_services_std.py +3 -3
  10. tests/{services → support}/wrapper/test_services_wrapper_docdict.py +2 -2
  11. orionis/support/abstracts/entities/abstract_class_attributes.py +0 -37
  12. orionis/support/abstracts/reflect_abstract.py +0 -556
  13. orionis/support/helpers/functions.py +0 -285
  14. orionis/support/introspection/container_integrity.py +0 -292
  15. orionis/support/introspection/contracts/__init__.py +0 -0
  16. orionis/support/introspection/contracts/reflection.py +0 -187
  17. orionis/support/introspection/contracts/reflexion_abstract.py +0 -264
  18. orionis/support/introspection/helpers/__init__.py +0 -0
  19. orionis/support/introspection/helpers/functions.py +0 -281
  20. orionis/support/introspection/instances/__init__.py +0 -0
  21. orionis/support/introspection/instances/contracts/__init__.py +0 -0
  22. orionis/support/introspection/instances/contracts/reflection_instance.py +0 -649
  23. orionis/support/introspection/instances/entities/__init__.py +0 -0
  24. orionis/support/introspection/instances/reflection_instance.py +0 -758
  25. orionis/support/introspection/reflect_decorators.py +0 -335
  26. orionis/support/introspection/reflection.py +0 -216
  27. orionis/support/introspection/reflexion_concrete.py +0 -276
  28. orionis/support/introspection/reflexion_concrete_with_abstract.py +0 -185
  29. orionis/support/introspection/reflexion_instance_with_abstract.py +0 -230
  30. orionis/support/introspection/reflexion_module.py +0 -19
  31. orionis/support/introspection/reflexion_module_with_classname.py +0 -22
  32. orionis/support/reflection.py +0 -216
  33. orionis/test/facade/__init__.py +0 -0
  34. orionis/test/facade/contracts/__init__.py +0 -0
  35. orionis/test/facade/contracts/test_suite.py +0 -25
  36. tests/services/standard/__init__.py +0 -0
  37. tests/services/wrapper/__init__.py +0 -0
  38. tests/support/inspection/__init__.py +0 -0
  39. tests/support/inspection/fakes/__init__.py +0 -0
  40. tests/support/inspection/fakes/fake_reflect_abstract.py +0 -276
  41. tests/support/inspection/fakes/fake_reflection_concrete.py +0 -44
  42. tests/support/inspection/fakes/fake_reflection_concrete_with_abstract.py +0 -78
  43. tests/support/inspection/fakes/fake_reflection_instance_with_abstract.py +0 -45
  44. tests/support/inspection/test_reflect_abstract.py +0 -334
  45. tests/support/inspection/test_reflect_instance.py +0 -288
  46. tests/support/inspection/test_reflection_concrete.py +0 -142
  47. tests/support/inspection/test_reflection_concrete_with_abstract.py +0 -87
  48. tests/support/inspection/test_reflection_instance_with_abstract.py +0 -79
  49. /orionis/services/introspection/modules/contracts/{reflection_instance.py → reflection_module.py} +0 -0
  50. /orionis/{services → support}/standard/__init__.py +0 -0
  51. /orionis/{services → support}/standard/contracts/__init__.py +0 -0
  52. /orionis/{services → support}/standard/contracts/std.py +0 -0
  53. /orionis/{services → support}/standard/exceptions/__init__.py +0 -0
  54. /orionis/{services → support}/standard/exceptions/std_value_exception.py +0 -0
  55. /orionis/{services → support}/wrapper/__init__.py +0 -0
  56. /orionis/{services → support}/wrapper/dicts/__init__.py +0 -0
  57. /orionis/{services → support}/wrapper/dicts/dot_dict.py +0 -0
  58. {orionis-0.304.0.dist-info → orionis-0.306.0.dist-info}/WHEEL +0 -0
  59. {orionis-0.304.0.dist-info → orionis-0.306.0.dist-info}/licenses/LICENCE +0 -0
  60. {orionis-0.304.0.dist-info → orionis-0.306.0.dist-info}/top_level.txt +0 -0
  61. {orionis-0.304.0.dist-info → orionis-0.306.0.dist-info}/zip-safe +0 -0
  62. {orionis/support/abstracts → tests/services/inspection/reflection}/__init__.py +0 -0
  63. {orionis/support/abstracts/entities → tests/services/inspection/reflection/mock}/__init__.py +0 -0
  64. /tests/{support/inspection/fakes → services/inspection/reflection/mock}/fake_reflect_instance.py +0 -0
  65. {orionis/support/helpers → tests/support/standard}/__init__.py +0 -0
  66. {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