retracesoftware-proxy 0.0.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/__init__.py +0 -0
- retracesoftware/__main__.py +266 -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 +242 -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 +384 -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 +373 -0
- retracesoftware/stackdifference.py +133 -0
- retracesoftware_proxy-0.0.0.dist-info/METADATA +8 -0
- retracesoftware_proxy-0.0.0.dist-info/RECORD +41 -0
- retracesoftware_proxy-0.0.0.dist-info/WHEEL +5 -0
- retracesoftware_proxy-0.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import retracesoftware.utils as utils
|
|
2
|
+
import retracesoftware.functional as functional
|
|
3
|
+
|
|
4
|
+
import types
|
|
5
|
+
|
|
6
|
+
from retracesoftware.proxy.stubfactory import StubMethodDescriptor, Stub
|
|
7
|
+
|
|
8
|
+
class Proxy:
|
|
9
|
+
__slots__ = []
|
|
10
|
+
|
|
11
|
+
class DynamicProxy(Proxy):
|
|
12
|
+
__slots__ = []
|
|
13
|
+
|
|
14
|
+
class ExtendingProxy(Proxy):
|
|
15
|
+
__slots__ = []
|
|
16
|
+
|
|
17
|
+
class InternalProxy:
|
|
18
|
+
__slots__ = []
|
|
19
|
+
|
|
20
|
+
@functional.memoize_one_arg
|
|
21
|
+
def unproxy_type(cls):
|
|
22
|
+
if not issubclass(cls, Proxy):
|
|
23
|
+
return cls
|
|
24
|
+
|
|
25
|
+
# Prefer attribute on the class, not on the mappingproxy
|
|
26
|
+
target = getattr(cls, '__retrace_target_class__', None)
|
|
27
|
+
if target is not None:
|
|
28
|
+
return unproxy_type(target)
|
|
29
|
+
|
|
30
|
+
# Rebuild with unproxied bases, preserving metaclass and critical dunder attrs
|
|
31
|
+
new_bases = tuple(map(unproxy_type, cls.__bases__))
|
|
32
|
+
|
|
33
|
+
# Copy attrs, but omit implementation-managed ones
|
|
34
|
+
attrs = {}
|
|
35
|
+
classcell = None
|
|
36
|
+
for k, v in cls.__dict__.items():
|
|
37
|
+
if k in ('__dict__', '__weakref__'):
|
|
38
|
+
continue
|
|
39
|
+
if k == '__classcell__':
|
|
40
|
+
# must be passed through at class creation for zero-arg super()
|
|
41
|
+
classcell = v
|
|
42
|
+
continue
|
|
43
|
+
attrs[k] = v
|
|
44
|
+
|
|
45
|
+
# Ensure module/doc are kept (in case they weren't in __dict__)
|
|
46
|
+
attrs.setdefault('__module__', cls.__module__)
|
|
47
|
+
attrs.setdefault('__doc__', cls.__doc__)
|
|
48
|
+
|
|
49
|
+
# Use types.new_class if you want full class-creation protocol
|
|
50
|
+
def exec_body(ns):
|
|
51
|
+
ns.update(attrs)
|
|
52
|
+
if classcell is not None:
|
|
53
|
+
ns['__classcell__'] = classcell
|
|
54
|
+
|
|
55
|
+
return types.new_class(cls.__name__, new_bases, {'metaclass': type(cls)}, exec_body)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def superdict(cls):
|
|
59
|
+
result = {}
|
|
60
|
+
for cls in list(reversed(cls.__mro__))[1:]:
|
|
61
|
+
result.update(cls.__dict__)
|
|
62
|
+
|
|
63
|
+
return result
|
|
64
|
+
|
|
65
|
+
def is_method_descriptor(obj):
|
|
66
|
+
return isinstance(obj, types.FunctionType) or \
|
|
67
|
+
(isinstance(obj, (types.WrapperDescriptorType,
|
|
68
|
+
types.MethodDescriptorType,
|
|
69
|
+
StubMethodDescriptor)) and obj.__objclass__ != object)
|
|
70
|
+
|
|
71
|
+
def proxy_method_descriptors(cls, handler):
|
|
72
|
+
for name, target in cls.__dict__.items():
|
|
73
|
+
if is_method_descriptor(target):
|
|
74
|
+
proxied = utils.wrapped_function(handler = handler, target = target)
|
|
75
|
+
setattr(cls, name, proxied)
|
|
76
|
+
|
|
77
|
+
def methods(cls):
|
|
78
|
+
for name,value in superdict(cls).items():
|
|
79
|
+
if is_descriptor(value) and is_method_descriptor(value):
|
|
80
|
+
yield name
|
|
81
|
+
|
|
82
|
+
def is_descriptor(obj):
|
|
83
|
+
return hasattr(obj, '__get__') or hasattr(obj, '__set__') or hasattr(obj, '__delete__')
|
|
84
|
+
|
|
85
|
+
class Named:
|
|
86
|
+
def __init__(self, name):
|
|
87
|
+
self.__name__ = name
|
|
88
|
+
|
|
89
|
+
class DescriptorStub:
|
|
90
|
+
|
|
91
|
+
__slots__ = ['handler', 'name']
|
|
92
|
+
|
|
93
|
+
def __init__(self, handler, name):
|
|
94
|
+
self.handler = handler
|
|
95
|
+
self.name = name
|
|
96
|
+
|
|
97
|
+
def __get__(self, instance, owner):
|
|
98
|
+
return self.handler(Named('getattr'), self.name)
|
|
99
|
+
|
|
100
|
+
def __set__(self, instance, value):
|
|
101
|
+
return self.handler(Named('setattr'), self.name, value)
|
|
102
|
+
|
|
103
|
+
def __delete__(self, instance):
|
|
104
|
+
return self.handler(Named('delattr'), self.name)
|
|
105
|
+
|
|
106
|
+
def stubtype_from_spec(handler, module, name, methods, members):
|
|
107
|
+
|
|
108
|
+
spec = {
|
|
109
|
+
'__module__': module,
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for method in methods:
|
|
113
|
+
spec[method] = utils.wrapped_function(
|
|
114
|
+
handler = handler, target = Named(method))
|
|
115
|
+
|
|
116
|
+
for member in members:
|
|
117
|
+
spec[member] = DescriptorStub(handler = handler, name = member)
|
|
118
|
+
|
|
119
|
+
return type(name, (Stub, DynamicProxy,), spec)
|
|
120
|
+
|
|
121
|
+
# stubtype.__new__ = thread_state.dispatch(disabled__new__, internal = stub.__new__, external = stub.__new__)
|
|
122
|
+
# stub.__retrace_unproxied__ = cls
|
|
123
|
+
|
|
124
|
+
def dynamic_stubtype(handler, cls):
|
|
125
|
+
|
|
126
|
+
assert not issubclass(cls, BaseException)
|
|
127
|
+
|
|
128
|
+
blacklist = ['__getattribute__', '__hash__', '__del__', '__call__']
|
|
129
|
+
|
|
130
|
+
to_proxy = [m for m in methods(cls) if m not in blacklist]
|
|
131
|
+
|
|
132
|
+
def wrap(name): return utils.wrapped_function(handler = handler,
|
|
133
|
+
target = Named(name))
|
|
134
|
+
|
|
135
|
+
spec = { name: wrap(name) for name in to_proxy }
|
|
136
|
+
|
|
137
|
+
spec['__getattr__'] = wrap('__getattr__')
|
|
138
|
+
spec['__setattr__'] = wrap('__setattr__')
|
|
139
|
+
|
|
140
|
+
if utils.yields_callable_instances(cls):
|
|
141
|
+
spec['__call__'] = handler
|
|
142
|
+
|
|
143
|
+
spec['__retrace_target_class__'] = cls
|
|
144
|
+
|
|
145
|
+
target_type = functional.sequence(utils.unwrap, functional.typeof)
|
|
146
|
+
spec['__class__'] = property(target_type)
|
|
147
|
+
|
|
148
|
+
spec['__module__'] = cls.__module__
|
|
149
|
+
spec['__qualname__'] = cls.__name__
|
|
150
|
+
|
|
151
|
+
# name = f'retrace.proxied.{cls.__module__}.{cls.__name__}'
|
|
152
|
+
|
|
153
|
+
return type(cls.__name__, (Stub, DynamicProxy), spec)
|
|
154
|
+
|
|
155
|
+
class DescriptorProxy:
|
|
156
|
+
__slots__ = ['target', 'handler']
|
|
157
|
+
|
|
158
|
+
def __init__(self, handler, target):
|
|
159
|
+
self.handler = handler
|
|
160
|
+
self.target = target
|
|
161
|
+
|
|
162
|
+
def __get__(self, obj, cls):
|
|
163
|
+
try:
|
|
164
|
+
return self.handler(self.target.__get__, obj, cls)
|
|
165
|
+
except:
|
|
166
|
+
print(f'error calling __get__')
|
|
167
|
+
raise
|
|
168
|
+
|
|
169
|
+
def __set__(self, obj, value):
|
|
170
|
+
return self.handler(self.target.__set__, obj, value)
|
|
171
|
+
|
|
172
|
+
def __delete__(self, obj):
|
|
173
|
+
return self.handler(self.target.__delete__, obj)
|
|
174
|
+
|
|
175
|
+
# class ExtendingDescriptorProxy:
|
|
176
|
+
|
|
177
|
+
# __slots__ = ['handler', 'proxytype', 'name']
|
|
178
|
+
|
|
179
|
+
# def __init__(self, proxytype, handler, name):
|
|
180
|
+
# self.proxytype = proxytype
|
|
181
|
+
# self.handler = handler
|
|
182
|
+
# self.name = name
|
|
183
|
+
|
|
184
|
+
# def __get__(self, instance, owner):
|
|
185
|
+
# inst = owner if instance is None else instance
|
|
186
|
+
# getter = functional.partial(getattr, super(self.proxytype, inst))
|
|
187
|
+
# return self.handler(getter, self.name)
|
|
188
|
+
|
|
189
|
+
# def __set__(self, instance, value):
|
|
190
|
+
# breakpoint()
|
|
191
|
+
# setter = functional.partial(setattr, super(self.proxytype, instance))
|
|
192
|
+
# return self.handler(setter, self.name, value)
|
|
193
|
+
|
|
194
|
+
# def __delete__(self, instance):
|
|
195
|
+
# deleter = functional.partial(delattr, super(self.proxytype, instance))
|
|
196
|
+
# return self.handler(deleter, self.name)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def dynamic_proxytype(handler, cls):
|
|
200
|
+
|
|
201
|
+
if cls.__module__.startswith('retracesoftware'):
|
|
202
|
+
print(cls)
|
|
203
|
+
utils.sigtrap('HERE5')
|
|
204
|
+
|
|
205
|
+
assert not cls.__module__.startswith('retracesoftware')
|
|
206
|
+
|
|
207
|
+
# print(f'In dynamic_proxytype: {cls}')
|
|
208
|
+
|
|
209
|
+
assert not issubclass(cls, Proxy)
|
|
210
|
+
assert not issubclass(cls, BaseException)
|
|
211
|
+
|
|
212
|
+
blacklist = ['__getattribute__', '__hash__', '__del__', '__call__', '__new__']
|
|
213
|
+
|
|
214
|
+
spec = {}
|
|
215
|
+
|
|
216
|
+
def wrap(func): return utils.wrapped_function(handler = handler, target = func)
|
|
217
|
+
|
|
218
|
+
for name in superdict(cls).keys():
|
|
219
|
+
if name not in blacklist:
|
|
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
|
|
241
|
+
|
|
242
|
+
# else:
|
|
243
|
+
# spec[name] = DescriptorProxy(handler = handler, target = value)
|
|
244
|
+
|
|
245
|
+
# to_proxy = [m for m in methods(cls) if m not in blacklist]
|
|
246
|
+
|
|
247
|
+
# def wrap(target): return utils.wrapped_function(handler = handler, target = target)
|
|
248
|
+
|
|
249
|
+
# spec = { name: wrap(getattr(cls, name)) for name in to_proxy }
|
|
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)
|
|
257
|
+
spec['__getattr__'] = wrap(getattr)
|
|
258
|
+
spec['__setattr__'] = wrap(setattr)
|
|
259
|
+
|
|
260
|
+
if utils.yields_callable_instances(cls):
|
|
261
|
+
spec['__call__'] = handler
|
|
262
|
+
|
|
263
|
+
spec['__retrace_target_class__'] = cls
|
|
264
|
+
|
|
265
|
+
# target_type = functional.sequence(utils.unwrap, functional.typeof)
|
|
266
|
+
|
|
267
|
+
target_type = cls.__retrace_target_type__ if issubclass(cls, Stub) else cls
|
|
268
|
+
# functional.repeatedly(resolved)
|
|
269
|
+
|
|
270
|
+
# spec['__class__'] = property(target_type)
|
|
271
|
+
spec['__class__'] = property(functional.constantly(target_type))
|
|
272
|
+
|
|
273
|
+
spec['__name__'] = cls.__name__
|
|
274
|
+
spec['__module__'] = cls.__module__
|
|
275
|
+
# name = f'retrace.proxied.{cls.__module__}.{cls.__name__}'
|
|
276
|
+
|
|
277
|
+
return type(cls.__name__, (utils.Wrapped, DynamicProxy), spec)
|
|
278
|
+
|
|
279
|
+
def dynamic_from_extended(cls):
|
|
280
|
+
|
|
281
|
+
base = cls.__base__
|
|
282
|
+
|
|
283
|
+
name = f'retrace.proxied1.{base.__module__}.{base.__name__}'
|
|
284
|
+
|
|
285
|
+
spec = dict(cls.__dict__)
|
|
286
|
+
|
|
287
|
+
spec['__retrace_target_class__'] = base
|
|
288
|
+
|
|
289
|
+
del spec['__init_subclass__']
|
|
290
|
+
# del spec['__new__']
|
|
291
|
+
|
|
292
|
+
target_type = functional.sequence(utils.unwrap, functional.typeof)
|
|
293
|
+
spec['__class__'] = property(target_type)
|
|
294
|
+
|
|
295
|
+
return type(name, (utils.Wrapped, DynamicProxy), spec)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def instantiable_dynamic_proxytype(handler, cls, thread_state, create_stub = False):
|
|
299
|
+
|
|
300
|
+
proxytype = dynamic_proxytype(handler = handler, cls = cls)
|
|
301
|
+
|
|
302
|
+
def create_original(proxytype, *args, **kwargs):
|
|
303
|
+
instance = cls(*args, **kwargs)
|
|
304
|
+
instance.__init__(*args, **kwargs)
|
|
305
|
+
return instance
|
|
306
|
+
|
|
307
|
+
def __new__(proxytype, *args, **kwargs):
|
|
308
|
+
instance = utils.create_stub_object(cls) if create_stub else cls(*args, **kwargs)
|
|
309
|
+
return utils.create_wrapped(proxytype, instance)
|
|
310
|
+
|
|
311
|
+
proxytype.__new__ = thread_state.dispatch(create_original, internal = __new__)
|
|
312
|
+
|
|
313
|
+
return proxytype
|
|
314
|
+
|
|
315
|
+
def dynamic_int_proxytype(handler, cls, bind):
|
|
316
|
+
proxytype = dynamic_proxytype(handler = handler, cls = cls)
|
|
317
|
+
proxytype.__new__ = functional.sequence(proxytype.__new__, functional.side_effect(bind))
|
|
318
|
+
proxytype.__retrace_source__ = 'internal'
|
|
319
|
+
return proxytype
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
blacklist = ['__getattribute__', '__hash__', '__del__', '__dict__']
|
|
323
|
+
|
|
324
|
+
# if the type can be patched, thats better, all new instances must be of correct type
|
|
325
|
+
|
|
326
|
+
# def make_extensible(thread_state, proxy_method_descriptor, cls):
|
|
327
|
+
|
|
328
|
+
# @functional.memoize_one_arg
|
|
329
|
+
# def proxy_subclass(subclass):
|
|
330
|
+
# if '__retrace_target_type__' in subclass.__dict__:
|
|
331
|
+
# return subclass
|
|
332
|
+
|
|
333
|
+
# attrs = {k: proxy_method_descriptor(v) for k, v in subclass.__dict__.items() if is_method_descriptor(v) }
|
|
334
|
+
|
|
335
|
+
# # Ensure module/doc are kept (in case they weren't in __dict__)
|
|
336
|
+
# attrs.setdefault('__module__', subclass.__module__)
|
|
337
|
+
# attrs.setdefault('__doc__', subclass.__doc__)
|
|
338
|
+
# attrs['__retrace_target_type__'] = subclass
|
|
339
|
+
|
|
340
|
+
# return type(subclass.__name__, (subclass,), attrs)
|
|
341
|
+
|
|
342
|
+
# orig__new__ = cls.__new__
|
|
343
|
+
|
|
344
|
+
# def proxied__new__(subclass, *args, **kwargs):
|
|
345
|
+
# nonlocal orig__new__
|
|
346
|
+
# return orig__new__(proxy_subclass(subclass), *args, **kwargs)
|
|
347
|
+
|
|
348
|
+
# def unproxied__new__(subclass, *args, **kwargs):
|
|
349
|
+
# return unproxy_type(subclass)(*args, **kwargs)
|
|
350
|
+
|
|
351
|
+
# # Dispatch which constructor to use based on your thread_state policy
|
|
352
|
+
# cls.__new__ = thread_state.dispatch(unproxied__new__, internal = proxied__new__)
|
|
353
|
+
|
|
354
|
+
def create_unproxied_type(cls):
|
|
355
|
+
def unproxy_type(cls):
|
|
356
|
+
return cls.__dict__.get('__retrace_unproxied__', cls)
|
|
357
|
+
|
|
358
|
+
bases = tuple(map(unproxy_type, cls.__bases__))
|
|
359
|
+
slots = dict(cls.__dict__)
|
|
360
|
+
|
|
361
|
+
if '__slots__' in slots:
|
|
362
|
+
for slot in slots['__slots__']:
|
|
363
|
+
slots.pop(slot)
|
|
364
|
+
|
|
365
|
+
# del slots['__init_subclass__']
|
|
366
|
+
return type(cls.__name__, tuple(bases), slots)
|
|
367
|
+
|
|
368
|
+
def extending_proxytype(cls, base, thread_state, ext_handler, int_handler, on_subclass_new):
|
|
369
|
+
|
|
370
|
+
# assert cls is base
|
|
371
|
+
assert not issubclass(cls, BaseException)
|
|
372
|
+
assert not issubclass(cls, ExtendingProxy)
|
|
373
|
+
|
|
374
|
+
def init_subclass(subclass, **kwargs):
|
|
375
|
+
# print(f'In init_subclass: {subclass} {subclass.__mro__} {kwargs}')
|
|
376
|
+
unproxied = create_unproxied_type(subclass)
|
|
377
|
+
subclass.__retrace_unproxied__ = unproxied
|
|
378
|
+
|
|
379
|
+
proxy_method_descriptors(cls = subclass, handler = int_handler)
|
|
380
|
+
|
|
381
|
+
if not issubclass(subclass, InternalProxy):
|
|
382
|
+
subclass.__new__ = functional.sequence(subclass.__new__, functional.side_effect(on_subclass_new))
|
|
383
|
+
subclass.__bases__ = subclass.__bases__ + (InternalProxy,)
|
|
384
|
+
|
|
385
|
+
assert not issubclass(subclass.__retrace_unproxied__, ExtendingProxy)
|
|
386
|
+
|
|
387
|
+
slots = { "__slots__": (),
|
|
388
|
+
"__retrace_unproxied__": cls,
|
|
389
|
+
"__module__": cls.__module__,
|
|
390
|
+
"__init_subclass__": init_subclass }
|
|
391
|
+
|
|
392
|
+
def wrap(target): return utils.wrapped_function(handler = ext_handler, target = target)
|
|
393
|
+
|
|
394
|
+
descriptors = []
|
|
395
|
+
|
|
396
|
+
for name,value in superdict(cls).items():
|
|
397
|
+
if name not in blacklist:
|
|
398
|
+
if is_method_descriptor(value):
|
|
399
|
+
slots[name] = wrap(getattr(base, name))
|
|
400
|
+
elif is_descriptor(value):
|
|
401
|
+
descriptors.append(name)
|
|
402
|
+
|
|
403
|
+
slots['__retrace_unproxied__'] = cls
|
|
404
|
+
|
|
405
|
+
extended = type(cls.__name__, (base, ExtendingProxy), slots)
|
|
406
|
+
|
|
407
|
+
for name in descriptors:
|
|
408
|
+
# proxy = ExtendingDescriptorProxy(handler = ext_handler, name = name, proxytype = extended)
|
|
409
|
+
proxy = DescriptorProxy(handler = ext_handler, target = getattr(cls, name))
|
|
410
|
+
setattr(extended, name, proxy)
|
|
411
|
+
|
|
412
|
+
def unproxied__new__(subclass, *args, **kwargs):
|
|
413
|
+
return subclass.__retrace_unproxied__(*args, **kwargs)
|
|
414
|
+
|
|
415
|
+
assert callable(base.__new__)
|
|
416
|
+
|
|
417
|
+
extended.__new__ = thread_state.dispatch(unproxied__new__, internal = base.__new__)
|
|
418
|
+
|
|
419
|
+
assert not issubclass(extended.__retrace_unproxied__, ExtendingProxy)
|
|
420
|
+
assert extended.__dict__['__retrace_unproxied__'] is extended.__retrace_unproxied__
|
|
421
|
+
# print(f'FOO: {extended} {id(extended)} {id(extended.__retrace_unproxied__)}')
|
|
422
|
+
# breakpoint()
|
|
423
|
+
|
|
424
|
+
return extended
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import retracesoftware.functional as functional
|
|
2
|
+
import retracesoftware.utils as utils
|
|
3
|
+
import retracesoftware.stream as stream
|
|
4
|
+
|
|
5
|
+
from retracesoftware.proxy.proxytype import *
|
|
6
|
+
# from retracesoftware.proxy.gateway import gateway_pair
|
|
7
|
+
from retracesoftware.proxy.proxysystem import ProxySystem
|
|
8
|
+
from retracesoftware.proxy.thread import write_thread_switch, ThreadSwitch, thread_id
|
|
9
|
+
from retracesoftware.install.tracer import Tracer
|
|
10
|
+
from retracesoftware.install.patchfindspec import patch_find_spec
|
|
11
|
+
from retracesoftware.proxy.stubfactory import StubRef, ExtendedRef
|
|
12
|
+
from retracesoftware.proxy.globalref import GlobalRef
|
|
13
|
+
|
|
14
|
+
import sys
|
|
15
|
+
import os
|
|
16
|
+
import types
|
|
17
|
+
import gc
|
|
18
|
+
|
|
19
|
+
# class Placeholder:
|
|
20
|
+
# __slots__ = ['id', '__weakref__']
|
|
21
|
+
|
|
22
|
+
# def __init__(self, id):
|
|
23
|
+
# self.id = id
|
|
24
|
+
|
|
25
|
+
def keys_where_value(pred, dict):
|
|
26
|
+
for key,value in dict.items():
|
|
27
|
+
if pred(value): yield key
|
|
28
|
+
|
|
29
|
+
types_lookup = {v:k for k,v in types.__dict__.items() if isinstance(v, type)}
|
|
30
|
+
|
|
31
|
+
def resolve(obj):
|
|
32
|
+
try:
|
|
33
|
+
return getattr(sys.modules[obj.__module__], obj.__name__)
|
|
34
|
+
except:
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
def resolveable(obj):
|
|
38
|
+
try:
|
|
39
|
+
return getattr(sys.modules[obj.__module__], obj.__name__) is obj
|
|
40
|
+
except:
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
def resolveable_name(obj):
|
|
44
|
+
if obj in types_lookup:
|
|
45
|
+
return ('types', types_lookup[obj])
|
|
46
|
+
elif resolve(obj) is obj:
|
|
47
|
+
return (obj.__module__, obj.__name__)
|
|
48
|
+
else:
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
# when
|
|
52
|
+
class RecordProxySystem(ProxySystem):
|
|
53
|
+
|
|
54
|
+
# def bind(self, obj):
|
|
55
|
+
# self.bindings[obj] = self.writer.handle(Placeholder(self.next_placeholder_id))
|
|
56
|
+
# self.writer(self.bindings[obj])
|
|
57
|
+
# self.next_placeholder_id += 1
|
|
58
|
+
|
|
59
|
+
def before_fork(self):
|
|
60
|
+
self.writer.keep_open = False
|
|
61
|
+
# self.writer.close()
|
|
62
|
+
super().before_fork()
|
|
63
|
+
# self.writer.path = self.dynamic_path
|
|
64
|
+
|
|
65
|
+
def after_fork_in_child(self):
|
|
66
|
+
new_path = self.new_child_path(self.writer.path)
|
|
67
|
+
new_path.parent.mkdir()
|
|
68
|
+
self.writer.path = new_path
|
|
69
|
+
self.writer.keep_open = True
|
|
70
|
+
super().after_fork_in_child()
|
|
71
|
+
|
|
72
|
+
def after_fork_in_parent(self):
|
|
73
|
+
super().after_fork_in_parent()
|
|
74
|
+
self.thread_state.value = self.saved_thread_state
|
|
75
|
+
self.writer.keep_open = True
|
|
76
|
+
# self.writer.reopen()
|
|
77
|
+
|
|
78
|
+
def set_thread_id(self, id):
|
|
79
|
+
utils.set_thread_id(self.writer.handle(ThreadSwitch(id)))
|
|
80
|
+
# utils.set_thread_id(id)
|
|
81
|
+
|
|
82
|
+
# def is_entry_frame(self, frame):
|
|
83
|
+
# if super().is_entry_frame(frame):
|
|
84
|
+
# self.write_main_path(frame.function.__code__.co_filename)
|
|
85
|
+
# return True
|
|
86
|
+
# return False
|
|
87
|
+
|
|
88
|
+
def create_from_external(self, obj):
|
|
89
|
+
# class of obj is bound
|
|
90
|
+
# can now write type(obj)
|
|
91
|
+
|
|
92
|
+
self.bind(obj)
|
|
93
|
+
|
|
94
|
+
breakpoint()
|
|
95
|
+
|
|
96
|
+
def patch_type(self, cls):
|
|
97
|
+
|
|
98
|
+
patched = super().patch_type(cls)
|
|
99
|
+
|
|
100
|
+
self.writer.type_serializer[patched] = functional.side_effect(self.writer.ext_bind)
|
|
101
|
+
|
|
102
|
+
return patched
|
|
103
|
+
|
|
104
|
+
def exclude_from_stacktrace(self, func):
|
|
105
|
+
self.writer.exclude_from_stacktrace(func)
|
|
106
|
+
|
|
107
|
+
def on_gc_event(self, phase, info):
|
|
108
|
+
if phase == 'start':
|
|
109
|
+
self.writer.stacktraces = False
|
|
110
|
+
self.on_start_collect(info['generation'])
|
|
111
|
+
|
|
112
|
+
elif phase == 'stop':
|
|
113
|
+
self.on_end_collect()
|
|
114
|
+
self.writer.stacktraces = self.stacktraces
|
|
115
|
+
|
|
116
|
+
def __init__(self, thread_state,
|
|
117
|
+
writer,
|
|
118
|
+
immutable_types,
|
|
119
|
+
tracing_config,
|
|
120
|
+
maybe_collect,
|
|
121
|
+
traceargs):
|
|
122
|
+
|
|
123
|
+
self.fork_counter = 0
|
|
124
|
+
# self.write_main_path = write_main_path
|
|
125
|
+
|
|
126
|
+
self.getpid = thread_state.wrap(
|
|
127
|
+
desired_state = 'disabled', function = os.getpid)
|
|
128
|
+
|
|
129
|
+
self.pid = self.getpid()
|
|
130
|
+
|
|
131
|
+
self.writer = writer
|
|
132
|
+
|
|
133
|
+
self.stacktraces = self.writer.stacktraces
|
|
134
|
+
|
|
135
|
+
if self.stacktraces:
|
|
136
|
+
def set(status):
|
|
137
|
+
self.writer.stacktraces = status
|
|
138
|
+
|
|
139
|
+
self.wrap_weakref_callback = functional.sequence(
|
|
140
|
+
self.wrap_weakref_callback,
|
|
141
|
+
lambda callback:
|
|
142
|
+
utils.observer(
|
|
143
|
+
on_call = functional.lazy(set, False),
|
|
144
|
+
on_result = functional.lazy(set, True),
|
|
145
|
+
on_error = functional.lazy(set, True),
|
|
146
|
+
function = callback))
|
|
147
|
+
|
|
148
|
+
self.exclude_from_stacktrace(RecordProxySystem.patch_type)
|
|
149
|
+
self.exclude_from_stacktrace(patch_find_spec.__call__)
|
|
150
|
+
|
|
151
|
+
self.extended_types = {}
|
|
152
|
+
|
|
153
|
+
sync_handle = self.writer.handle('SYNC')
|
|
154
|
+
|
|
155
|
+
self.on_ext_call = functional.lazy(utils.runall(maybe_collect, sync_handle) if maybe_collect else sync_handle)
|
|
156
|
+
|
|
157
|
+
write_sync = thread_state.dispatch(utils.noop, internal = functional.lazy(sync_handle))
|
|
158
|
+
|
|
159
|
+
self.sync = lambda function: \
|
|
160
|
+
utils.observer(on_call = write_sync, function = function)
|
|
161
|
+
error = self.writer.handle('ERROR')
|
|
162
|
+
|
|
163
|
+
def write_error(cls, val, traceback):
|
|
164
|
+
assert isinstance(val, BaseException)
|
|
165
|
+
error(cls, val)
|
|
166
|
+
|
|
167
|
+
tracer = Tracer(tracing_config, writer = self.writer.handle('TRACE'))
|
|
168
|
+
|
|
169
|
+
self.writer.exclude_from_stacktrace(write_error)
|
|
170
|
+
# self.writer.exclude_from_stacktrace(Tracer.write_call)
|
|
171
|
+
|
|
172
|
+
self.on_int_call = self.writer.handle('CALL')
|
|
173
|
+
|
|
174
|
+
# write_new_ref = self.writer.handle('RESULT')
|
|
175
|
+
|
|
176
|
+
self.on_ext_result = self.writer.handle('RESULT')
|
|
177
|
+
|
|
178
|
+
self.on_ext_error = write_error
|
|
179
|
+
|
|
180
|
+
self.writer.type_serializer[types.ModuleType] = GlobalRef
|
|
181
|
+
|
|
182
|
+
self.bind = self.writer.bind
|
|
183
|
+
|
|
184
|
+
self.create_from_external = self.writer.ext_bind
|
|
185
|
+
|
|
186
|
+
self.write_trace = self.writer.handle('TRACER')
|
|
187
|
+
|
|
188
|
+
self.checkpoint = self.writer.handle('CHECKPOINT')
|
|
189
|
+
|
|
190
|
+
self.on_weakref_callback_start = functional.lazy(self.writer.handle('ON_WEAKREF_CALLBACK_START'))
|
|
191
|
+
self.on_weakref_callback_end = functional.lazy(self.writer.handle('ON_WEAKREF_CALLBACK_END'))
|
|
192
|
+
|
|
193
|
+
self.on_start_collect = self.writer.handle('ON_START_COLLECT')
|
|
194
|
+
self.on_end_collect = self.writer.handle('ON_END_COLLECT')
|
|
195
|
+
|
|
196
|
+
super().__init__(thread_state = thread_state,
|
|
197
|
+
tracer = tracer,
|
|
198
|
+
traceargs = traceargs,
|
|
199
|
+
immutable_types = immutable_types)
|
|
200
|
+
|
|
201
|
+
def ext_proxytype(self, cls):
|
|
202
|
+
|
|
203
|
+
proxytype = super().ext_proxytype(cls)
|
|
204
|
+
|
|
205
|
+
ref = self.writer.handle(StubRef(proxytype))
|
|
206
|
+
|
|
207
|
+
self.writer.type_serializer[proxytype] = functional.constantly(ref)
|
|
208
|
+
|
|
209
|
+
return proxytype
|
|
210
|
+
|
|
211
|
+
|