Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/wrapt/patches.py: 22%

87 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-03 07:57 +0000

1import inspect 

2import sys 

3 

4PY2 = sys.version_info[0] == 2 

5 

6if PY2: 

7 string_types = basestring, 

8else: 

9 string_types = str, 

10 

11from .__wrapt__ import FunctionWrapper 

12 

13# Helper functions for applying wrappers to existing functions. 

14 

15def resolve_path(module, name): 

16 if isinstance(module, string_types): 

17 __import__(module) 

18 module = sys.modules[module] 

19 

20 parent = module 

21 

22 path = name.split('.') 

23 attribute = path[0] 

24 

25 # We can't just always use getattr() because in doing 

26 # that on a class it will cause binding to occur which 

27 # will complicate things later and cause some things not 

28 # to work. For the case of a class we therefore access 

29 # the __dict__ directly. To cope though with the wrong 

30 # class being given to us, or a method being moved into 

31 # a base class, we need to walk the class hierarchy to 

32 # work out exactly which __dict__ the method was defined 

33 # in, as accessing it from __dict__ will fail if it was 

34 # not actually on the class given. Fallback to using 

35 # getattr() if we can't find it. If it truly doesn't 

36 # exist, then that will fail. 

37 

38 def lookup_attribute(parent, attribute): 

39 if inspect.isclass(parent): 

40 for cls in inspect.getmro(parent): 

41 if attribute in vars(cls): 

42 return vars(cls)[attribute] 

43 else: 

44 return getattr(parent, attribute) 

45 else: 

46 return getattr(parent, attribute) 

47 

48 original = lookup_attribute(parent, attribute) 

49 

50 for attribute in path[1:]: 

51 parent = original 

52 original = lookup_attribute(parent, attribute) 

53 

54 return (parent, attribute, original) 

55 

56def apply_patch(parent, attribute, replacement): 

57 setattr(parent, attribute, replacement) 

58 

59def wrap_object(module, name, factory, args=(), kwargs={}): 

60 (parent, attribute, original) = resolve_path(module, name) 

61 wrapper = factory(original, *args, **kwargs) 

62 apply_patch(parent, attribute, wrapper) 

63 return wrapper 

64 

65# Function for applying a proxy object to an attribute of a class 

66# instance. The wrapper works by defining an attribute of the same name 

67# on the class which is a descriptor and which intercepts access to the 

68# instance attribute. Note that this cannot be used on attributes which 

69# are themselves defined by a property object. 

70 

71class AttributeWrapper(object): 

72 

73 def __init__(self, attribute, factory, args, kwargs): 

74 self.attribute = attribute 

75 self.factory = factory 

76 self.args = args 

77 self.kwargs = kwargs 

78 

79 def __get__(self, instance, owner): 

80 value = instance.__dict__[self.attribute] 

81 return self.factory(value, *self.args, **self.kwargs) 

82 

83 def __set__(self, instance, value): 

84 instance.__dict__[self.attribute] = value 

85 

86 def __delete__(self, instance): 

87 del instance.__dict__[self.attribute] 

88 

89def wrap_object_attribute(module, name, factory, args=(), kwargs={}): 

90 path, attribute = name.rsplit('.', 1) 

91 parent = resolve_path(module, path)[2] 

92 wrapper = AttributeWrapper(attribute, factory, args, kwargs) 

93 apply_patch(parent, attribute, wrapper) 

94 return wrapper 

95 

96# Functions for creating a simple decorator using a FunctionWrapper, 

97# plus short cut functions for applying wrappers to functions. These are 

98# for use when doing monkey patching. For a more featured way of 

99# creating decorators see the decorator decorator instead. 

100 

101def function_wrapper(wrapper): 

102 def _wrapper(wrapped, instance, args, kwargs): 

103 target_wrapped = args[0] 

104 if instance is None: 

105 target_wrapper = wrapper 

106 elif inspect.isclass(instance): 

107 target_wrapper = wrapper.__get__(None, instance) 

108 else: 

109 target_wrapper = wrapper.__get__(instance, type(instance)) 

110 return FunctionWrapper(target_wrapped, target_wrapper) 

111 return FunctionWrapper(wrapper, _wrapper) 

112 

113def wrap_function_wrapper(module, name, wrapper): 

114 return wrap_object(module, name, FunctionWrapper, (wrapper,)) 

115 

116def patch_function_wrapper(module, name, enabled=None): 

117 def _wrapper(wrapper): 

118 return wrap_object(module, name, FunctionWrapper, (wrapper, enabled)) 

119 return _wrapper 

120 

121def transient_function_wrapper(module, name): 

122 def _decorator(wrapper): 

123 def _wrapper(wrapped, instance, args, kwargs): 

124 target_wrapped = args[0] 

125 if instance is None: 

126 target_wrapper = wrapper 

127 elif inspect.isclass(instance): 

128 target_wrapper = wrapper.__get__(None, instance) 

129 else: 

130 target_wrapper = wrapper.__get__(instance, type(instance)) 

131 def _execute(wrapped, instance, args, kwargs): 

132 (parent, attribute, original) = resolve_path(module, name) 

133 replacement = FunctionWrapper(original, target_wrapper) 

134 setattr(parent, attribute, replacement) 

135 try: 

136 return wrapped(*args, **kwargs) 

137 finally: 

138 setattr(parent, attribute, original) 

139 return FunctionWrapper(target_wrapped, _execute) 

140 return FunctionWrapper(wrapper, _wrapper) 

141 return _decorator