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,556 +0,0 @@
1
- import abc
2
- import ast
3
- import inspect
4
- import types
5
- from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type, TypeVar
6
- from orionis.services.introspection.abstracts.entities.abstract_class_attributes import AbstractClassAttributes
7
-
8
- ABC = TypeVar('ABC', bound=abc.ABC)
9
-
10
- class ReflexionAbstract:
11
- """A reflection object encapsulating an abstract class.
12
-
13
- Parameters
14
- ----------
15
- abstract : Type[ABC]
16
- The abstract class being reflected upon
17
-
18
- Attributes
19
- ----------
20
- _abstract : Type[ABC]
21
- The encapsulated abstract class
22
- """
23
-
24
- def __init__(self, abstract: Type[ABC]) -> None:
25
- """Initialize with the abstract class."""
26
- self._abstract = abstract
27
-
28
- def parse(self) -> None:
29
- pass
30
-
31
- def getClassName(self) -> str:
32
- """
33
- Get the name of the abstract class.
34
-
35
- Returns
36
- -------
37
- str
38
- The name of the abstract class
39
- """
40
- return self._abstract.__name__
41
-
42
- def getClass(self) -> RuntimeError:
43
- """
44
- Retrieve the class of the abstract base class.
45
- This method is intended to be overridden in subclasses to provide
46
- the actual abstract class. By default, it raises a RuntimeError
47
- since abstract classes cannot be instantiated directly.
48
- The abstract base class itself.
49
- Raises
50
- ------
51
- RuntimeError
52
- If called directly on the abstract class.
53
- """
54
- raise RuntimeError("Cannot instantiate an abstract class.")
55
-
56
- def getModuleName(self) -> str:
57
- """
58
- Get the name of the module where the abstract class is defined.
59
-
60
- Returns
61
- -------
62
- str
63
- The module name
64
- """
65
- return self._abstract.__module__
66
-
67
- def getAllAttributes(self) -> AbstractClassAttributes:
68
- """
69
- Get all attributes of the abstract class.
70
-
71
- Returns
72
- -------
73
- Dict[str, Any]
74
- Dictionary of attribute names and their values
75
- """
76
- attributes = {
77
- name: value for name, value in vars(self._abstract).items()
78
- if not callable(value) and not isinstance(value, (staticmethod, classmethod, property))
79
- and not isinstance(value, types.MemberDescriptorType)
80
- }
81
- class_name = self.getClassName()
82
- public = {}
83
- private = {}
84
- protected = {}
85
-
86
- for attr, value in attributes.items():
87
- if (str(attr).startswith("__") and str(attr).endswith("__")) or str(attr).startswith("_abc_"):
88
- continue
89
- if str(attr).startswith("_") and not str(attr).startswith("__") and not str(attr).startswith(f"_{class_name}"):
90
- protected[attr] = value
91
- elif str(attr).startswith(f"_{class_name}"):
92
- private[str(attr).replace(f"_{class_name}", "")] = value
93
- else:
94
- public[attr] = value
95
-
96
- return AbstractClassAttributes(
97
- public=public,
98
- private=private,
99
- protected=protected
100
- )
101
-
102
- def getAttributes(self) -> Dict[str, Any]:
103
- """
104
- Get all attributes of the instance.
105
-
106
- Returns
107
- -------
108
- Dict[str, Any]
109
- Dictionary of attribute names and their values
110
- """
111
- attr = self.getAllAttributes()
112
- return {**attr.public, **attr.private, **attr.protected}
113
-
114
- def getPublicAttributes(self) -> Dict[str, Any]:
115
- """
116
- Get all public attributes of the instance.
117
-
118
- Returns
119
- -------
120
- Dict[str, Any]
121
- Dictionary of public attribute names and their values
122
- """
123
- attr = self.getAllAttributes()
124
- return attr.public
125
-
126
- def getPrivateAttributes(self) -> Dict[str, Any]:
127
- """
128
- Get all private attributes of the instance.
129
-
130
- Returns
131
- -------
132
- Dict[str, Any]
133
- Dictionary of private attribute names and their values
134
- """
135
- attr = self.getAllAttributes()
136
- return attr.private
137
-
138
- def getProtectedAttributes(self) -> Dict[str, Any]:
139
- """
140
- Get all Protected attributes of the instance.
141
-
142
- Returns
143
- -------
144
- Dict[str, Any]
145
- Dictionary of Protected attribute names and their values
146
- """
147
- attr = self.getAllAttributes()
148
- return attr.protected
149
-
150
- def getAllMethods(self) -> Dict[str, List[str]]:
151
- """
152
- Categorize all methods and relevant members of the abstract class into public, private, protected,
153
- static, asynchronous, synchronous, class methods, magic methods, abstract methods, and properties.
154
-
155
- Returns
156
- -------
157
- Dict[str, List[str]]
158
- A dictionary categorizing methods and attributes into various types.
159
- """
160
- class_name = self.getClassName()
161
- private_prefix = f"_{class_name}"
162
- attributes = set(self.getAttributes().keys()) | {attr for attr in dir(self._abstract) if attr.startswith('_abc_')}
163
-
164
- result = {
165
- "public": [],
166
- "private": [],
167
- "protected": [],
168
- "static": [],
169
- "asynchronous": [],
170
- "synchronous": [],
171
- "class_methods": [],
172
- "asynchronous_static": [],
173
- "synchronous_static": [],
174
- "magic": [],
175
- "abstract": [],
176
- "abstract_class_methods": [],
177
- "abstract_static_methods": []
178
- }
179
-
180
- # Precompute all members once
181
- members = inspect.getmembers(self._abstract)
182
- static_attrs = {}
183
-
184
- # First pass to collect all relevant information
185
- for name, attr in members:
186
- if name in attributes:
187
- continue
188
-
189
- # Get static attribute once
190
- static_attr = inspect.getattr_static(self._abstract, name)
191
- static_attrs[name] = static_attr
192
-
193
- # Magic methods
194
- if name.startswith("__") and name.endswith("__"):
195
- result["magic"].append(name)
196
- continue
197
-
198
- # Static and class methods
199
- if isinstance(static_attr, staticmethod):
200
- result["static"].append(name)
201
- elif isinstance(static_attr, classmethod):
202
- result["class_methods"].append(name)
203
-
204
- # Private, protected, public
205
- if name.startswith(private_prefix):
206
- clean_name = name.replace(private_prefix, "")
207
- result["private"].append(clean_name)
208
- elif name.startswith("_"):
209
- result["protected"].append(name)
210
- else:
211
- result["public"].append(name)
212
-
213
- # Async methods
214
- if inspect.iscoroutinefunction(attr):
215
- clean_name = name.replace(private_prefix, "")
216
- if name in result["static"]:
217
- result["asynchronous_static"].append(clean_name)
218
- else:
219
- result["asynchronous"].append(clean_name)
220
-
221
- # Second pass for synchronous methods (needs info from first pass)
222
- for name, attr in members:
223
- if name in attributes or name in result["magic"] or name in result["class_methods"] or name in result["static"]:
224
- continue
225
-
226
- if inspect.isfunction(attr):
227
- clean_name = name.replace(private_prefix, "")
228
- if clean_name not in result["asynchronous"]:
229
- result["synchronous"].append(clean_name)
230
-
231
- # Synchronous static methods
232
- for name in result["static"]:
233
- if name not in attributes and name not in result["asynchronous_static"] and name not in result["class_methods"]:
234
- result["synchronous_static"].append(name)
235
-
236
- # Abstract methods
237
- abstract_methods = getattr(self._abstract, "__abstractmethods__", set())
238
- for name in abstract_methods:
239
- if name in attributes:
240
- continue
241
-
242
- static_attr = static_attrs.get(name, inspect.getattr_static(self._abstract, name))
243
- if isinstance(static_attr, staticmethod):
244
- result["abstract_static_methods"].append(name)
245
- elif isinstance(static_attr, classmethod):
246
- result["abstract_class_methods"].append(name)
247
- elif not isinstance(static_attr, property):
248
- result["abstract"].append(name)
249
-
250
- return result
251
-
252
-
253
-
254
-
255
-
256
-
257
-
258
-
259
-
260
-
261
-
262
-
263
-
264
- def getAbstractProperties(self) -> Set[str]:
265
- """Get all abstract property names required by the class.
266
-
267
- Returns
268
- -------
269
- Set[str]
270
- Set of abstract property names
271
- """
272
- properties = []
273
- for name in getattr(self._abstract, '__abstractmethods__', set()):
274
- attr = getattr(self._abstract, name, None)
275
- if isinstance(attr, property):
276
- properties.append(name)
277
- return set(properties)
278
-
279
- def getConcreteMethods(self) -> Dict[str, Callable]:
280
- """Get all concrete methods implemented in the abstract class.
281
-
282
- Returns
283
- -------
284
- Dict[str, Callable]
285
- Dictionary of method names and their implementations
286
- """
287
- return {
288
- name: member for name, member in inspect.getmembers(
289
- self._abstract,
290
- predicate=inspect.isfunction
291
- ) if not name.startswith('_') and name not in self.getAbstractMethods()
292
- }
293
-
294
- def getStaticMethods(self) -> List[str]:
295
- """Get all static method names of the abstract class.
296
-
297
- Returns
298
- -------
299
- List[str]
300
- List of static method names
301
- """
302
- return [
303
- name for name in dir( self._abstract)
304
- if not name.startswith('_') and
305
- isinstance(inspect.getattr_static( self._abstract, name), staticmethod)
306
- ]
307
-
308
- def getClassMethods(self) -> List[str]:
309
- """Get all class method names of the abstract class.
310
-
311
- Returns
312
- -------
313
- List[str]
314
- List of class method names, excluding private/protected methods (starting with '_')
315
-
316
- Notes
317
- -----
318
- - Uses inspect.getattr_static to avoid method binding
319
- - Properly handles both @classmethod decorator and classmethod instances
320
- - Filters out private/protected methods (starting with '_')
321
-
322
- Examples
323
- --------
324
- >>> class MyAbstract(ABC):
325
- ... @classmethod
326
- ... def factory(cls): pass
327
- ... @classmethod
328
- ... def _protected_factory(cls): pass
329
- >>> reflex = ReflexionAbstract(MyAbstract)
330
- >>> reflex.getClassMethods()
331
- ['factory']
332
- """
333
- return [
334
- name for name in dir(self._abstract)
335
- if not name.startswith('_') and
336
- isinstance(
337
- inspect.getattr_static(self._abstract, name),
338
- (classmethod, types.MethodType)
339
- )
340
- ]
341
-
342
- def getProperties(self) -> List[str]:
343
- """Get all property names of the abstract class.
344
-
345
- Returns
346
- -------
347
- List[str]
348
- List of property names
349
- """
350
- return [
351
- name for name, member in inspect.getmembers(
352
- self._abstract,
353
- predicate=lambda x: isinstance(x, property))
354
- if not name.startswith('_')
355
- ]
356
-
357
- def getMethodSignature(self, methodName: str) -> inspect.Signature:
358
- """Get the signature of a method.
359
-
360
- Parameters
361
- ----------
362
- methodName : str
363
- Name of the method
364
-
365
- Returns
366
- -------
367
- inspect.Signature
368
- The method signature
369
-
370
- Raises
371
- ------
372
- AttributeError
373
- If the method doesn't exist
374
- """
375
- method = getattr(self._abstract, methodName)
376
- if callable(method):
377
- return inspect.signature(method)
378
-
379
- def getPropertySignature(self, propertyName: str) -> inspect.Signature:
380
- """Get the signature of an abstract property's getter.
381
-
382
- Parameters
383
- ----------
384
- propertyName : str
385
- Name of the abstract property
386
-
387
- Returns
388
- -------
389
- inspect.Signature
390
- The getter signature of the abstract property
391
-
392
- Raises
393
- ------
394
- AttributeError
395
- If the property doesn't exist or is not an abstract property
396
- """
397
- attr = getattr(self._abstract, propertyName, None)
398
- if isinstance(attr, property) and attr.fget is not None:
399
- return inspect.signature(attr.fget)
400
- raise AttributeError(f"{propertyName} is not an abstract property or doesn't have a getter.")
401
-
402
- def getDocstring(self) -> Optional[str]:
403
- """Get the docstring of the abstract class.
404
-
405
- Returns
406
- -------
407
- Optional[str]
408
- The class docstring
409
- """
410
- return self._abstract.__doc__
411
-
412
- def getBaseAbstractClasses(self) -> Tuple[Type[ABC], ...]:
413
- """Get the abstract base classes.
414
-
415
- Returns
416
- -------
417
- Tuple[Type[ABC], ...]
418
- Tuple of abstract base classes
419
- """
420
- return tuple(
421
- base for base in self._abstract.__bases__
422
- if inspect.isabstract(base) or issubclass(base, abc.ABC) or isinstance(base, abc.ABCMeta)
423
- )
424
-
425
- def getInterfaceMethods(self) -> Dict[str, inspect.Signature]:
426
- """Get all abstract methods with their signatures.
427
-
428
- Returns
429
- -------
430
- Dict[str, inspect.Signature]
431
- Dictionary of method names and their signatures
432
- """
433
- return {
434
- name: inspect.signature(getattr(self._abstract, name))
435
- for name in self.getAbstractMethods()
436
- }
437
-
438
- def isSubclassOf(self, abstract_class: Type[ABC]) -> bool:
439
- """Check if the abstract class inherits from another abstract class.
440
-
441
- Parameters
442
- ----------
443
- abstract_class : Type[ABC]
444
- The abstract class to check against
445
-
446
- Returns
447
- -------
448
- bool
449
- True if this is a subclass
450
- """
451
- return issubclass(self._abstract, abstract_class)
452
-
453
- def getSourceCode(self) -> Optional[str]:
454
- """Get the source code of the abstract class.
455
-
456
- Returns
457
- -------
458
- Optional[str]
459
- The source code if available
460
- """
461
- try:
462
- return inspect.getsource(self._abstract)
463
- except (TypeError, OSError):
464
- return None
465
-
466
- def getFileLocation(self) -> Optional[str]:
467
- """Get the file location where the abstract class is defined.
468
-
469
- Returns
470
- -------
471
- Optional[str]
472
- The file path if available
473
- """
474
- try:
475
- return inspect.getfile(self._abstract)
476
- except (TypeError, OSError):
477
- return None
478
-
479
- def getAnnotations(self) -> Dict[str, Any]:
480
- """Get type annotations of the abstract class.
481
-
482
- Returns
483
- -------
484
- Dict[str, Any]
485
- Dictionary of attribute names and their type annotations
486
- """
487
- return self._abstract.__annotations__
488
-
489
- def getDecorators(self, method_name: str) -> List[str]:
490
- """
491
- Get decorators applied to a method.
492
-
493
- Parameters
494
- ----------
495
- method_name : str
496
- Name of the method to inspect
497
- """
498
- method = getattr(self._abstract, method_name, None)
499
- if method is None:
500
- return []
501
-
502
- try:
503
- source = inspect.getsource(self._abstract)
504
- except (OSError, TypeError):
505
- return []
506
-
507
- tree = ast.parse(source)
508
-
509
- class DecoratorVisitor(ast.NodeVisitor):
510
- def __init__(self):
511
- self.decorators = []
512
-
513
- def visit_FunctionDef(self, node):
514
- if node.name == method_name:
515
- for deco in node.decorator_list:
516
- if isinstance(deco, ast.Name):
517
- self.decorators.append(deco.id)
518
- elif isinstance(deco, ast.Call):
519
- # handles decorators with arguments like @deco(arg)
520
- if isinstance(deco.func, ast.Name):
521
- self.decorators.append(deco.func.id)
522
- elif isinstance(deco, ast.Attribute):
523
- self.decorators.append(deco.attr)
524
- # No need to visit deeper
525
- return
526
-
527
- visitor = DecoratorVisitor()
528
- visitor.visit(tree)
529
-
530
- return visitor.decorators
531
-
532
- def isProtocol(self) -> bool:
533
- """Check if the abstract class is a Protocol.
534
-
535
- Returns
536
- -------
537
- bool
538
- True if this is a Protocol class
539
- """
540
- return hasattr(self._abstract, '_is_protocol') and self._abstract._is_protocol
541
-
542
- def getRequiredAttributes(self) -> Set[str]:
543
- """For Protocol classes, get required attributes.
544
-
545
- Returns
546
- -------
547
- Set[str]
548
- Set of required attribute names
549
- """
550
- if not self.isProtocol():
551
- return set()
552
-
553
- return {
554
- name for name in dir(self._abstract)
555
- if not name.startswith('_') and not inspect.isfunction(getattr(self._abstract, name))
556
- }