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

1import types 

2 

3from pure_eval.utils import of_type, CannotEval 

4 

5_sentinel = object() 

6 

7 

8def _static_getmro(klass): 

9 return type.__dict__['__mro__'].__get__(klass) 

10 

11 

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) 

19 

20 

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 

31 

32 

33def _is_type(obj): 

34 try: 

35 _static_getmro(obj) 

36 except TypeError: 

37 return False 

38 return True 

39 

40 

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 

54 

55 

56def getattr_static(obj, attr): 

57 """Retrieve attributes without triggering dynamic lookup via the 

58 descriptor protocol, __getattr__ or __getattribute__. 

59 

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 

78 

79 klass_result = _check_class(klass, attr) 

80 

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) 

85 

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) 

98 

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 

112 

113 

114class _foo: 

115 __slots__ = ['foo'] 

116 method = lambda: 0 

117 

118 

119slot_descriptor = _foo.foo 

120wrapper_descriptor = str.__dict__['__add__'] 

121method_descriptor = str.__dict__['startswith'] 

122user_method_descriptor = _foo.__dict__['method'] 

123 

124safe_descriptors_raw = [ 

125 slot_descriptor, 

126 wrapper_descriptor, 

127 method_descriptor, 

128 user_method_descriptor, 

129] 

130 

131safe_descriptor_types = list(map(type, safe_descriptors_raw)) 

132 

133 

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