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