19
19
20
20
"""
21
21
22
- import sys
23
22
import inspect
24
23
25
- from newrelic .packages import six
26
-
27
- from newrelic .packages .wrapt import (ObjectProxy as _ObjectProxy ,
28
- FunctionWrapper as _FunctionWrapper ,
29
- BoundFunctionWrapper as _BoundFunctionWrapper )
30
-
31
- from newrelic .packages .wrapt .wrappers import _FunctionWrapperBase
24
+ from newrelic .packages .wrapt import BoundFunctionWrapper as _BoundFunctionWrapper
25
+ from newrelic .packages .wrapt import CallableObjectProxy as _CallableObjectProxy
26
+ from newrelic .packages .wrapt import FunctionWrapper as _FunctionWrapper
27
+ from newrelic .packages .wrapt import ObjectProxy as _ObjectProxy
28
+ from newrelic .packages .wrapt import ( # noqa: F401; pylint: disable=W0611
29
+ apply_patch ,
30
+ resolve_path ,
31
+ wrap_object ,
32
+ wrap_object_attribute ,
33
+ )
34
+ from newrelic .packages .wrapt .__wrapt__ import _FunctionWrapperBase
32
35
33
36
# We previously had our own pure Python implementation of the generic
34
37
# object wrapper but we now defer to using the wrapt module as its C
47
50
# ObjectProxy or FunctionWrapper should be used going forward.
48
51
49
52
50
- class _ObjectWrapperBase (object ):
53
+ class ObjectProxy (_ObjectProxy ):
54
+ """
55
+ This class provides method overrides for all object wrappers used by the
56
+ agent. These methods allow attributes to be defined with the special prefix
57
+ _nr_ to be interpretted as attributes on the wrapper, rather than the
58
+ wrapped object. Inheriting from the base class wrapt.ObjectProxy preserves
59
+ method resolution order (MRO) through multiple inheritance.
60
+ (See https://www.python.org/download/releases/2.3/mro/).
61
+ """
51
62
52
63
def __setattr__ (self , name , value ):
53
- if name .startswith (' _nr_' ):
54
- name = name .replace (' _nr_' , ' _self_' , 1 )
64
+ if name .startswith (" _nr_" ):
65
+ name = name .replace (" _nr_" , " _self_" , 1 )
55
66
setattr (self , name , value )
56
67
else :
57
- _ObjectProxy . __setattr__ ( self , name , value )
68
+ super ( ObjectProxy , self ). __setattr__ ( name , value )
58
69
59
70
def __getattr__ (self , name ):
60
- if name .startswith (' _nr_' ):
61
- name = name .replace (' _nr_' , ' _self_' , 1 )
71
+ if name .startswith (" _nr_" ):
72
+ name = name .replace (" _nr_" , " _self_" , 1 )
62
73
return getattr (self , name )
63
74
else :
64
- return _ObjectProxy . __getattr__ ( self , name )
75
+ return super ( ObjectProxy , self ). __getattr__ ( name )
65
76
66
77
def __delattr__ (self , name ):
67
- if name .startswith (' _nr_' ):
68
- name = name .replace (' _nr_' , ' _self_' , 1 )
78
+ if name .startswith (" _nr_" ):
79
+ name = name .replace (" _nr_" , " _self_" , 1 )
69
80
delattr (self , name )
70
81
else :
71
- _ObjectProxy . __delattr__ ( self , name )
82
+ super ( ObjectProxy , self ). __delattr__ ( name )
72
83
73
84
@property
74
85
def _nr_next_object (self ):
@@ -79,8 +90,7 @@ def _nr_last_object(self):
79
90
try :
80
91
return self ._self_last_object
81
92
except AttributeError :
82
- self ._self_last_object = getattr (self .__wrapped__ ,
83
- '_nr_last_object' , self .__wrapped__ )
93
+ self ._self_last_object = getattr (self .__wrapped__ , "_nr_last_object" , self .__wrapped__ )
84
94
return self ._self_last_object
85
95
86
96
@property
@@ -96,166 +106,45 @@ def _nr_parent(self):
96
106
return self ._self_parent
97
107
98
108
99
- class _NRBoundFunctionWrapper (_ObjectWrapperBase , _BoundFunctionWrapper ):
109
+ class _NRBoundFunctionWrapper (ObjectProxy , _BoundFunctionWrapper ):
100
110
pass
101
111
102
112
103
- class FunctionWrapper (_ObjectWrapperBase , _FunctionWrapper ):
113
+ class FunctionWrapper (ObjectProxy , _FunctionWrapper ):
104
114
__bound_function_wrapper__ = _NRBoundFunctionWrapper
105
115
106
116
107
- class ObjectProxy (_ObjectProxy ):
108
-
109
- def __setattr__ (self , name , value ):
110
- if name .startswith ('_nr_' ):
111
- name = name .replace ('_nr_' , '_self_' , 1 )
112
- setattr (self , name , value )
113
- else :
114
- _ObjectProxy .__setattr__ (self , name , value )
115
-
116
- def __getattr__ (self , name ):
117
- if name .startswith ('_nr_' ):
118
- name = name .replace ('_nr_' , '_self_' , 1 )
119
- return getattr (self , name )
120
- else :
121
- return _ObjectProxy .__getattr__ (self , name )
122
-
123
- def __delattr__ (self , name ):
124
- if name .startswith ('_nr_' ):
125
- name = name .replace ('_nr_' , '_self_' , 1 )
126
- delattr (self , name )
127
- else :
128
- _ObjectProxy .__delattr__ (self , name )
129
-
130
- @property
131
- def _nr_next_object (self ):
132
- return self .__wrapped__
133
-
134
- @property
135
- def _nr_last_object (self ):
136
- try :
137
- return self ._self_last_object
138
- except AttributeError :
139
- self ._self_last_object = getattr (self .__wrapped__ ,
140
- '_nr_last_object' , self .__wrapped__ )
141
- return self ._self_last_object
142
-
143
-
144
- class CallableObjectProxy (ObjectProxy ):
117
+ class CallableObjectProxy (ObjectProxy , _CallableObjectProxy ):
118
+ pass
145
119
146
- def __call__ (self , * args , ** kwargs ):
147
- return self .__wrapped__ (* args , ** kwargs )
148
120
149
121
# The ObjectWrapper class needs to be deprecated and removed once all our
150
122
# own code no longer uses it. It reaches down into what are wrapt internals
151
123
# at present which shouldn't be doing.
152
124
153
125
154
- class ObjectWrapper (_ObjectWrapperBase , _FunctionWrapperBase ):
126
+ class ObjectWrapper (ObjectProxy , _FunctionWrapperBase ):
155
127
__bound_function_wrapper__ = _NRBoundFunctionWrapper
156
128
157
129
def __init__ (self , wrapped , instance , wrapper ):
158
130
if isinstance (wrapped , classmethod ):
159
- binding = ' classmethod'
131
+ binding = " classmethod"
160
132
elif isinstance (wrapped , staticmethod ):
161
- binding = ' staticmethod'
133
+ binding = " staticmethod"
162
134
else :
163
- binding = 'function'
164
-
165
- super (ObjectWrapper , self ).__init__ (wrapped , instance , wrapper ,
166
- binding = binding )
167
-
168
-
169
- # Helper functions for performing monkey patching.
135
+ binding = "function"
170
136
137
+ super (ObjectWrapper , self ).__init__ (wrapped , instance , wrapper , binding = binding )
171
138
172
- def resolve_path (module , name ):
173
- if isinstance (module , six .string_types ):
174
- __import__ (module )
175
- module = sys .modules [module ]
176
-
177
- parent = module
178
-
179
- path = name .split ('.' )
180
- attribute = path [0 ]
181
-
182
- original = getattr (parent , attribute )
183
- for attribute in path [1 :]:
184
- parent = original
185
-
186
- # We can't just always use getattr() because in doing
187
- # that on a class it will cause binding to occur which
188
- # will complicate things later and cause some things not
189
- # to work. For the case of a class we therefore access
190
- # the __dict__ directly. To cope though with the wrong
191
- # class being given to us, or a method being moved into
192
- # a base class, we need to walk the class hierarchy to
193
- # work out exactly which __dict__ the method was defined
194
- # in, as accessing it from __dict__ will fail if it was
195
- # not actually on the class given. Fallback to using
196
- # getattr() if we can't find it. If it truly doesn't
197
- # exist, then that will fail.
198
-
199
- if inspect .isclass (original ):
200
- for cls in inspect .getmro (original ):
201
- if attribute in vars (cls ):
202
- original = vars (cls )[attribute ]
203
- break
204
- else :
205
- original = getattr (original , attribute )
206
-
207
- else :
208
- original = getattr (original , attribute )
209
-
210
- return (parent , attribute , original )
211
-
212
-
213
- def apply_patch (parent , attribute , replacement ):
214
- setattr (parent , attribute , replacement )
215
-
216
-
217
- def wrap_object (module , name , factory , args = (), kwargs = {}):
218
- (parent , attribute , original ) = resolve_path (module , name )
219
- wrapper = factory (original , * args , ** kwargs )
220
- apply_patch (parent , attribute , wrapper )
221
- return wrapper
222
-
223
- # Function for apply a proxy object to an attribute of a class instance.
224
- # The wrapper works by defining an attribute of the same name on the
225
- # class which is a descriptor and which intercepts access to the
226
- # instance attribute. Note that this cannot be used on attributes which
227
- # are themselves defined by a property object.
228
-
229
-
230
- class AttributeWrapper (object ):
231
-
232
- def __init__ (self , attribute , factory , args , kwargs ):
233
- self .attribute = attribute
234
- self .factory = factory
235
- self .args = args
236
- self .kwargs = kwargs
237
-
238
- def __get__ (self , instance , owner ):
239
- value = instance .__dict__ [self .attribute ]
240
- return self .factory (value , * self .args , ** self .kwargs )
241
-
242
- def __set__ (self , instance , value ):
243
- instance .__dict__ [self .attribute ] = value
244
-
245
- def __delete__ (self , instance ):
246
- del instance .__dict__ [self .attribute ]
247
-
248
-
249
- def wrap_object_attribute (module , name , factory , args = (), kwargs = {}):
250
- path , attribute = name .rsplit ('.' , 1 )
251
- parent = resolve_path (module , path )[2 ]
252
- wrapper = AttributeWrapper (attribute , factory , args , kwargs )
253
- apply_patch (parent , attribute , wrapper )
254
- return wrapper
255
139
256
140
# Function for creating a decorator for applying to functions, as well as
257
141
# short cut functions for applying wrapper functions via monkey patching.
258
142
143
+ # WARNING: These functions are reproduced directly from wrapt, but using
144
+ # our FunctionWrapper class which includes the _nr_ attriubte overrides
145
+ # that are inherited from our subclass of wrapt.ObjectProxy.These MUST be
146
+ # kept in sync with wrapt when upgrading, or drift may introduce bugs.
147
+
259
148
260
149
def function_wrapper (wrapper ):
261
150
def _wrapper (wrapped , instance , args , kwargs ):
@@ -267,16 +156,18 @@ def _wrapper(wrapped, instance, args, kwargs):
267
156
else :
268
157
target_wrapper = wrapper .__get__ (instance , type (instance ))
269
158
return FunctionWrapper (target_wrapped , target_wrapper )
159
+
270
160
return FunctionWrapper (wrapper , _wrapper )
271
161
272
162
273
163
def wrap_function_wrapper (module , name , wrapper ):
274
164
return wrap_object (module , name , FunctionWrapper , (wrapper ,))
275
165
276
166
277
- def patch_function_wrapper (module , name ):
167
+ def patch_function_wrapper (module , name , enabled = None ):
278
168
def _wrapper (wrapper ):
279
- return wrap_object (module , name , FunctionWrapper , (wrapper ,))
169
+ return wrap_object (module , name , FunctionWrapper , (wrapper , enabled ))
170
+
280
171
return _wrapper
281
172
282
173
@@ -299,10 +190,14 @@ def _execute(wrapped, instance, args, kwargs):
299
190
return wrapped (* args , ** kwargs )
300
191
finally :
301
192
setattr (parent , attribute , original )
193
+
302
194
return FunctionWrapper (target_wrapped , _execute )
195
+
303
196
return FunctionWrapper (wrapper , _wrapper )
197
+
304
198
return _decorator
305
199
200
+
306
201
# Generic decorators for performing actions before and after a wrapped
307
202
# function is called, or modifying the inbound arguments or return value.
308
203
@@ -315,6 +210,7 @@ def _wrapper(wrapped, instance, args, kwargs):
315
210
else :
316
211
function (* args , ** kwargs )
317
212
return wrapped (* args , ** kwargs )
213
+
318
214
return _wrapper
319
215
320
216
@@ -335,6 +231,7 @@ def _wrapper(wrapped, instance, args, kwargs):
335
231
else :
336
232
function (* args , ** kwargs )
337
233
return result
234
+
338
235
return _wrapper
339
236
340
237
@@ -382,6 +279,7 @@ def out_function(function):
382
279
@function_wrapper
383
280
def _wrapper (wrapped , instance , args , kwargs ):
384
281
return function (wrapped (* args , ** kwargs ))
282
+
385
283
return _wrapper
386
284
387
285
0 commit comments