retracesoftware-proxy 0.2.11__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.
- retracesoftware/__init__.py +0 -0
- retracesoftware/__main__.py +288 -0
- retracesoftware/autoenable.py +53 -0
- retracesoftware/config.json +175 -0
- retracesoftware/config.yaml +0 -0
- retracesoftware/install/__init__.py +0 -0
- retracesoftware/install/config.py +59 -0
- retracesoftware/install/edgecases.py +250 -0
- retracesoftware/install/globals.py +17 -0
- retracesoftware/install/install.py +142 -0
- retracesoftware/install/patcher.py +122 -0
- retracesoftware/install/patchfindspec.py +117 -0
- retracesoftware/install/phases.py +338 -0
- retracesoftware/install/predicate.py +92 -0
- retracesoftware/install/record.py +174 -0
- retracesoftware/install/references.py +66 -0
- retracesoftware/install/replace.py +28 -0
- retracesoftware/install/replay.py +102 -0
- retracesoftware/install/tracer.py +284 -0
- retracesoftware/install/typeutils.py +92 -0
- retracesoftware/modules.toml +388 -0
- retracesoftware/preload.txt +218 -0
- retracesoftware/proxy/__init__.py +3 -0
- retracesoftware/proxy/gateway.py +49 -0
- retracesoftware/proxy/globalref.py +31 -0
- retracesoftware/proxy/messagestream.py +204 -0
- retracesoftware/proxy/proxyfactory.py +357 -0
- retracesoftware/proxy/proxysystem.py +454 -0
- retracesoftware/proxy/proxytype.py +424 -0
- retracesoftware/proxy/record.py +211 -0
- retracesoftware/proxy/replay.py +138 -0
- retracesoftware/proxy/serializer.py +28 -0
- retracesoftware/proxy/startthread.py +40 -0
- retracesoftware/proxy/stubfactory.py +195 -0
- retracesoftware/proxy/thread.py +106 -0
- retracesoftware/replay.py +104 -0
- retracesoftware/run.py +378 -0
- retracesoftware/stackdifference.py +133 -0
- retracesoftware_proxy-0.2.11.dist-info/METADATA +8 -0
- retracesoftware_proxy-0.2.11.dist-info/RECORD +42 -0
- retracesoftware_proxy-0.2.11.dist-info/WHEEL +5 -0
- retracesoftware_proxy-0.2.11.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import retracesoftware.functional as functional
|
|
2
|
+
import retracesoftware_utils as utils
|
|
3
|
+
import types
|
|
4
|
+
from retracesoftware.proxy.gateway import adapter_pair
|
|
5
|
+
from types import SimpleNamespace
|
|
6
|
+
from retracesoftware.proxy.proxytype import *
|
|
7
|
+
from retracesoftware.proxy.stubfactory import Stub
|
|
8
|
+
from retracesoftware.install.typeutils import modify, WithFlags, WithoutFlags
|
|
9
|
+
|
|
10
|
+
from retracesoftware.proxy.serializer import serializer
|
|
11
|
+
from retracesoftware.install.tracer import Tracer
|
|
12
|
+
import sys
|
|
13
|
+
import gc
|
|
14
|
+
import weakref
|
|
15
|
+
import enum
|
|
16
|
+
import functools
|
|
17
|
+
import re
|
|
18
|
+
|
|
19
|
+
class RetraceError(Exception):
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
def proxy(proxytype):
|
|
23
|
+
return functional.spread(
|
|
24
|
+
utils.create_wrapped,
|
|
25
|
+
functional.sequence(functional.typeof, proxytype),
|
|
26
|
+
None)
|
|
27
|
+
|
|
28
|
+
def maybe_proxy(proxytype):
|
|
29
|
+
return functional.if_then_else(
|
|
30
|
+
functional.isinstanceof(utils.Wrapped),
|
|
31
|
+
utils.unwrap,
|
|
32
|
+
proxy(functional.memoize_one_arg(proxytype)))
|
|
33
|
+
|
|
34
|
+
class Patched:
|
|
35
|
+
__slots__ = ()
|
|
36
|
+
|
|
37
|
+
class RetraceBase:
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
unproxy_execute = functional.mapargs(starting = 1,
|
|
41
|
+
transform = functional.walker(utils.try_unwrap),
|
|
42
|
+
function = functional.apply)
|
|
43
|
+
|
|
44
|
+
def resolve(obj):
|
|
45
|
+
try:
|
|
46
|
+
return getattr(sys.modules[obj.__module__], obj.__name__)
|
|
47
|
+
except:
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
def is_function_type(cls):
|
|
51
|
+
return cls in [types.BuiltinFunctionType, types.FunctionType]
|
|
52
|
+
|
|
53
|
+
method_types = (types.MethodDescriptorType,
|
|
54
|
+
types.WrapperDescriptorType,
|
|
55
|
+
types.FunctionType)
|
|
56
|
+
|
|
57
|
+
def is_instance_method(obj):
|
|
58
|
+
return isinstance(obj, method_types)
|
|
59
|
+
|
|
60
|
+
def get_all_subtypes(cls):
|
|
61
|
+
"""Recursively find all subtypes of a given class."""
|
|
62
|
+
subclasses = set(cls.__subclasses__())
|
|
63
|
+
for subclass in cls.__subclasses__():
|
|
64
|
+
subclasses.update(get_all_subtypes(subclass))
|
|
65
|
+
return subclasses
|
|
66
|
+
|
|
67
|
+
def cleanse(text):
|
|
68
|
+
pattern = r'0x[a-fA-F0-9]+'
|
|
69
|
+
return re.sub(pattern, '0x####', text)
|
|
70
|
+
|
|
71
|
+
excludes = [
|
|
72
|
+
"ABCMeta.__instancecheck__",
|
|
73
|
+
"ABCMeta.__subclasscheck__",
|
|
74
|
+
"Collection.__subclasshook__",
|
|
75
|
+
re.compile(r"WeakSet"),
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
def exclude(text):
|
|
79
|
+
for elem in excludes:
|
|
80
|
+
if isinstance(elem, str):
|
|
81
|
+
if elem == text: return True
|
|
82
|
+
else:
|
|
83
|
+
# breakpoint()
|
|
84
|
+
# if text.contains('WeakSet'):
|
|
85
|
+
|
|
86
|
+
if re.match(elem, text):
|
|
87
|
+
return True
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
def normalize_for_checkpoint(obj):
|
|
91
|
+
if isinstance(obj, types.FunctionType):
|
|
92
|
+
return obj.__qualname__
|
|
93
|
+
elif isinstance(obj, types.MethodType):
|
|
94
|
+
return obj.__qualname__
|
|
95
|
+
elif isinstance(obj, types.BuiltinFunctionType):
|
|
96
|
+
return obj.__name__
|
|
97
|
+
elif isinstance(obj, types.BuiltinMethodType):
|
|
98
|
+
return obj.__name__
|
|
99
|
+
elif isinstance(obj, str):
|
|
100
|
+
return obj
|
|
101
|
+
elif isinstance(obj, dict):
|
|
102
|
+
return {normalize_for_checkpoint(k): normalize_for_checkpoint(v) for k,v in obj.items()}
|
|
103
|
+
elif isinstance(obj, tuple):
|
|
104
|
+
return tuple(normalize_for_checkpoint(x) for x in obj)
|
|
105
|
+
elif isinstance(obj, list):
|
|
106
|
+
return [normalize_for_checkpoint(x) for x in obj]
|
|
107
|
+
elif isinstance(obj, int):
|
|
108
|
+
# try and filter out memory addresses
|
|
109
|
+
if obj > 1000000 or obj < -1000000:
|
|
110
|
+
return "XXXX"
|
|
111
|
+
else:
|
|
112
|
+
return int(obj)
|
|
113
|
+
elif isinstance(obj, float):
|
|
114
|
+
return obj
|
|
115
|
+
elif isinstance(obj, bool):
|
|
116
|
+
return obj
|
|
117
|
+
elif isinstance(obj, type):
|
|
118
|
+
return obj.__name__
|
|
119
|
+
elif isinstance(obj, enum.Enum):
|
|
120
|
+
return obj.name
|
|
121
|
+
elif isinstance(obj, enum.EnumMeta):
|
|
122
|
+
return obj.__name__
|
|
123
|
+
elif isinstance(obj, enum.EnumMember):
|
|
124
|
+
return obj.name
|
|
125
|
+
else:
|
|
126
|
+
return f"<object of type: {type(obj)}>"
|
|
127
|
+
|
|
128
|
+
class ProxySystem:
|
|
129
|
+
|
|
130
|
+
# def bind(self, obj): pass
|
|
131
|
+
|
|
132
|
+
def wrap_int_to_ext(self, obj): return obj
|
|
133
|
+
|
|
134
|
+
def wrap_ext_to_int(self, obj): return obj
|
|
135
|
+
|
|
136
|
+
def on_int_call(self, func, *args, **kwargs):
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
def on_ext_result(self, result):
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
def on_ext_error(self, err_type, err_value, err_traceback):
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
def on_ext_call(self, func, *args, **kwargs):
|
|
146
|
+
pass
|
|
147
|
+
|
|
148
|
+
# def stacktrace(self):
|
|
149
|
+
# self.tracer.stacktrace()
|
|
150
|
+
|
|
151
|
+
def set_thread_id(self, id):
|
|
152
|
+
utils.set_thread_id(id)
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def ext_apply(self): return functional.apply
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def int_apply(self): return functional.apply
|
|
159
|
+
|
|
160
|
+
def wrap_weakref_callback(self, callback):
|
|
161
|
+
def when_internal(f):
|
|
162
|
+
return self.thread_state.dispatch(utils.noop, internal = f)
|
|
163
|
+
|
|
164
|
+
return utils.observer(
|
|
165
|
+
on_call = when_internal(self.on_weakref_callback_start),
|
|
166
|
+
on_result = when_internal(self.on_weakref_callback_end),
|
|
167
|
+
on_error = when_internal(self.on_weakref_callback_end),
|
|
168
|
+
function = callback)
|
|
169
|
+
|
|
170
|
+
def __init__(self, thread_state, immutable_types, tracer, traceargs):
|
|
171
|
+
|
|
172
|
+
self.patched_types = set()
|
|
173
|
+
self.thread_state = thread_state
|
|
174
|
+
self.fork_counter = 0
|
|
175
|
+
self.tracer = tracer
|
|
176
|
+
self.immutable_types = immutable_types
|
|
177
|
+
self.base_to_patched = {}
|
|
178
|
+
|
|
179
|
+
def should_proxy_type(cls):
|
|
180
|
+
return cls is not object and \
|
|
181
|
+
not issubclass(cls, tuple(immutable_types)) and \
|
|
182
|
+
cls not in self.patched_types
|
|
183
|
+
|
|
184
|
+
should_proxy = functional.sequence(functional.typeof, functional.memoize_one_arg(should_proxy_type))
|
|
185
|
+
|
|
186
|
+
def proxyfactory(proxytype):
|
|
187
|
+
return functional.walker(functional.when(should_proxy, maybe_proxy(proxytype)))
|
|
188
|
+
|
|
189
|
+
int_spec = SimpleNamespace(
|
|
190
|
+
apply = thread_state.wrap('internal', self.int_apply),
|
|
191
|
+
proxy = proxyfactory(thread_state.wrap('disabled', self.int_proxytype)),
|
|
192
|
+
on_call = tracer('proxy.int.call', self.on_int_call),
|
|
193
|
+
on_result = tracer('proxy.int.result'),
|
|
194
|
+
on_error = tracer('proxy.int.error'),
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
def trace_ext_call(func, *args, **kwargs):
|
|
198
|
+
self.on_ext_call(func, *args, **kwargs)
|
|
199
|
+
self.checkpoint(self.normalize_for_checkpoint({'function': func, 'args': args, 'kwargs': kwargs}))
|
|
200
|
+
|
|
201
|
+
ext_spec = SimpleNamespace(
|
|
202
|
+
apply = thread_state.wrap('external', self.ext_apply),
|
|
203
|
+
proxy = proxyfactory(thread_state.wrap('disabled', self.ext_proxytype)),
|
|
204
|
+
|
|
205
|
+
on_call = trace_ext_call if traceargs else self.on_ext_call,
|
|
206
|
+
on_result = self.on_ext_result,
|
|
207
|
+
on_error = self.on_ext_error,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
int2ext, ext2int = adapter_pair(int_spec, ext_spec)
|
|
211
|
+
|
|
212
|
+
def gateway(name, internal = functional.apply, external = functional.apply):
|
|
213
|
+
default = tracer(name, unproxy_execute)
|
|
214
|
+
return thread_state.dispatch(default, internal = internal, external = external)
|
|
215
|
+
|
|
216
|
+
self.ext_handler = thread_state.wrap('retrace', self.wrap_int_to_ext(int2ext))
|
|
217
|
+
self.int_handler = thread_state.wrap('retrace', self.wrap_ext_to_int(ext2int))
|
|
218
|
+
|
|
219
|
+
self.ext_dispatch = gateway('proxy.int.disabled.event', internal = self.ext_handler)
|
|
220
|
+
self.int_dispatch = gateway('proxy.ext.disabled.event', external = self.int_handler)
|
|
221
|
+
|
|
222
|
+
self.exclude_from_stacktrace(Tracer._write_call)
|
|
223
|
+
|
|
224
|
+
# if 'systrace' in tracer.config:
|
|
225
|
+
# func = thread_state.wrap(desired_state = 'disabled', function = tracer.systrace)
|
|
226
|
+
# func = self.thread_state.dispatch(lambda *args: None, internal = func)
|
|
227
|
+
# sys.settrace(func)
|
|
228
|
+
# self.on_new_patched = self.thread_state.dispatch(utils.noop,
|
|
229
|
+
# internal = self.on_new_ext_patched, external = self.on_new_int_patched)
|
|
230
|
+
# tracer.trace_calls(thread_state)
|
|
231
|
+
|
|
232
|
+
def disable_for(self, func):
|
|
233
|
+
return self.thread_state.wrap('disabled', func)
|
|
234
|
+
|
|
235
|
+
def new_child_path(self, path):
|
|
236
|
+
return path.parent / f'fork-{self.fork_counter}' / path.name
|
|
237
|
+
|
|
238
|
+
def before_fork(self):
|
|
239
|
+
self.saved_thread_state = self.thread_state.value
|
|
240
|
+
self.thread_state.value = 'disabled'
|
|
241
|
+
|
|
242
|
+
def after_fork_in_child(self):
|
|
243
|
+
self.thread_state.value = self.saved_thread_state
|
|
244
|
+
self.fork_counter = 0
|
|
245
|
+
|
|
246
|
+
def after_fork_in_parent(self):
|
|
247
|
+
self.thread_state.value = self.saved_thread_state
|
|
248
|
+
self.fork_counter += 1
|
|
249
|
+
|
|
250
|
+
def on_thread_exit(self, thread_id):
|
|
251
|
+
pass
|
|
252
|
+
|
|
253
|
+
# def create_stub(self): return False
|
|
254
|
+
|
|
255
|
+
def int_proxytype(self, cls):
|
|
256
|
+
if cls is object:
|
|
257
|
+
breakpoint()
|
|
258
|
+
|
|
259
|
+
return dynamic_int_proxytype(
|
|
260
|
+
handler = self.int_dispatch,
|
|
261
|
+
cls = cls,
|
|
262
|
+
bind = self.bind)
|
|
263
|
+
|
|
264
|
+
def ext_proxytype(self, cls):
|
|
265
|
+
|
|
266
|
+
proxytype = dynamic_proxytype(handler = self.ext_dispatch, cls = cls)
|
|
267
|
+
proxytype.__retrace_source__ = 'external'
|
|
268
|
+
|
|
269
|
+
if issubclass(cls, Patched):
|
|
270
|
+
patched = cls
|
|
271
|
+
elif cls in self.base_to_patched:
|
|
272
|
+
patched = self.base_to_patched[cls]
|
|
273
|
+
else:
|
|
274
|
+
patched = None
|
|
275
|
+
|
|
276
|
+
assert patched == None or patched.__base__ is not object
|
|
277
|
+
|
|
278
|
+
if patched:
|
|
279
|
+
# breakpoint()
|
|
280
|
+
|
|
281
|
+
patcher = getattr(patched, '__retrace_patch_proxy__', None)
|
|
282
|
+
if patcher: patcher(proxytype)
|
|
283
|
+
|
|
284
|
+
# for key,value in patched.__dict__.items():
|
|
285
|
+
# if callable(value) and key not in ['__new__'] and not hasattr(proxytype, key):
|
|
286
|
+
# setattr(proxytype, key, value)
|
|
287
|
+
|
|
288
|
+
return proxytype
|
|
289
|
+
|
|
290
|
+
def function_target(self, obj): return obj
|
|
291
|
+
|
|
292
|
+
def proxy_function(self, func, **kwargs):
|
|
293
|
+
if is_instance_method(func):
|
|
294
|
+
return self.thread_state.method_dispatch(func, **kwargs)
|
|
295
|
+
else:
|
|
296
|
+
f = self.thread_state.dispatch(func, **kwargs)
|
|
297
|
+
|
|
298
|
+
if isinstance(func, staticmethod):
|
|
299
|
+
return staticmethod(f)
|
|
300
|
+
elif isinstance(func, classmethod):
|
|
301
|
+
return classmethod(f)
|
|
302
|
+
else:
|
|
303
|
+
return f
|
|
304
|
+
|
|
305
|
+
def proxy_ext_function(self, func):
|
|
306
|
+
proxied = utils.wrapped_function(handler = self.ext_handler, target = func)
|
|
307
|
+
return self.proxy_function(func = func, internal = proxied)
|
|
308
|
+
|
|
309
|
+
def proxy_int_function(self, func):
|
|
310
|
+
proxied = utils.wrapped_function(handler = self.int_handler, target = func)
|
|
311
|
+
return self.proxy_function(func = func, external = proxied)
|
|
312
|
+
|
|
313
|
+
def proxy_ext_member(self, member):
|
|
314
|
+
return utils.wrapped_member(handler = self.ext_dispatch, target = member)
|
|
315
|
+
|
|
316
|
+
def proxy_int_member(self, member):
|
|
317
|
+
return utils.wrapped_member(handler = self.int_dispatch, target = member)
|
|
318
|
+
|
|
319
|
+
# def proxy__new__(self, *args, **kwargs):
|
|
320
|
+
# return self.ext_handler(*args, **kwargs)
|
|
321
|
+
|
|
322
|
+
# def on_new_ext_patched(self, obj):
|
|
323
|
+
# print(f'HWE!!!!!!!!!!! 2')
|
|
324
|
+
# print(f'HWE!!!!!!!!!!! 3')
|
|
325
|
+
# return id(obj)
|
|
326
|
+
|
|
327
|
+
# def on_new_int_patched(self, obj):
|
|
328
|
+
# return id(obj)
|
|
329
|
+
|
|
330
|
+
# def on_del_patched(self, ref):
|
|
331
|
+
# pass
|
|
332
|
+
|
|
333
|
+
# def create_from_external(self, obj):
|
|
334
|
+
# pass
|
|
335
|
+
# breakpoint()
|
|
336
|
+
|
|
337
|
+
def patch_type(self, cls):
|
|
338
|
+
|
|
339
|
+
# breakpoint()
|
|
340
|
+
|
|
341
|
+
assert isinstance(cls, type)
|
|
342
|
+
|
|
343
|
+
if issubclass(cls, BaseException): breakpoint()
|
|
344
|
+
|
|
345
|
+
assert not issubclass(cls, BaseException)
|
|
346
|
+
|
|
347
|
+
assert cls not in self.patched_types
|
|
348
|
+
|
|
349
|
+
self.patched_types.add(cls)
|
|
350
|
+
|
|
351
|
+
# if a method returns a patched object... what to do
|
|
352
|
+
# well if its a subclass, may need to return id as may have local state
|
|
353
|
+
# a subclass will have an associated id, should have been created via __new__
|
|
354
|
+
# if not a subclass, create empty proxy, what about object identity?
|
|
355
|
+
|
|
356
|
+
# track ALL creations ? override tp_alloc ?
|
|
357
|
+
# patch tp_alloc and tp_dealloc to call lifecycle object
|
|
358
|
+
# given a lifecycle, can attach to a class
|
|
359
|
+
# have one function attach_lifecycle, on_new returns token passed to on_del function
|
|
360
|
+
|
|
361
|
+
def proxy_attrs(cls, dict, proxy_function, proxy_member):
|
|
362
|
+
|
|
363
|
+
blacklist = ['__new__', '__getattribute__', '__del__', '__dict__']
|
|
364
|
+
|
|
365
|
+
for name, value in dict.items():
|
|
366
|
+
if name not in blacklist:
|
|
367
|
+
if type(value) in [types.MemberDescriptorType, types.GetSetDescriptorType]:
|
|
368
|
+
setattr(cls, name, proxy_member(value))
|
|
369
|
+
elif callable(value):
|
|
370
|
+
setattr(cls, name, proxy_function(value))
|
|
371
|
+
|
|
372
|
+
with WithoutFlags(cls, "Py_TPFLAGS_IMMUTABLETYPE"):
|
|
373
|
+
|
|
374
|
+
proxy_attrs(
|
|
375
|
+
cls,
|
|
376
|
+
dict = superdict(cls),
|
|
377
|
+
proxy_function = self.proxy_ext_function,
|
|
378
|
+
proxy_member = self.proxy_ext_member)
|
|
379
|
+
|
|
380
|
+
on_alloc = self.thread_state.dispatch(
|
|
381
|
+
utils.noop,
|
|
382
|
+
internal = self.bind,
|
|
383
|
+
external = self.create_from_external)
|
|
384
|
+
|
|
385
|
+
utils.set_on_alloc(cls, on_alloc)
|
|
386
|
+
|
|
387
|
+
cls.__retrace_system__ = self
|
|
388
|
+
|
|
389
|
+
if utils.is_extendable(cls):
|
|
390
|
+
def init_subclass(cls, **kwargs):
|
|
391
|
+
|
|
392
|
+
self.patched_types.add(cls)
|
|
393
|
+
|
|
394
|
+
def proxy_function(obj):
|
|
395
|
+
return utils.wrapped_function(handler = self.int_handler, target = obj)
|
|
396
|
+
|
|
397
|
+
proxy_attrs(
|
|
398
|
+
cls,
|
|
399
|
+
dict = cls.__dict__,
|
|
400
|
+
proxy_function = self.proxy_int_function,
|
|
401
|
+
proxy_member = self.proxy_int_member)
|
|
402
|
+
|
|
403
|
+
cls.__init_subclass__ = classmethod(init_subclass)
|
|
404
|
+
|
|
405
|
+
for subtype in get_all_subtypes(cls):
|
|
406
|
+
init_subclass(subtype)
|
|
407
|
+
utils.set_on_alloc(subtype, on_alloc)
|
|
408
|
+
|
|
409
|
+
cls.__retrace__ = self
|
|
410
|
+
|
|
411
|
+
self.bind(cls)
|
|
412
|
+
|
|
413
|
+
return cls
|
|
414
|
+
|
|
415
|
+
# def is_entry_frame(self, frame):
|
|
416
|
+
# return frame.globals.get("__name__", None) == "__main__"
|
|
417
|
+
|
|
418
|
+
def proxy_value(self, obj):
|
|
419
|
+
utils.sigtrap('proxy_value')
|
|
420
|
+
|
|
421
|
+
proxytype = dynamic_proxytype(handler = self.ext_dispatch, cls = type(obj))
|
|
422
|
+
proxytype.__retrace_source__ = 'external'
|
|
423
|
+
|
|
424
|
+
return utils.create_wrapped(proxytype, obj)
|
|
425
|
+
|
|
426
|
+
def __call__(self, obj):
|
|
427
|
+
assert not isinstance(obj, BaseException)
|
|
428
|
+
assert not isinstance(obj, Proxy)
|
|
429
|
+
assert not isinstance(obj, utils.wrapped_function)
|
|
430
|
+
|
|
431
|
+
if type(obj) == type:
|
|
432
|
+
return self.patch_type(obj)
|
|
433
|
+
|
|
434
|
+
elif type(obj) in self.immutable_types:
|
|
435
|
+
return obj
|
|
436
|
+
|
|
437
|
+
elif is_function_type(type(obj)):
|
|
438
|
+
return self.thread_state.dispatch(obj, internal = self.proxy_ext_function(obj))
|
|
439
|
+
|
|
440
|
+
elif type(obj) == types.ClassMethodDescriptorType:
|
|
441
|
+
func = self.thread_state.dispatch(obj, internal = self.proxy_ext_function(obj))
|
|
442
|
+
return classmethod(func)
|
|
443
|
+
else:
|
|
444
|
+
return self.proxy_value(obj)
|
|
445
|
+
|
|
446
|
+
# def write_trace(self, obj):
|
|
447
|
+
|
|
448
|
+
# exclude = set([
|
|
449
|
+
# "ABCMeta.__subclasscheck__"
|
|
450
|
+
# # "__subclasscheck__"
|
|
451
|
+
# ])
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
|