orionis 0.300.0__py3-none-any.whl → 0.302.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.
@@ -0,0 +1,1266 @@
1
+ import inspect
2
+ import keyword
3
+ from typing import List, Type
4
+ from orionis.services.introspection.abstract.contracts.reflection_abstract import IReflectionAbstract
5
+ from orionis.services.introspection.dependencies.entities.class_dependencies import ClassDependency
6
+ from orionis.services.introspection.dependencies.entities.method_dependencies import MethodDependency
7
+ from orionis.services.introspection.dependencies.reflect_dependencies import ReflectDependencies
8
+ from orionis.services.introspection.exceptions.reflection_attribute_error import ReflectionAttributeError
9
+ from orionis.services.introspection.exceptions.reflection_type_error import ReflectionTypeError
10
+ from orionis.services.introspection.exceptions.reflection_value_error import ReflectionValueError
11
+
12
+ class ReflectionAbstract(IReflectionAbstract):
13
+
14
+ def __init__(self, abstract: Type) -> None:
15
+ """
16
+ Initializes the reflection class with the provided abstract base class (interface).
17
+
18
+ Parameters
19
+ ----------
20
+ abstract : Type
21
+ The abstract base class (interface) to be reflected upon.
22
+
23
+ Raises
24
+ ------
25
+ ReflectionTypeError
26
+ If 'abstract' is not a class type.
27
+ ReflectionTypeError
28
+ If 'abstract' is not an abstract base class (interface).
29
+ """
30
+
31
+ # Check if the provided abstract is a class type
32
+ if not isinstance(abstract, type):
33
+ raise ReflectionTypeError(f"Expected a class type for 'abstract', got {type(abstract).__name__!r}")
34
+
35
+ # Check if it's an abstract base class (interface)
36
+ if not bool(getattr(abstract, '__abstractmethods__', False)):
37
+ raise ReflectionTypeError(f"Provided class '{abstract.__name__}' is not an interface (abstract base class)")
38
+
39
+ self.__abstract = abstract
40
+
41
+ def getClass(self) -> Type:
42
+ """
43
+ Returns the class type that this reflection concrete is based on.
44
+
45
+ Returns
46
+ -------
47
+ Type
48
+ The class type provided during initialization.
49
+ """
50
+ return self.__abstract
51
+
52
+ def getClassName(self) -> str:
53
+ """
54
+ Returns the name of the class type.
55
+
56
+ Returns
57
+ -------
58
+ str
59
+ The name of the class type.
60
+ """
61
+ return self.__abstract.__name__
62
+
63
+ def getModuleName(self) -> str:
64
+ """
65
+ Returns the name of the module where the class is defined.
66
+
67
+ Returns
68
+ -------
69
+ str
70
+ The name of the module.
71
+ """
72
+ return self.__abstract.__module__
73
+
74
+ def getModuleWithClassName(self) -> str:
75
+ """
76
+ Returns the module name concatenated with the class name.
77
+
78
+ Returns
79
+ -------
80
+ str
81
+ The module name followed by the class name.
82
+ """
83
+ return f"{self.getModuleName()}.{self.getClassName()}"
84
+
85
+ def getDocstring(self) -> str:
86
+ """
87
+ Returns the docstring of the class.
88
+
89
+ Returns
90
+ -------
91
+ str or None
92
+ The docstring of the class, or None if not defined.
93
+ """
94
+ return self.__abstract.__doc__ if self.__abstract.__doc__ else None
95
+
96
+ def getBaseClasses(self) -> list:
97
+ """
98
+ Returns a list of base classes of the reflected class.
99
+
100
+ Returns
101
+ -------
102
+ list
103
+ A list of base classes.
104
+ """
105
+ return self.__abstract.__bases__
106
+
107
+ def getSourceCode(self) -> str:
108
+ """
109
+ Returns the source code of the class.
110
+
111
+ Returns
112
+ -------
113
+ str
114
+ The source code of the class.
115
+
116
+ Raises
117
+ ------
118
+ ReflectionValueError
119
+ If the source code cannot be retrieved.
120
+ """
121
+ try:
122
+ return inspect.getsource(self.__abstract)
123
+ except OSError as e:
124
+ raise ReflectionValueError(f"Could not retrieve source code for '{self.__abstract.__name__}': {e}")
125
+
126
+ def getFile(self) -> str:
127
+ """
128
+ Returns the file path where the class is defined.
129
+
130
+ Returns
131
+ -------
132
+ str
133
+ The file path of the class definition.
134
+
135
+ Raises
136
+ ------
137
+ ReflectionValueError
138
+ If the file path cannot be retrieved.
139
+ """
140
+ try:
141
+ return inspect.getfile(self.__abstract)
142
+ except TypeError as e:
143
+ raise ReflectionValueError(f"Could not retrieve file for '{self.__abstract.__name__}': {e}")
144
+
145
+ def getAnnotations(self) -> dict:
146
+ """
147
+ Returns the type annotations of the class.
148
+
149
+ Returns
150
+ -------
151
+ dict
152
+ A dictionary of type annotations.
153
+ """
154
+ annotations = {}
155
+ for k, v in getattr(self.__abstract, '__annotations__', {}).items():
156
+ annotations[str(k).replace(f"_{self.getClassName()}", "")] = v
157
+ return annotations
158
+
159
+ def hasAttribute(self, attribute: str) -> bool:
160
+ """
161
+ Checks if the class has a specific attribute.
162
+
163
+ Parameters
164
+ ----------
165
+ attribute : str
166
+ The name of the attribute to check.
167
+
168
+ Returns
169
+ -------
170
+ bool
171
+ True if the class has the specified attribute, False otherwise.
172
+ """
173
+ return attribute in self.getAttributes()
174
+
175
+ def getAttribute(self, attribute: str):
176
+ """
177
+ Returns the value of a specific class attribute.
178
+
179
+ Parameters
180
+ ----------
181
+ attribute : str
182
+ The name of the attribute to retrieve.
183
+
184
+ Returns
185
+ -------
186
+ Any
187
+ The value of the specified class attribute.
188
+
189
+ Raises
190
+ ------
191
+ ReflectionValueError
192
+ If the attribute does not exist or is not accessible.
193
+ """
194
+ attrs = self.getAttributes()
195
+ return attrs.get(attribute, None)
196
+
197
+ def setAttribute(self, name: str, value) -> bool:
198
+ """
199
+ Set an attribute value.
200
+
201
+ Parameters
202
+ ----------
203
+ name : str
204
+ The attribute name
205
+ value : Any
206
+ The value to set
207
+
208
+ Raises
209
+ ------
210
+ ReflectionValueError
211
+ If the attribute is read-only or invalid
212
+ """
213
+
214
+ # Ensure the name is a valid attr name with regular expression
215
+ if not isinstance(name, str) or not name.isidentifier() or keyword.iskeyword(name):
216
+ raise ReflectionValueError(f"Invalid attribute name '{name}'. Must be a valid Python identifier and not a keyword.")
217
+
218
+ # Ensure the value is not callable
219
+ if callable(value):
220
+ raise ReflectionValueError(f"Cannot set attribute '{name}' to a callable. Use setMethod instead.")
221
+
222
+ # Handle private attribute name mangling
223
+ if name.startswith("__") and not name.endswith("__"):
224
+ class_name = self.getClassName()
225
+ name = f"_{class_name}{name}"
226
+
227
+ # Set the attribute on the class itself
228
+ setattr(self.__abstract, name, value)
229
+
230
+ return True
231
+
232
+ def removeAttribute(self, name: str) -> bool:
233
+ """
234
+ Remove an attribute from the class.
235
+
236
+ Parameters
237
+ ----------
238
+ name : str
239
+ The name of the attribute to remove.
240
+
241
+ Raises
242
+ ------
243
+ ReflectionValueError
244
+ If the attribute does not exist or cannot be removed.
245
+ """
246
+ if not self.hasAttribute(name):
247
+ raise ReflectionValueError(f"Attribute '{name}' does not exist in class '{self.getClassName()}'.")
248
+
249
+ # Handle private attribute name mangling
250
+ if name.startswith("__") and not name.endswith("__"):
251
+ class_name = self.getClassName()
252
+ name = f"_{class_name}{name}"
253
+
254
+ delattr(self.__abstract, name)
255
+
256
+ return True
257
+
258
+ def getAttributes(self) -> dict:
259
+ """
260
+ Returns a dictionary of all class attributes (not instance attributes).
261
+
262
+ Parameters
263
+ ----------
264
+ None
265
+
266
+ Returns
267
+ -------
268
+ dict
269
+ A dictionary where keys are the names of class attributes and values are their corresponding values.
270
+ Only attributes that are not callable, not static/class methods, not properties, and do not start with
271
+ underscores (including dunder, protected, or private) are included.
272
+ """
273
+ return {
274
+ **self.getPublicAttributes(),
275
+ **self.getProtectedAttributes(),
276
+ **self.getPrivateAttributes(),
277
+ **self.getDunderAttributes()
278
+ }
279
+
280
+ def getPublicAttributes(self) -> dict:
281
+ """
282
+ Returns a dictionary of public class attributes (not instance attributes).
283
+
284
+ Parameters
285
+ ----------
286
+ None
287
+
288
+ Returns
289
+ -------
290
+ dict
291
+ A dictionary where keys are the names of public class attributes and values are their corresponding values.
292
+ Only attributes that are not callable, not static/class methods, not properties, and do not start with
293
+ underscores (including dunder, protected, or private) are included.
294
+ """
295
+ class_name = self.getClassName()
296
+ attributes = self.__abstract.__dict__
297
+ public = {}
298
+
299
+ # Exclude dunder, protected, and private attributes
300
+ for attr, value in attributes.items():
301
+ if callable(value) or isinstance(value, staticmethod) or isinstance(value, classmethod) or isinstance(value, property):
302
+ continue
303
+ if attr.startswith("__") and attr.endswith("__"):
304
+ continue
305
+ if attr.startswith(f"_{class_name}"):
306
+ continue
307
+ if attr.startswith("_"):
308
+ continue
309
+ public[attr] = value
310
+
311
+ return public
312
+
313
+ def getProtectedAttributes(self) -> dict:
314
+ """
315
+ Returns a dictionary of protected class attributes (not instance attributes).
316
+
317
+ Parameters
318
+ ----------
319
+ None
320
+
321
+ Returns
322
+ -------
323
+ dict
324
+ A dictionary where keys are the names of protected class attributes and values are their corresponding values.
325
+ Only attributes that are not callable, not static/class methods, not properties, and start with a single underscore
326
+ (indicating protected visibility) are included.
327
+ """
328
+ class_name = self.getClassName()
329
+ attributes = self.__abstract.__dict__
330
+ protected = {}
331
+
332
+ # Exclude dunder, public, and private attributes
333
+ for attr, value in attributes.items():
334
+ if callable(value) or isinstance(value, staticmethod) or isinstance(value, classmethod) or isinstance(value, property):
335
+ continue
336
+ if attr.startswith("__") and attr.endswith("__"):
337
+ continue
338
+ if attr.startswith(f"_{class_name}"):
339
+ continue
340
+ if not attr.startswith("_"):
341
+ continue
342
+ if attr.startswith("_abc_"):
343
+ continue
344
+ protected[attr] = value
345
+
346
+ return protected
347
+
348
+ def getPrivateAttributes(self) -> dict:
349
+ """
350
+ Returns a dictionary of private class attributes (not instance attributes).
351
+
352
+ Parameters
353
+ ----------
354
+ None
355
+
356
+ Returns
357
+ -------
358
+ dict
359
+ A dictionary where keys are the names of private class attributes and values are their corresponding values.
360
+ Only attributes that are not callable, not static/class methods, not properties, and start with double underscores
361
+ (indicating private visibility) are included.
362
+ """
363
+ class_name = self.getClassName()
364
+ attributes = self.__abstract.__dict__
365
+ private = {}
366
+
367
+ # Exclude dunder, public, and protected attributes
368
+ for attr, value in attributes.items():
369
+ if callable(value) or isinstance(value, staticmethod) or isinstance(value, classmethod) or isinstance(value, property):
370
+ continue
371
+ if attr.startswith(f"_{class_name}"):
372
+ private[str(attr).replace(f"_{class_name}", "")] = value
373
+
374
+ return private
375
+
376
+ def getDunderAttributes(self) -> dict:
377
+ """
378
+ Returns a dictionary of dunder (double underscore) class attributes (not instance attributes).
379
+
380
+ Parameters
381
+ ----------
382
+ None
383
+
384
+ Returns
385
+ -------
386
+ dict
387
+ A dictionary where keys are the names of dunder class attributes and values are their corresponding values.
388
+ Only attributes that are not callable, not static/class methods, not properties, and start with double underscores
389
+ (indicating dunder visibility) are included.
390
+ """
391
+ attributes = self.__abstract.__dict__
392
+ dunder = {}
393
+ exclude = [
394
+ "__class__", "__delattr__", "__dir__", "__doc__", "__eq__", "__format__", "__ge__", "__getattribute__",
395
+ "__gt__", "__hash__", "__init__", "__init_subclass__", "__le__", "__lt__", "__module__", "__ne__",
396
+ "__new__", "__reduce__", "__reduce_ex__", "__repr__", "__setattr__", "__sizeof__", "__str__",
397
+ "__subclasshook__", "__firstlineno__", "__annotations__", "__static_attributes__", "__dict__",
398
+ "__weakref__", "__slots__", "__mro__", "__subclasses__", "__bases__", "__base__", "__flags__",
399
+ "__abstractmethods__", "__code__", "__defaults__", "__kwdefaults__", "__closure__"
400
+ ]
401
+
402
+ # Exclude public, protected, and private attributes
403
+ for attr, value in attributes.items():
404
+ if callable(value) or isinstance(value, staticmethod) or isinstance(value, classmethod) or isinstance(value, property) or not attr.startswith("__"):
405
+ continue
406
+ if attr in exclude:
407
+ continue
408
+ if attr.startswith("__") and attr.endswith("__"):
409
+ dunder[attr] = value
410
+
411
+ return dunder
412
+
413
+ def getMagicAttributes(self) -> dict:
414
+ """
415
+ Returns a dictionary of magic (dunder) class attributes (not instance attributes).
416
+
417
+ Parameters
418
+ ----------
419
+ None
420
+
421
+ Returns
422
+ -------
423
+ dict
424
+ A dictionary where keys are the names of magic class attributes and values are their corresponding values.
425
+ Only attributes that are not callable, not static/class methods, not properties, and start with double underscores
426
+ (indicating magic visibility) are included.
427
+ """
428
+ return self.getDunderAttributes()
429
+
430
+ def hasMethod(self, name: str) -> bool:
431
+ """
432
+ Check if the instance has a specific method.
433
+
434
+ Parameters
435
+ ----------
436
+ name : str
437
+ The method name to check
438
+
439
+ Returns
440
+ -------
441
+ bool
442
+ True if the method exists, False otherwise
443
+ """
444
+ return name in self.getMethods()
445
+
446
+ def removeMethod(self, name: str) -> bool:
447
+ """
448
+ Remove a method from the class.
449
+
450
+ Parameters
451
+ ----------
452
+ name : str
453
+ The method name to remove
454
+
455
+ Raises
456
+ ------
457
+ ReflectionValueError
458
+ If the method does not exist or cannot be removed.
459
+ """
460
+ if not self.hasMethod(name):
461
+ raise ReflectionValueError(f"Method '{name}' does not exist in class '{self.getClassName()}'.")
462
+
463
+ # Handle private method name mangling
464
+ if name.startswith("__") and not name.endswith("__"):
465
+ class_name = self.getClassName()
466
+ name = f"_{class_name}{name}"
467
+
468
+ # Delete the method from the class itself
469
+ delattr(self.__abstract, name)
470
+
471
+ # Return True to indicate successful removal
472
+ return True
473
+
474
+ def getMethodSignature(self, name: str) -> inspect.Signature:
475
+ """
476
+ Get the signature of a method.
477
+
478
+ Parameters
479
+ ----------
480
+ name : str
481
+ The method name to get the signature for
482
+
483
+ Returns
484
+ -------
485
+ str
486
+ The signature of the method
487
+
488
+ Raises
489
+ ------
490
+ ReflectionValueError
491
+ If the method does not exist or is not callable.
492
+ """
493
+ if not self.hasMethod(name):
494
+ raise ReflectionValueError(f"Method '{name}' does not exist in class '{self.getClassName()}'.")
495
+
496
+ # Extract the method from the class if instance is not initialized
497
+ method = getattr(self.__abstract, name, None)
498
+
499
+ if not callable(method):
500
+ raise ReflectionValueError(f"'{name}' is not callable in class '{self.getClassName()}'.")
501
+
502
+ # Get the signature of the method
503
+ return inspect.signature(method)
504
+
505
+ def getMethods(self) -> List[str]:
506
+ """
507
+ Get all method names of the instance.
508
+
509
+ Returns
510
+ -------
511
+ List[str]
512
+ List of method names
513
+ """
514
+ return [
515
+ *self.getPublicMethods(),
516
+ *self.getProtectedMethods(),
517
+ *self.getPrivateMethods(),
518
+ *self.getPublicClassMethods(),
519
+ *self.getProtectedClassMethods(),
520
+ *self.getPrivateClassMethods(),
521
+ *self.getPublicStaticMethods(),
522
+ *self.getProtectedStaticMethods(),
523
+ *self.getPrivateStaticMethods(),
524
+ ]
525
+
526
+ def getPublicMethods(self) -> list:
527
+ """
528
+ Returns a list of public class methods (not instance methods).
529
+
530
+ Parameters
531
+ ----------
532
+ None
533
+
534
+ Returns
535
+ -------
536
+ dict
537
+ A list where each element is the name of a public class method.
538
+ """
539
+ class_name = self.getClassName()
540
+ attributes = self.__abstract.__dict__
541
+ public_methods = []
542
+
543
+ # Exclude dunder, protected, private attributes and properties
544
+ for attr, value in attributes.items():
545
+ if callable(value) and not isinstance(value, (staticmethod, classmethod)) and not isinstance(value, property):
546
+ if attr.startswith("__") and attr.endswith("__"):
547
+ continue
548
+ if attr.startswith(f"_{class_name}"):
549
+ continue
550
+ if attr.startswith("_"):
551
+ continue
552
+ public_methods.append(attr)
553
+
554
+ return public_methods
555
+
556
+ def getPublicSyncMethods(self) -> list:
557
+ """
558
+ Get all public synchronous method names of the class.
559
+
560
+ Returns
561
+ -------
562
+ list
563
+ List of public synchronous method names
564
+ """
565
+ methods = self.getPublicMethods()
566
+ sync_methods = []
567
+ for method in methods:
568
+ if not inspect.iscoroutinefunction(getattr(self.__abstract, method)):
569
+ sync_methods.append(method)
570
+ return sync_methods
571
+
572
+ def getPublicAsyncMethods(self) -> list:
573
+ """
574
+ Get all public asynchronous method names of the class.
575
+
576
+ Returns
577
+ -------
578
+ list
579
+ List of public asynchronous method names
580
+ """
581
+ methods = self.getPublicMethods()
582
+ async_methods = []
583
+ for method in methods:
584
+ if inspect.iscoroutinefunction(getattr(self.__abstract, method)):
585
+ async_methods.append(method)
586
+ return async_methods
587
+
588
+ def getProtectedMethods(self) -> list:
589
+ """
590
+ Returns a list of protected class methods (not instance methods).
591
+
592
+ Parameters
593
+ ----------
594
+ None
595
+
596
+ Returns
597
+ -------
598
+ dict
599
+ A list where each element is the name of a protected class method.
600
+ """
601
+ class_name = self.getClassName()
602
+ attributes = self.__abstract.__dict__
603
+ protected_methods = []
604
+
605
+ # Exclude dunder, public, private attributes and properties
606
+ for attr, value in attributes.items():
607
+ if callable(value) and not isinstance(value, (staticmethod, classmethod)) and not isinstance(value, property):
608
+ if attr.startswith("_") and not attr.startswith("__") and not attr.startswith(f"_{self.getClassName()}"):
609
+ protected_methods.append(attr)
610
+
611
+ return protected_methods
612
+
613
+ def getProtectedSyncMethods(self) -> list:
614
+ """
615
+ Get all protected synchronous method names of the class.
616
+
617
+ Returns
618
+ -------
619
+ list
620
+ List of protected synchronous method names
621
+ """
622
+ methods = self.getProtectedMethods()
623
+ sync_methods = []
624
+ for method in methods:
625
+ if not inspect.iscoroutinefunction(getattr(self.__abstract, method)):
626
+ sync_methods.append(method)
627
+ return sync_methods
628
+
629
+ def getProtectedAsyncMethods(self) -> list:
630
+ """
631
+ Get all protected asynchronous method names of the class.
632
+
633
+ Returns
634
+ -------
635
+ list
636
+ List of protected asynchronous method names
637
+ """
638
+ methods = self.getProtectedMethods()
639
+ async_methods = []
640
+ for method in methods:
641
+ if inspect.iscoroutinefunction(getattr(self.__abstract, method)):
642
+ async_methods.append(method)
643
+ return async_methods
644
+
645
+ def getPrivateMethods(self) -> list:
646
+ """
647
+ Returns a list of private class methods (not instance methods).
648
+
649
+ Parameters
650
+ ----------
651
+ None
652
+
653
+ Returns
654
+ -------
655
+ list
656
+ A list where each element is the name of a private class method.
657
+ """
658
+ class_name = self.getClassName()
659
+ attributes = self.__abstract.__dict__
660
+ private_methods = []
661
+
662
+ # Exclude dunder, public, protected attributes and properties
663
+ for attr, value in attributes.items():
664
+ if callable(value) and not isinstance(value, (staticmethod, classmethod)) and not isinstance(value, property):
665
+ if attr.startswith(f"_{class_name}"):
666
+ private_methods.append(str(attr).replace(f"_{class_name}", ""))
667
+
668
+ return private_methods
669
+
670
+ def getPrivateSyncMethods(self) -> list:
671
+ """
672
+ Get all private synchronous method names of the class.
673
+
674
+ Returns
675
+ -------
676
+ list
677
+ List of private synchronous method names
678
+ """
679
+ methods = self.getPrivateMethods()
680
+ sync_methods = []
681
+ for method in methods:
682
+ if not inspect.iscoroutinefunction(getattr(self.__abstract, f"_{self.getClassName()}{method}")):
683
+ sync_methods.append(method)
684
+ return sync_methods
685
+
686
+ def getPrivateAsyncMethods(self) -> list:
687
+ """
688
+ Get all private asynchronous method names of the class.
689
+
690
+ Returns
691
+ -------
692
+ list
693
+ List of private asynchronous method names
694
+ """
695
+ methods = self.getPrivateMethods()
696
+ async_methods = []
697
+ for method in methods:
698
+ if inspect.iscoroutinefunction(getattr(self.__abstract, f"_{self.getClassName()}{method}")):
699
+ async_methods.append(method)
700
+ return async_methods
701
+
702
+ def getPublicClassMethods(self) -> list:
703
+ """
704
+ Returns a list of public class methods (not instance methods).
705
+
706
+ Parameters
707
+ ----------
708
+ None
709
+
710
+ Returns
711
+ -------
712
+ list
713
+ A list where each element is the name of a public class method.
714
+ """
715
+ class_name = self.getClassName()
716
+ attributes = self.__abstract.__dict__
717
+ public_class_methods = []
718
+
719
+ # Exclude dunder, protected, private attributes and properties
720
+ for attr, value in attributes.items():
721
+ if isinstance(value, classmethod):
722
+ if attr.startswith("__") and attr.endswith("__"):
723
+ continue
724
+ if attr.startswith(f"_{class_name}"):
725
+ continue
726
+ if attr.startswith("_"):
727
+ continue
728
+ public_class_methods.append(attr)
729
+
730
+ return public_class_methods
731
+
732
+ def getPublicClassSyncMethods(self) -> list:
733
+ """
734
+ Get all public synchronous class method names of the class.
735
+
736
+ Returns
737
+ -------
738
+ list
739
+ List of public synchronous class method names
740
+ """
741
+ methods = self.getPublicClassMethods()
742
+ sync_methods = []
743
+ for method in methods:
744
+ if not inspect.iscoroutinefunction(getattr(self.__abstract, method)):
745
+ sync_methods.append(method)
746
+ return sync_methods
747
+
748
+ def getPublicClassAsyncMethods(self) -> list:
749
+ """
750
+ Get all public asynchronous class method names of the class.
751
+
752
+ Returns
753
+ -------
754
+ list
755
+ List of public asynchronous class method names
756
+ """
757
+ methods = self.getPublicClassMethods()
758
+ async_methods = []
759
+ for method in methods:
760
+ if inspect.iscoroutinefunction(getattr(self.__abstract, method)):
761
+ async_methods.append(method)
762
+ return async_methods
763
+
764
+ def getProtectedClassMethods(self) -> list:
765
+ """
766
+ Returns a list of protected class methods (not instance methods).
767
+
768
+ Parameters
769
+ ----------
770
+ None
771
+
772
+ Returns
773
+ -------
774
+ list
775
+ A list where each element is the name of a protected class method.
776
+ """
777
+ class_name = self.getClassName()
778
+ attributes = self.__abstract.__dict__
779
+ protected_class_methods = []
780
+
781
+ # Exclude dunder, public, private attributes and properties
782
+ for attr, value in attributes.items():
783
+ if isinstance(value, classmethod):
784
+ if attr.startswith("_") and not attr.startswith("__") and not attr.startswith(f"_{class_name}"):
785
+ protected_class_methods.append(attr)
786
+
787
+ return protected_class_methods
788
+
789
+ def getProtectedClassSyncMethods(self) -> list:
790
+ """
791
+ Get all protected synchronous class method names of the class.
792
+
793
+ Returns
794
+ -------
795
+ list
796
+ List of protected synchronous class method names
797
+ """
798
+ methods = self.getProtectedClassMethods()
799
+ sync_methods = []
800
+ for method in methods:
801
+ if not inspect.iscoroutinefunction(getattr(self.__abstract, method)):
802
+ sync_methods.append(method)
803
+ return sync_methods
804
+
805
+ def getProtectedClassAsyncMethods(self) -> list:
806
+ """
807
+ Get all protected asynchronous class method names of the class.
808
+
809
+ Returns
810
+ -------
811
+ list
812
+ List of protected asynchronous class method names
813
+ """
814
+ methods = self.getProtectedClassMethods()
815
+ async_methods = []
816
+ for method in methods:
817
+ if inspect.iscoroutinefunction(getattr(self.__abstract, method)):
818
+ async_methods.append(method)
819
+ return async_methods
820
+
821
+ def getPrivateClassMethods(self) -> list:
822
+ """
823
+ Returns a list of private class methods (not instance methods).
824
+
825
+ Parameters
826
+ ----------
827
+ None
828
+
829
+ Returns
830
+ -------
831
+ list
832
+ A list where each element is the name of a private class method.
833
+ """
834
+ class_name = self.getClassName()
835
+ attributes = self.__abstract.__dict__
836
+ private_class_methods = []
837
+
838
+ # Exclude dunder, public, protected attributes and properties
839
+ for attr, value in attributes.items():
840
+ if isinstance(value, classmethod):
841
+ if attr.startswith(f"_{class_name}"):
842
+ private_class_methods.append(str(attr).replace(f"_{class_name}", ""))
843
+
844
+ return private_class_methods
845
+
846
+ def getPrivateClassSyncMethods(self) -> list:
847
+ """
848
+ Get all private synchronous class method names of the class.
849
+
850
+ Returns
851
+ -------
852
+ list
853
+ List of private synchronous class method names
854
+ """
855
+ methods = self.getPrivateClassMethods()
856
+ sync_methods = []
857
+ for method in methods:
858
+ if not inspect.iscoroutinefunction(getattr(self.__abstract, f"_{self.getClassName()}{method}")):
859
+ sync_methods.append(method)
860
+ return sync_methods
861
+
862
+ def getPrivateClassAsyncMethods(self) -> list:
863
+ """
864
+ Get all private asynchronous class method names of the class.
865
+
866
+ Returns
867
+ -------
868
+ list
869
+ List of private asynchronous class method names
870
+ """
871
+ methods = self.getPrivateClassMethods()
872
+ async_methods = []
873
+ for method in methods:
874
+ if inspect.iscoroutinefunction(getattr(self.__abstract, f"_{self.getClassName()}{method}")):
875
+ async_methods.append(method)
876
+ return async_methods
877
+
878
+ def getPublicStaticMethods(self) -> list:
879
+ """
880
+ Returns a list of public static methods of the class.
881
+
882
+ Parameters
883
+ ----------
884
+ None
885
+
886
+ Returns
887
+ -------
888
+ list
889
+ A list where each element is the name of a public static method.
890
+ """
891
+ class_name = self.getClassName()
892
+ attributes = self.__abstract.__dict__
893
+ public_static_methods = []
894
+
895
+ # Exclude dunder, protected, private attributes and properties
896
+ for attr, value in attributes.items():
897
+ if isinstance(value, staticmethod):
898
+ if attr.startswith("__") and attr.endswith("__"):
899
+ continue
900
+ if attr.startswith(f"_{class_name}"):
901
+ continue
902
+ if attr.startswith("_"):
903
+ continue
904
+ public_static_methods.append(attr)
905
+
906
+ return public_static_methods
907
+
908
+ def getPublicStaticSyncMethods(self) -> list:
909
+ """
910
+ Get all public synchronous static method names of the class.
911
+
912
+ Returns
913
+ -------
914
+ list
915
+ List of public synchronous static method names
916
+ """
917
+ methods = self.getPublicStaticMethods()
918
+ sync_methods = []
919
+ for method in methods:
920
+ if not inspect.iscoroutinefunction(getattr(self.__abstract, method)):
921
+ sync_methods.append(method)
922
+ return sync_methods
923
+
924
+ def getPublicStaticAsyncMethods(self) -> list:
925
+ """
926
+ Get all public asynchronous static method names of the class.
927
+
928
+ Returns
929
+ -------
930
+ list
931
+ List of public asynchronous static method names
932
+ """
933
+ methods = self.getPublicStaticMethods()
934
+ async_methods = []
935
+ for method in methods:
936
+ if inspect.iscoroutinefunction(getattr(self.__abstract, method)):
937
+ async_methods.append(method)
938
+ return async_methods
939
+
940
+ def getProtectedStaticMethods(self) -> list:
941
+ """
942
+ Returns a list of protected static methods of the class.
943
+
944
+ Parameters
945
+ ----------
946
+ None
947
+
948
+ Returns
949
+ -------
950
+ list
951
+ A list where each element is the name of a protected static method.
952
+ """
953
+ class_name = self.getClassName()
954
+ attributes = self.__abstract.__dict__
955
+ protected_static_methods = []
956
+
957
+ # Exclude dunder, public, private attributes and properties
958
+ for attr, value in attributes.items():
959
+ if isinstance(value, staticmethod):
960
+ if attr.startswith("_") and not attr.startswith("__") and not attr.startswith(f"_{class_name}"):
961
+ protected_static_methods.append(attr)
962
+
963
+ return protected_static_methods
964
+
965
+ def getProtectedStaticSyncMethods(self) -> list:
966
+ """
967
+ Get all protected synchronous static method names of the class.
968
+
969
+ Returns
970
+ -------
971
+ list
972
+ List of protected synchronous static method names
973
+ """
974
+ methods = self.getProtectedStaticMethods()
975
+ sync_methods = []
976
+ for method in methods:
977
+ if not inspect.iscoroutinefunction(getattr(self.__abstract, method)):
978
+ sync_methods.append(method)
979
+ return sync_methods
980
+
981
+ def getProtectedStaticAsyncMethods(self) -> list:
982
+ """
983
+ Get all protected asynchronous static method names of the class.
984
+
985
+ Returns
986
+ -------
987
+ list
988
+ List of protected asynchronous static method names
989
+ """
990
+ methods = self.getProtectedStaticMethods()
991
+ async_methods = []
992
+ for method in methods:
993
+ if inspect.iscoroutinefunction(getattr(self.__abstract, method)):
994
+ async_methods.append(method)
995
+ return async_methods
996
+
997
+ def getPrivateStaticMethods(self) -> list:
998
+ """
999
+ Returns a list of private static methods of the class.
1000
+
1001
+ Parameters
1002
+ ----------
1003
+ None
1004
+
1005
+ Returns
1006
+ -------
1007
+ list
1008
+ A list where each element is the name of a private static method.
1009
+ """
1010
+ class_name = self.getClassName()
1011
+ attributes = self.__abstract.__dict__
1012
+ private_static_methods = []
1013
+
1014
+ # Exclude dunder, public, protected attributes and properties
1015
+ for attr, value in attributes.items():
1016
+ if isinstance(value, staticmethod):
1017
+ if attr.startswith(f"_{class_name}"):
1018
+ private_static_methods.append(str(attr).replace(f"_{class_name}", ""))
1019
+
1020
+ return private_static_methods
1021
+
1022
+ def getPrivateStaticSyncMethods(self) -> list:
1023
+ """
1024
+ Get all private synchronous static method names of the class.
1025
+
1026
+ Returns
1027
+ -------
1028
+ list
1029
+ List of private synchronous static method names
1030
+ """
1031
+ methods = self.getPrivateStaticMethods()
1032
+ sync_methods = []
1033
+ for method in methods:
1034
+ if not inspect.iscoroutinefunction(getattr(self.__abstract, f"_{self.getClassName()}{method}")):
1035
+ sync_methods.append(method)
1036
+ return sync_methods
1037
+
1038
+ def getPrivateStaticAsyncMethods(self) -> list:
1039
+ """
1040
+ Get all private asynchronous static method names of the class.
1041
+
1042
+ Returns
1043
+ -------
1044
+ list
1045
+ List of private asynchronous static method names
1046
+ """
1047
+ methods = self.getPrivateStaticMethods()
1048
+ async_methods = []
1049
+ for method in methods:
1050
+ if inspect.iscoroutinefunction(getattr(self.__abstract, f"_{self.getClassName()}{method}")):
1051
+ async_methods.append(method)
1052
+ return async_methods
1053
+
1054
+ def getDunderMethods(self) -> list:
1055
+ """
1056
+ Returns a list of dunder (double underscore) methods of the class.
1057
+
1058
+ Parameters
1059
+ ----------
1060
+ None
1061
+
1062
+ Returns
1063
+ -------
1064
+ list
1065
+ A list where each element is the name of a dunder method.
1066
+ """
1067
+ attributes = self.__abstract.__dict__
1068
+ dunder_methods = []
1069
+ exclude = []
1070
+
1071
+ # Exclude public, protected, private attributes and properties
1072
+ for attr, value in attributes.items():
1073
+ if callable(value) and not isinstance(value, (staticmethod, classmethod)) and not isinstance(value, property):
1074
+ if attr.startswith("__") and attr.endswith("__") and attr not in exclude:
1075
+ dunder_methods.append(attr)
1076
+
1077
+ return dunder_methods
1078
+
1079
+ def getMagicMethods(self) -> list:
1080
+ """
1081
+ Returns a list of magic (dunder) methods of the class.
1082
+
1083
+ Parameters
1084
+ ----------
1085
+ None
1086
+
1087
+ Returns
1088
+ -------
1089
+ list
1090
+ A list where each element is the name of a magic method.
1091
+ """
1092
+ return self.getDunderMethods()
1093
+
1094
+ def getProperties(self) -> List:
1095
+ """
1096
+ Get all properties of the instance.
1097
+
1098
+ Returns
1099
+ -------
1100
+ List[str]
1101
+ List of property names
1102
+ """
1103
+
1104
+ properties = []
1105
+ for name, prop in self.__abstract.__dict__.items():
1106
+ if isinstance(prop, property):
1107
+ name_prop = name.replace(f"_{self.getClassName()}", "")
1108
+ properties.append(name_prop)
1109
+ return properties
1110
+
1111
+ def getPublicProperties(self) -> List:
1112
+ """
1113
+ Get all public properties of the instance.
1114
+
1115
+ Returns
1116
+ -------
1117
+ List:
1118
+ List of public property names and their values
1119
+ """
1120
+ properties = []
1121
+ cls_name = self.getClassName()
1122
+ for name, prop in self.__abstract.__dict__.items():
1123
+ if isinstance(prop, property):
1124
+ if not name.startswith(f"_") and not name.startswith(f"_{cls_name}"):
1125
+ properties.append(name.replace(f"_{cls_name}", ""))
1126
+ return properties
1127
+
1128
+ def getProtectedProperties(self) -> List:
1129
+ """
1130
+ Get all protected properties of the instance.
1131
+
1132
+ Returns
1133
+ -------
1134
+ List
1135
+ List of protected property names and their values
1136
+ """
1137
+ properties = []
1138
+ for name, prop in self.__abstract.__dict__.items():
1139
+ if isinstance(prop, property):
1140
+ if name.startswith(f"_") and not name.startswith("__") and not name.startswith(f"_{self.getClassName()}"):
1141
+ properties.append(name)
1142
+ return properties
1143
+
1144
+ def getPrivateProperties(self) -> List:
1145
+ """
1146
+ Get all private properties of the instance.
1147
+
1148
+ Returns
1149
+ -------
1150
+ List
1151
+ List of private property names and their values
1152
+ """
1153
+ properties = []
1154
+ for name, prop in self.__abstract.__dict__.items():
1155
+ if isinstance(prop, property):
1156
+ if name.startswith(f"_{self.getClassName()}") and not name.startswith("__"):
1157
+ properties.append(name.replace(f"_{self.getClassName()}", ""))
1158
+ return properties
1159
+
1160
+ def getPropertySignature(self, name: str) -> inspect.Signature:
1161
+ """
1162
+ Get the signature of a property.
1163
+
1164
+ Parameters
1165
+ ----------
1166
+ name : str
1167
+ The property name to get the signature for
1168
+
1169
+ Returns
1170
+ -------
1171
+ inspect.Signature
1172
+ The signature of the property
1173
+
1174
+ Raises
1175
+ ------
1176
+ ReflectionValueError
1177
+ If the property does not exist or is not accessible.
1178
+ """
1179
+ # Handle private property name mangling
1180
+ if name.startswith("__") and not name.endswith("__"):
1181
+ class_name = self.getClassName()
1182
+ name = f"_{class_name}{name}"
1183
+
1184
+ if not hasattr(self.__abstract, name):
1185
+ raise ReflectionValueError(f"Property '{name}' does not exist in class '{self.getClassName()}'.")
1186
+
1187
+ prop = getattr(self.__abstract, name)
1188
+ if not isinstance(prop, property):
1189
+ raise ReflectionValueError(f"'{name}' is not a property in class '{self.getClassName()}'.")
1190
+
1191
+ return inspect.signature(prop.fget)
1192
+
1193
+ def getPropiertyDocstring(self, name: str) -> str:
1194
+ """
1195
+ Get the docstring of a property.
1196
+
1197
+ Parameters
1198
+ ----------
1199
+ name : str
1200
+ The property name to get the docstring for
1201
+
1202
+ Returns
1203
+ -------
1204
+ str
1205
+ The docstring of the property
1206
+
1207
+ Raises
1208
+ ------
1209
+ ReflectionValueError
1210
+ If the property does not exist or is not accessible.
1211
+ """
1212
+ # Handle private property name mangling
1213
+ if name.startswith("__") and not name.endswith("__"):
1214
+ class_name = self.getClassName()
1215
+ name = f"_{class_name}{name}"
1216
+
1217
+ if not hasattr(self.__abstract, name):
1218
+ raise ReflectionValueError(f"Property '{name}' does not exist in class '{self.getClassName()}'.")
1219
+
1220
+ prop = getattr(self.__abstract, name)
1221
+ if not isinstance(prop, property):
1222
+ raise ReflectionValueError(f"'{name}' is not a property in class '{self.getClassName()}'.")
1223
+
1224
+ return prop.fget.__doc__ if prop.fget else None
1225
+
1226
+ def getConstructorDependencies(self) -> ClassDependency:
1227
+ """
1228
+ Get the resolved and unresolved dependencies from the constructor of the instance's class.
1229
+
1230
+ Returns
1231
+ -------
1232
+ ClassDependency
1233
+ A structured representation of the constructor dependencies, containing:
1234
+ - resolved: Dictionary of resolved dependencies with their names and values.
1235
+ - unresolved: List of unresolved dependencies (parameter names without default values or annotations).
1236
+ """
1237
+ return ReflectDependencies(self.__abstract).getConstructorDependencies()
1238
+
1239
+ def getMethodDependencies(self, method_name: str) -> MethodDependency:
1240
+ """
1241
+ Get the resolved and unresolved dependencies from a method of the instance's class.
1242
+
1243
+ Parameters
1244
+ ----------
1245
+ method_name : str
1246
+ The name of the method to inspect
1247
+
1248
+ Returns
1249
+ -------
1250
+ MethodDependency
1251
+ A structured representation of the method dependencies, containing:
1252
+ - resolved: Dictionary of resolved dependencies with their names and values.
1253
+ - unresolved: List of unresolved dependencies (parameter names without default values or annotations).
1254
+ """
1255
+
1256
+ # Ensure the method name is a valid identifier
1257
+ if not self.hasMethod(method_name):
1258
+ raise ReflectionAttributeError(f"Method '{method_name}' does not exist on '{self.getClassName()}'.")
1259
+
1260
+ # Handle private method name mangling
1261
+ if method_name.startswith("__") and not method_name.endswith("__"):
1262
+ class_name = self.getClassName()
1263
+ method_name = f"_{class_name}{method_name}"
1264
+
1265
+ # Use ReflectDependencies to get method dependencies
1266
+ return ReflectDependencies(self.__abstract).getMethodDependencies(method_name)