Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pure_eval/my_getattr_static.py: 22%
86 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-20 06:09 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-20 06:09 +0000
1import types
3from pure_eval.utils import of_type, CannotEval
5_sentinel = object()
8def _static_getmro(klass):
9 return type.__dict__['__mro__'].__get__(klass)
12def _check_instance(obj, attr):
13 instance_dict = {}
14 try:
15 instance_dict = object.__getattribute__(obj, "__dict__")
16 except AttributeError:
17 pass
18 return dict.get(instance_dict, attr, _sentinel)
21def _check_class(klass, attr):
22 for entry in _static_getmro(klass):
23 if _shadowed_dict(type(entry)) is _sentinel:
24 try:
25 return entry.__dict__[attr]
26 except KeyError:
27 pass
28 else:
29 break
30 return _sentinel
33def _is_type(obj):
34 try:
35 _static_getmro(obj)
36 except TypeError:
37 return False
38 return True
41def _shadowed_dict(klass):
42 dict_attr = type.__dict__["__dict__"]
43 for entry in _static_getmro(klass):
44 try:
45 class_dict = dict_attr.__get__(entry)["__dict__"]
46 except KeyError:
47 pass
48 else:
49 if not (type(class_dict) is types.GetSetDescriptorType and
50 class_dict.__name__ == "__dict__" and
51 class_dict.__objclass__ is entry):
52 return class_dict
53 return _sentinel
56def getattr_static(obj, attr):
57 """Retrieve attributes without triggering dynamic lookup via the
58 descriptor protocol, __getattr__ or __getattribute__.
60 Note: this function may not be able to retrieve all attributes
61 that getattr can fetch (like dynamically created attributes)
62 and may find attributes that getattr can't (like descriptors
63 that raise AttributeError). It can also return descriptor objects
64 instead of instance members in some cases. See the
65 documentation for details.
66 """
67 instance_result = _sentinel
68 if not _is_type(obj):
69 klass = type(obj)
70 dict_attr = _shadowed_dict(klass)
71 if (dict_attr is _sentinel or
72 type(dict_attr) is types.MemberDescriptorType):
73 instance_result = _check_instance(obj, attr)
74 else:
75 raise CannotEval
76 else:
77 klass = obj
79 klass_result = _check_class(klass, attr)
81 if instance_result is not _sentinel and klass_result is not _sentinel:
82 if (_check_class(type(klass_result), '__get__') is not _sentinel and
83 _check_class(type(klass_result), '__set__') is not _sentinel):
84 return _resolve_descriptor(klass_result, obj, klass)
86 if instance_result is not _sentinel:
87 return instance_result
88 if klass_result is not _sentinel:
89 get = _check_class(type(klass_result), '__get__')
90 if get is _sentinel:
91 return klass_result
92 else:
93 if obj is klass:
94 instance = None
95 else:
96 instance = obj
97 return _resolve_descriptor(klass_result, instance, klass)
99 if obj is klass:
100 # for types we check the metaclass too
101 for entry in _static_getmro(type(klass)):
102 if _shadowed_dict(type(entry)) is _sentinel:
103 try:
104 result = entry.__dict__[attr]
105 get = _check_class(type(result), '__get__')
106 if get is not _sentinel:
107 raise CannotEval
108 return result
109 except KeyError:
110 pass
111 raise CannotEval
114class _foo:
115 __slots__ = ['foo']
116 method = lambda: 0
119slot_descriptor = _foo.foo
120wrapper_descriptor = str.__dict__['__add__']
121method_descriptor = str.__dict__['startswith']
122user_method_descriptor = _foo.__dict__['method']
124safe_descriptors_raw = [
125 slot_descriptor,
126 wrapper_descriptor,
127 method_descriptor,
128 user_method_descriptor,
129]
131safe_descriptor_types = list(map(type, safe_descriptors_raw))
134def _resolve_descriptor(d, instance, owner):
135 try:
136 return type(of_type(d, *safe_descriptor_types)).__get__(d, instance, owner)
137 except AttributeError as e:
138 raise CannotEval from e