retracesoftware-proxy 0.1.21__py3-none-any.whl → 0.2.0__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/__main__.py +266 -0
- retracesoftware/autoenable.py +53 -0
- retracesoftware/config.json +19 -295
- retracesoftware/install/config.py +6 -0
- retracesoftware/install/edgecases.py +23 -1
- retracesoftware/install/patcher.py +93 -649
- retracesoftware/install/patchfindspec.py +117 -0
- retracesoftware/install/phases.py +338 -0
- retracesoftware/install/record.py +97 -37
- retracesoftware/install/replace.py +28 -0
- retracesoftware/install/replay.py +55 -11
- retracesoftware/install/tracer.py +87 -77
- retracesoftware/modules.toml +384 -0
- retracesoftware/proxy/messagestream.py +204 -0
- retracesoftware/proxy/proxysystem.py +283 -64
- retracesoftware/proxy/proxytype.py +34 -10
- retracesoftware/proxy/record.py +97 -64
- retracesoftware/proxy/replay.py +62 -219
- retracesoftware/proxy/serializer.py +28 -0
- retracesoftware/proxy/startthread.py +40 -0
- retracesoftware/proxy/stubfactory.py +42 -19
- retracesoftware/replay.py +104 -0
- retracesoftware/run.py +373 -0
- retracesoftware/stackdifference.py +133 -0
- {retracesoftware_proxy-0.1.21.dist-info → retracesoftware_proxy-0.2.0.dist-info}/METADATA +2 -1
- retracesoftware_proxy-0.2.0.dist-info/RECORD +41 -0
- retracesoftware_proxy-0.1.21.dist-info/RECORD +0 -29
- {retracesoftware_proxy-0.1.21.dist-info → retracesoftware_proxy-0.2.0.dist-info}/WHEEL +0 -0
- {retracesoftware_proxy-0.1.21.dist-info → retracesoftware_proxy-0.2.0.dist-info}/top_level.txt +0 -0
|
@@ -5,10 +5,16 @@ from retracesoftware.proxy.gateway import adapter_pair
|
|
|
5
5
|
from types import SimpleNamespace
|
|
6
6
|
from retracesoftware.proxy.proxytype import *
|
|
7
7
|
from retracesoftware.proxy.stubfactory import Stub
|
|
8
|
-
from retracesoftware.install.typeutils import modify, WithFlags
|
|
8
|
+
from retracesoftware.install.typeutils import modify, WithFlags, WithoutFlags
|
|
9
9
|
|
|
10
|
+
from retracesoftware.proxy.serializer import serializer
|
|
11
|
+
from retracesoftware.install.tracer import Tracer
|
|
10
12
|
import sys
|
|
11
13
|
import gc
|
|
14
|
+
import weakref
|
|
15
|
+
import enum
|
|
16
|
+
import functools
|
|
17
|
+
import re
|
|
12
18
|
|
|
13
19
|
class RetraceError(Exception):
|
|
14
20
|
pass
|
|
@@ -25,6 +31,12 @@ def maybe_proxy(proxytype):
|
|
|
25
31
|
utils.unwrap,
|
|
26
32
|
proxy(functional.memoize_one_arg(proxytype)))
|
|
27
33
|
|
|
34
|
+
class Patched:
|
|
35
|
+
__slots__ = ()
|
|
36
|
+
|
|
37
|
+
class RetraceBase:
|
|
38
|
+
pass
|
|
39
|
+
|
|
28
40
|
unproxy_execute = functional.mapargs(starting = 1,
|
|
29
41
|
transform = functional.walker(utils.try_unwrap),
|
|
30
42
|
function = functional.apply)
|
|
@@ -45,9 +57,77 @@ method_types = (types.MethodDescriptorType,
|
|
|
45
57
|
def is_instance_method(obj):
|
|
46
58
|
return isinstance(obj, method_types)
|
|
47
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
|
+
|
|
48
128
|
class ProxySystem:
|
|
49
129
|
|
|
50
|
-
def bind(self, obj): pass
|
|
130
|
+
# def bind(self, obj): pass
|
|
51
131
|
|
|
52
132
|
def wrap_int_to_ext(self, obj): return obj
|
|
53
133
|
|
|
@@ -62,40 +142,67 @@ class ProxySystem:
|
|
|
62
142
|
def on_ext_error(self, err_type, err_value, err_traceback):
|
|
63
143
|
pass
|
|
64
144
|
|
|
145
|
+
def on_ext_call(self, func, *args, **kwargs):
|
|
146
|
+
pass
|
|
147
|
+
|
|
65
148
|
# def stacktrace(self):
|
|
66
149
|
# self.tracer.stacktrace()
|
|
67
150
|
|
|
68
151
|
def set_thread_id(self, id):
|
|
69
152
|
utils.set_thread_id(id)
|
|
70
153
|
|
|
71
|
-
|
|
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)
|
|
72
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()
|
|
73
173
|
self.thread_state = thread_state
|
|
74
174
|
self.fork_counter = 0
|
|
75
175
|
self.tracer = tracer
|
|
76
176
|
self.immutable_types = immutable_types
|
|
77
|
-
self.
|
|
78
|
-
|
|
79
|
-
def
|
|
80
|
-
return cls is object
|
|
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
|
|
81
183
|
|
|
82
|
-
|
|
184
|
+
should_proxy = functional.sequence(functional.typeof, functional.memoize_one_arg(should_proxy_type))
|
|
83
185
|
|
|
84
186
|
def proxyfactory(proxytype):
|
|
85
|
-
return functional.walker(functional.
|
|
187
|
+
return functional.walker(functional.when(should_proxy, maybe_proxy(proxytype)))
|
|
86
188
|
|
|
87
189
|
int_spec = SimpleNamespace(
|
|
88
|
-
apply = thread_state.wrap('internal',
|
|
190
|
+
apply = thread_state.wrap('internal', self.int_apply),
|
|
89
191
|
proxy = proxyfactory(thread_state.wrap('disabled', self.int_proxytype)),
|
|
90
192
|
on_call = tracer('proxy.int.call', self.on_int_call),
|
|
91
193
|
on_result = tracer('proxy.int.result'),
|
|
92
194
|
on_error = tracer('proxy.int.error'),
|
|
93
195
|
)
|
|
94
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
|
+
|
|
95
201
|
ext_spec = SimpleNamespace(
|
|
96
|
-
apply = thread_state.wrap('external',
|
|
202
|
+
apply = thread_state.wrap('external', self.ext_apply),
|
|
97
203
|
proxy = proxyfactory(thread_state.wrap('disabled', self.ext_proxytype)),
|
|
98
|
-
|
|
204
|
+
|
|
205
|
+
on_call = trace_ext_call if traceargs else self.on_ext_call,
|
|
99
206
|
on_result = self.on_ext_result,
|
|
100
207
|
on_error = self.on_ext_error,
|
|
101
208
|
)
|
|
@@ -112,13 +219,19 @@ class ProxySystem:
|
|
|
112
219
|
self.ext_dispatch = gateway('proxy.int.disabled.event', internal = self.ext_handler)
|
|
113
220
|
self.int_dispatch = gateway('proxy.ext.disabled.event', external = self.int_handler)
|
|
114
221
|
|
|
115
|
-
|
|
116
|
-
func = thread_state.wrap(desired_state = 'disabled', function = tracer.systrace)
|
|
117
|
-
func = self.thread_state.dispatch(lambda *args: None, internal = func)
|
|
118
|
-
sys.settrace(func)
|
|
222
|
+
self.exclude_from_stacktrace(Tracer._write_call)
|
|
119
223
|
|
|
120
|
-
tracer.
|
|
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)
|
|
121
231
|
|
|
232
|
+
def disable_for(self, func):
|
|
233
|
+
return self.thread_state.wrap('disabled', func)
|
|
234
|
+
|
|
122
235
|
def new_child_path(self, path):
|
|
123
236
|
return path.parent / f'fork-{self.fork_counter}' / path.name
|
|
124
237
|
|
|
@@ -143,70 +256,172 @@ class ProxySystem:
|
|
|
143
256
|
if cls is object:
|
|
144
257
|
breakpoint()
|
|
145
258
|
|
|
146
|
-
|
|
259
|
+
return dynamic_int_proxytype(
|
|
147
260
|
handler = self.int_dispatch,
|
|
148
261
|
cls = cls,
|
|
149
262
|
bind = self.bind)
|
|
150
263
|
|
|
151
|
-
if self.on_proxytype: self.on_proxytype(proxytype)
|
|
152
|
-
return proxytype
|
|
153
|
-
|
|
154
264
|
def ext_proxytype(self, cls):
|
|
155
|
-
if cls is object:
|
|
156
|
-
breakpoint()
|
|
157
265
|
|
|
158
266
|
proxytype = dynamic_proxytype(handler = self.ext_dispatch, cls = cls)
|
|
159
267
|
proxytype.__retrace_source__ = 'external'
|
|
160
268
|
|
|
161
|
-
if
|
|
162
|
-
|
|
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
|
+
|
|
163
288
|
return proxytype
|
|
164
289
|
|
|
165
290
|
def function_target(self, obj): return obj
|
|
166
291
|
|
|
167
|
-
def proxy_function(self,
|
|
168
|
-
|
|
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)
|
|
169
308
|
|
|
170
|
-
def
|
|
171
|
-
|
|
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)
|
|
172
312
|
|
|
173
|
-
def
|
|
174
|
-
|
|
175
|
-
with WithFlags(cls, "Py_TPFLAGS_BASETYPE"):
|
|
176
|
-
assert utils.is_extendable(cls)
|
|
177
|
-
return self.patchtype(cls)
|
|
313
|
+
def proxy_ext_member(self, member):
|
|
314
|
+
return utils.wrapped_member(handler = self.ext_dispatch, target = member)
|
|
178
315
|
|
|
179
|
-
|
|
180
|
-
|
|
316
|
+
def proxy_int_member(self, member):
|
|
317
|
+
return utils.wrapped_member(handler = self.int_dispatch, target = member)
|
|
181
318
|
|
|
182
|
-
|
|
183
|
-
|
|
319
|
+
# def proxy__new__(self, *args, **kwargs):
|
|
320
|
+
# return self.ext_handler(*args, **kwargs)
|
|
184
321
|
|
|
185
|
-
|
|
186
|
-
|
|
322
|
+
# def on_new_ext_patched(self, obj):
|
|
323
|
+
# print(f'HWE!!!!!!!!!!! 2')
|
|
324
|
+
# print(f'HWE!!!!!!!!!!! 3')
|
|
325
|
+
# return id(obj)
|
|
187
326
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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__']
|
|
194
364
|
|
|
195
|
-
|
|
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))
|
|
196
371
|
|
|
197
|
-
|
|
372
|
+
with WithoutFlags(cls, "Py_TPFLAGS_IMMUTABLETYPE"):
|
|
198
373
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
374
|
+
proxy_attrs(
|
|
375
|
+
cls,
|
|
376
|
+
dict = superdict(cls),
|
|
377
|
+
proxy_function = self.proxy_ext_function,
|
|
378
|
+
proxy_member = self.proxy_ext_member)
|
|
202
379
|
|
|
203
|
-
|
|
204
|
-
|
|
380
|
+
on_alloc = self.thread_state.dispatch(
|
|
381
|
+
utils.noop,
|
|
382
|
+
internal = self.bind,
|
|
383
|
+
external = self.create_from_external)
|
|
205
384
|
|
|
206
|
-
|
|
385
|
+
utils.set_on_alloc(cls, on_alloc)
|
|
207
386
|
|
|
208
|
-
|
|
209
|
-
|
|
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)
|
|
210
425
|
|
|
211
426
|
def __call__(self, obj):
|
|
212
427
|
assert not isinstance(obj, BaseException)
|
|
@@ -214,22 +429,26 @@ class ProxySystem:
|
|
|
214
429
|
assert not isinstance(obj, utils.wrapped_function)
|
|
215
430
|
|
|
216
431
|
if type(obj) == type:
|
|
217
|
-
return self.
|
|
432
|
+
return self.patch_type(obj)
|
|
218
433
|
|
|
219
434
|
elif type(obj) in self.immutable_types:
|
|
220
435
|
return obj
|
|
221
436
|
|
|
222
437
|
elif is_function_type(type(obj)):
|
|
223
|
-
return self.thread_state.dispatch(obj, internal = self.
|
|
438
|
+
return self.thread_state.dispatch(obj, internal = self.proxy_ext_function(obj))
|
|
224
439
|
|
|
225
440
|
elif type(obj) == types.ClassMethodDescriptorType:
|
|
226
|
-
func = self.thread_state.dispatch(obj, internal = self.
|
|
441
|
+
func = self.thread_state.dispatch(obj, internal = self.proxy_ext_function(obj))
|
|
227
442
|
return classmethod(func)
|
|
228
443
|
else:
|
|
229
|
-
|
|
230
|
-
|
|
444
|
+
return self.proxy_value(obj)
|
|
445
|
+
|
|
446
|
+
# def write_trace(self, obj):
|
|
447
|
+
|
|
448
|
+
# exclude = set([
|
|
449
|
+
# "ABCMeta.__subclasscheck__"
|
|
450
|
+
# # "__subclasscheck__"
|
|
451
|
+
# ])
|
|
231
452
|
|
|
232
|
-
if self.on_proxytype: self.on_proxytype(proxytype)
|
|
233
453
|
|
|
234
|
-
|
|
235
|
-
# raise Exception(f'object {obj} was not proxied as its not a extensible type and is not callable')
|
|
454
|
+
|
|
@@ -198,12 +198,18 @@ class DescriptorProxy:
|
|
|
198
198
|
|
|
199
199
|
def dynamic_proxytype(handler, cls):
|
|
200
200
|
|
|
201
|
+
if cls.__module__.startswith('retracesoftware'):
|
|
202
|
+
print(cls)
|
|
203
|
+
utils.sigtrap('HERE5')
|
|
204
|
+
|
|
205
|
+
assert not cls.__module__.startswith('retracesoftware')
|
|
206
|
+
|
|
201
207
|
# print(f'In dynamic_proxytype: {cls}')
|
|
202
208
|
|
|
203
209
|
assert not issubclass(cls, Proxy)
|
|
204
210
|
assert not issubclass(cls, BaseException)
|
|
205
211
|
|
|
206
|
-
blacklist = ['__getattribute__', '__hash__', '__del__', '__call__']
|
|
212
|
+
blacklist = ['__getattribute__', '__hash__', '__del__', '__call__', '__new__']
|
|
207
213
|
|
|
208
214
|
spec = {}
|
|
209
215
|
|
|
@@ -211,15 +217,27 @@ def dynamic_proxytype(handler, cls):
|
|
|
211
217
|
|
|
212
218
|
for name in superdict(cls).keys():
|
|
213
219
|
if name not in blacklist:
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
220
|
+
value = getattr(cls, name)
|
|
221
|
+
|
|
222
|
+
if issubclass(type(value), utils.dispatch):
|
|
223
|
+
value = utils.dispatch.table(value)['disabled']
|
|
224
|
+
|
|
225
|
+
# if is_descriptor(value):
|
|
226
|
+
if utils.is_method_descriptor(value):
|
|
227
|
+
spec[name] = wrap(value)
|
|
228
|
+
|
|
229
|
+
# try:
|
|
230
|
+
# value = getattr(cls, name)
|
|
231
|
+
|
|
232
|
+
# assert type(value) is not utils.dispatch
|
|
233
|
+
|
|
234
|
+
# if is_descriptor(value):
|
|
235
|
+
# if utils.is_method_descriptor(value):
|
|
236
|
+
# spec[name] = wrap(value)
|
|
237
|
+
# except Exception as error:
|
|
238
|
+
# print(f'FOO! {cls} {name} {error}')
|
|
239
|
+
# breakpoint()
|
|
240
|
+
# raise
|
|
223
241
|
|
|
224
242
|
# else:
|
|
225
243
|
# spec[name] = DescriptorProxy(handler = handler, target = value)
|
|
@@ -230,6 +248,12 @@ def dynamic_proxytype(handler, cls):
|
|
|
230
248
|
|
|
231
249
|
# spec = { name: wrap(getattr(cls, name)) for name in to_proxy }
|
|
232
250
|
|
|
251
|
+
# def foo(obj, name, default = None):
|
|
252
|
+
# print(f'dynamic_proxytype.__getattr__: {type(obj).__mro__} {name}')
|
|
253
|
+
# utils.sigtrap(obj)
|
|
254
|
+
# return getattr(obj, name, default)
|
|
255
|
+
|
|
256
|
+
# spec['__getattr__'] = wrap(foo)
|
|
233
257
|
spec['__getattr__'] = wrap(getattr)
|
|
234
258
|
spec['__setattr__'] = wrap(setattr)
|
|
235
259
|
|