retracesoftware-proxy 0.1.8__py3-none-any.whl → 0.1.10__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/config.json +5 -0
- retracesoftware/install/patcher.py +14 -13
- retracesoftware/install/tracer.py +31 -2
- retracesoftware/proxy/proxysystem.py +58 -46
- retracesoftware/proxy/proxytype.py +29 -23
- retracesoftware/proxy/record.py +13 -96
- retracesoftware/proxy/replay.py +74 -152
- retracesoftware/proxy/stubfactory.py +20 -8
- {retracesoftware_proxy-0.1.8.dist-info → retracesoftware_proxy-0.1.10.dist-info}/METADATA +1 -1
- {retracesoftware_proxy-0.1.8.dist-info → retracesoftware_proxy-0.1.10.dist-info}/RECORD +12 -12
- {retracesoftware_proxy-0.1.8.dist-info → retracesoftware_proxy-0.1.10.dist-info}/WHEEL +0 -0
- {retracesoftware_proxy-0.1.8.dist-info → retracesoftware_proxy-0.1.10.dist-info}/top_level.txt +0 -0
retracesoftware/config.json
CHANGED
|
@@ -275,7 +275,7 @@ class Patcher:
|
|
|
275
275
|
|
|
276
276
|
@patch
|
|
277
277
|
def patch_start_new_thread(self, value):
|
|
278
|
-
def start_new_thread(
|
|
278
|
+
def start_new_thread(function, *args):
|
|
279
279
|
# synchronized, replay shoudl yield correct number
|
|
280
280
|
thread_id = self.thread_counter()
|
|
281
281
|
|
|
@@ -474,18 +474,19 @@ class Patcher:
|
|
|
474
474
|
|
|
475
475
|
def __call__(self, module):
|
|
476
476
|
|
|
477
|
-
if not hasattr(module, '__retrace__'):
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
if len(configs) >
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
477
|
+
if self.thread_state.value == 'internal' and not hasattr(module, '__retrace__'):
|
|
478
|
+
with self.thread_state.select('bootstrap'):
|
|
479
|
+
configs = list(self.configs(module))
|
|
480
|
+
|
|
481
|
+
if len(configs) > 0:
|
|
482
|
+
if len(configs) > 1:
|
|
483
|
+
raise Exception(f'TODO')
|
|
484
|
+
else:
|
|
485
|
+
module.__retrace__ = None
|
|
486
|
+
try:
|
|
487
|
+
self.patch_module_with_name(configs[0], module)
|
|
488
|
+
except Exception as error:
|
|
489
|
+
raise Exception(f'Error patching module: {configs[0]}') from error
|
|
489
490
|
|
|
490
491
|
return module
|
|
491
492
|
|
|
@@ -13,11 +13,34 @@ def format_kwargs(kwargs):
|
|
|
13
13
|
return tuple(result)
|
|
14
14
|
|
|
15
15
|
class Tracer:
|
|
16
|
+
|
|
16
17
|
def __init__(self, config, writer):
|
|
17
18
|
self.config = config
|
|
18
19
|
serialize = functional.walker(self.serialize)
|
|
19
20
|
self.writer = functional.mapargs(transform = serialize, function = writer)
|
|
20
21
|
|
|
22
|
+
def systrace(self, frame, event, arg):
|
|
23
|
+
try:
|
|
24
|
+
if event in ['line', 'call']:
|
|
25
|
+
print(f'In systrace: {event} {frame.f_code.co_filename}:{frame.f_lineno}')
|
|
26
|
+
self.writer(event, frame.f_code.co_filename, frame.f_code.co_name, frame.f_lineno)
|
|
27
|
+
|
|
28
|
+
elif event == 'return':
|
|
29
|
+
print(f'In systrace: {event}')
|
|
30
|
+
self.writer(event)
|
|
31
|
+
# self.writer(event, self.serialize(arg))
|
|
32
|
+
|
|
33
|
+
elif event == 'exception':
|
|
34
|
+
print(f'In systrace: {event}')
|
|
35
|
+
self.writer(event)
|
|
36
|
+
else:
|
|
37
|
+
print(f'In systrace: {event}')
|
|
38
|
+
|
|
39
|
+
return self.systrace
|
|
40
|
+
except:
|
|
41
|
+
print(f'systrace RAISED ERROR!')
|
|
42
|
+
raise
|
|
43
|
+
|
|
21
44
|
def serialize(self, obj):
|
|
22
45
|
try:
|
|
23
46
|
if obj is None: return None
|
|
@@ -56,6 +79,9 @@ class Tracer:
|
|
|
56
79
|
if name in self.config:
|
|
57
80
|
self.writer(name, message)
|
|
58
81
|
|
|
82
|
+
def checkpoint(self, obj):
|
|
83
|
+
self.writer(obj)
|
|
84
|
+
|
|
59
85
|
def stacktrace(self):
|
|
60
86
|
self.writer('stacktrace', utils.stacktrace())
|
|
61
87
|
|
|
@@ -63,8 +89,11 @@ class Tracer:
|
|
|
63
89
|
if name in self.config:
|
|
64
90
|
if name.endswith('.call'):
|
|
65
91
|
def write_call(*args, **kwargs):
|
|
66
|
-
|
|
67
|
-
|
|
92
|
+
self.stacktrace()
|
|
93
|
+
if len(args) > 0:
|
|
94
|
+
self.writer(name, args[0].__name__, args[1:], kwargs)
|
|
95
|
+
else:
|
|
96
|
+
breakpoint()
|
|
68
97
|
|
|
69
98
|
return functional.firstof(write_call, func) if func else write_call
|
|
70
99
|
|
|
@@ -36,13 +36,14 @@ def resolve(obj):
|
|
|
36
36
|
def is_function_type(cls):
|
|
37
37
|
return cls in [types.BuiltinFunctionType, types.FunctionType]
|
|
38
38
|
|
|
39
|
+
def is_instance_method(obj):
|
|
40
|
+
return isinstance(obj, types.MethodDescriptorType) or isinstance(obj, types.FunctionType)
|
|
41
|
+
|
|
39
42
|
class ProxySystem:
|
|
40
43
|
|
|
41
44
|
def bind(self, obj): pass
|
|
42
45
|
|
|
43
|
-
def wrap_int_to_ext(self, obj):
|
|
44
|
-
return obj
|
|
45
|
-
# return functional.sequence(functional.side_effect(functional.repeatedly(gc.collect)), obj)
|
|
46
|
+
def wrap_int_to_ext(self, obj): return obj
|
|
46
47
|
|
|
47
48
|
def wrap_ext_to_int(self, obj): return obj
|
|
48
49
|
|
|
@@ -58,6 +59,9 @@ class ProxySystem:
|
|
|
58
59
|
# def stacktrace(self):
|
|
59
60
|
# self.tracer.stacktrace()
|
|
60
61
|
|
|
62
|
+
def set_thread_id(self, id):
|
|
63
|
+
utils.set_thread_id(id)
|
|
64
|
+
|
|
61
65
|
def __init__(self, thread_state, immutable_types, tracer):
|
|
62
66
|
|
|
63
67
|
self.thread_state = thread_state
|
|
@@ -67,7 +71,7 @@ class ProxySystem:
|
|
|
67
71
|
self.on_proxytype = None
|
|
68
72
|
|
|
69
73
|
def is_immutable_type(cls):
|
|
70
|
-
return issubclass(cls, tuple(immutable_types))
|
|
74
|
+
return cls is object or issubclass(cls, tuple(immutable_types))
|
|
71
75
|
|
|
72
76
|
is_immutable = functional.sequence(functional.typeof, functional.memoize_one_arg(is_immutable_type))
|
|
73
77
|
|
|
@@ -84,7 +88,7 @@ class ProxySystem:
|
|
|
84
88
|
|
|
85
89
|
ext_spec = SimpleNamespace(
|
|
86
90
|
apply = thread_state.wrap('external', functional.apply),
|
|
87
|
-
proxy = proxyfactory(thread_state.wrap('disabled', self.
|
|
91
|
+
proxy = proxyfactory(thread_state.wrap('disabled', self.ext_proxytype)),
|
|
88
92
|
on_call = tracer('proxy.ext.call'),
|
|
89
93
|
on_result = self.on_ext_result,
|
|
90
94
|
on_error = self.on_ext_error,
|
|
@@ -102,6 +106,11 @@ class ProxySystem:
|
|
|
102
106
|
self.ext_dispatch = gateway('proxy.int.disabled.event', internal = self.ext_handler)
|
|
103
107
|
self.int_dispatch = gateway('proxy.ext.disabled.event', external = self.int_handler)
|
|
104
108
|
|
|
109
|
+
if 'systrace' in tracer.config:
|
|
110
|
+
func = thread_state.wrap(desired_state = 'disabled', function = tracer.systrace)
|
|
111
|
+
func = self.thread_state.dispatch(lambda *args: None, internal = func)
|
|
112
|
+
sys.settrace(func)
|
|
113
|
+
|
|
105
114
|
def new_child_path(self, path):
|
|
106
115
|
return path.parent / f'fork-{self.fork_counter}' / path.name
|
|
107
116
|
|
|
@@ -117,9 +126,12 @@ class ProxySystem:
|
|
|
117
126
|
self.thread_state.value = self.saved_thread_state
|
|
118
127
|
self.fork_counter += 1
|
|
119
128
|
|
|
120
|
-
def create_stub(self): return False
|
|
129
|
+
# def create_stub(self): return False
|
|
121
130
|
|
|
122
131
|
def int_proxytype(self, cls):
|
|
132
|
+
if cls is object:
|
|
133
|
+
breakpoint()
|
|
134
|
+
|
|
123
135
|
proxytype = dynamic_int_proxytype(
|
|
124
136
|
handler = self.int_dispatch,
|
|
125
137
|
cls = cls,
|
|
@@ -128,64 +140,64 @@ class ProxySystem:
|
|
|
128
140
|
if self.on_proxytype: self.on_proxytype(proxytype)
|
|
129
141
|
return proxytype
|
|
130
142
|
|
|
131
|
-
|
|
132
|
-
|
|
143
|
+
def ext_proxytype(self, cls):
|
|
144
|
+
if cls is object:
|
|
145
|
+
breakpoint()
|
|
133
146
|
|
|
134
147
|
proxytype = dynamic_proxytype(handler = self.ext_dispatch, cls = cls)
|
|
135
148
|
|
|
136
149
|
if self.on_proxytype: self.on_proxytype(proxytype)
|
|
137
150
|
|
|
138
151
|
return proxytype
|
|
152
|
+
|
|
153
|
+
def function_target(self, obj): return obj
|
|
154
|
+
|
|
155
|
+
def proxy_function(self, obj):
|
|
156
|
+
return utils.wrapped_function(handler = self.ext_handler, target = obj)
|
|
139
157
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
158
|
+
def patchtype(self, cls):
|
|
159
|
+
if cls in self.immutable_types or issubclass(cls, tuple):
|
|
160
|
+
return cls
|
|
161
|
+
|
|
162
|
+
def wrap(func):
|
|
163
|
+
return self.thread_state.dispatch(func, internal = self.proxy_function(func))
|
|
164
|
+
|
|
165
|
+
def wrap_new(func):
|
|
166
|
+
proxied = self.proxy_function(func)
|
|
167
|
+
|
|
168
|
+
def new(cls, *args, **kwargs):
|
|
169
|
+
instance = proxied(cls, *args, **kwargs)
|
|
170
|
+
instance.__init__(*args, **kwargs)
|
|
171
|
+
return instance
|
|
172
|
+
|
|
173
|
+
return self.thread_state.dispatch(func, internal = new)
|
|
147
174
|
|
|
148
|
-
def ext_proxytype(self, cls):
|
|
149
|
-
assert isinstance(cls, type)
|
|
150
175
|
if utils.is_extendable(cls):
|
|
151
|
-
|
|
152
|
-
if self.on_proxytype: self.on_proxytype(proxytype)
|
|
153
|
-
return proxytype
|
|
154
|
-
else:
|
|
155
|
-
new = functional.droparg(self.proxy_function(cls))
|
|
156
|
-
return type(cls.__name__, (object,), {'__module__': cls.__module__, '__new__': new})
|
|
176
|
+
slots = {'__module__': cls.__module__, '__slots__': []}
|
|
157
177
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
def extend_type(self, cls):
|
|
162
|
-
extended = extending_proxytype(
|
|
163
|
-
cls = cls,
|
|
164
|
-
base = self.basetype(cls),
|
|
165
|
-
thread_state = self.thread_state,
|
|
166
|
-
ext_handler = self.ext_dispatch,
|
|
167
|
-
int_handler = self.int_dispatch,
|
|
168
|
-
on_subclass_new = self.bind)
|
|
169
|
-
|
|
170
|
-
self.immutable_types.add(extended)
|
|
178
|
+
for name, value in superdict(cls).items():
|
|
179
|
+
if callable(value) and not is_instance_method(value):
|
|
180
|
+
slots[name] = wrap_new(value) if name == '__new__' else wrap(value)
|
|
171
181
|
|
|
172
|
-
|
|
182
|
+
return type(cls.__name__, (cls,), slots)
|
|
173
183
|
|
|
174
|
-
|
|
184
|
+
elif not utils.is_immutable(cls):
|
|
185
|
+
def update(name, f):
|
|
186
|
+
setattr(cls, name, f(getattr(cls, name)))
|
|
187
|
+
|
|
188
|
+
for name, value in superdict(cls).items():
|
|
189
|
+
if callable(value) and not is_instance_method(value):
|
|
190
|
+
update(name, wrap_new if name == '__new__' else wrap)
|
|
191
|
+
else:
|
|
192
|
+
return wrap(cls)
|
|
175
193
|
|
|
176
|
-
def proxy_function(self, obj):
|
|
177
|
-
return utils.wrapped_function(handler = self.ext_handler, target = obj)
|
|
178
|
-
|
|
179
194
|
def __call__(self, obj):
|
|
180
195
|
assert not isinstance(obj, BaseException)
|
|
181
196
|
assert not isinstance(obj, Proxy)
|
|
182
197
|
assert not isinstance(obj, utils.wrapped_function)
|
|
183
198
|
|
|
184
|
-
if type(obj) == type:
|
|
185
|
-
|
|
186
|
-
return obj
|
|
187
|
-
|
|
188
|
-
return self.ext_proxytype(obj)
|
|
199
|
+
if type(obj) == type:
|
|
200
|
+
return self.patchtype(obj)
|
|
189
201
|
|
|
190
202
|
elif type(obj) in self.immutable_types:
|
|
191
203
|
return obj
|
|
@@ -163,7 +163,11 @@ class DescriptorProxy:
|
|
|
163
163
|
self.target = target
|
|
164
164
|
|
|
165
165
|
def __get__(self, obj, cls):
|
|
166
|
-
|
|
166
|
+
try:
|
|
167
|
+
return self.handler(self.target.__get__, obj, cls)
|
|
168
|
+
except:
|
|
169
|
+
print(f'error calling __get__')
|
|
170
|
+
raise
|
|
167
171
|
|
|
168
172
|
def __set__(self, obj, value):
|
|
169
173
|
return self.handler(self.target.__set__, obj, value)
|
|
@@ -171,28 +175,28 @@ class DescriptorProxy:
|
|
|
171
175
|
def __delete__(self, obj):
|
|
172
176
|
return self.handler(self.target.__delete__, obj)
|
|
173
177
|
|
|
174
|
-
class ExtendingDescriptorProxy:
|
|
178
|
+
# class ExtendingDescriptorProxy:
|
|
175
179
|
|
|
176
|
-
|
|
180
|
+
# __slots__ = ['handler', 'proxytype', 'name']
|
|
177
181
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
+
# def __init__(self, proxytype, handler, name):
|
|
183
|
+
# self.proxytype = proxytype
|
|
184
|
+
# self.handler = handler
|
|
185
|
+
# self.name = name
|
|
182
186
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
+
# def __get__(self, instance, owner):
|
|
188
|
+
# inst = owner if instance is None else instance
|
|
189
|
+
# getter = functional.partial(getattr, super(self.proxytype, inst))
|
|
190
|
+
# return self.handler(getter, self.name)
|
|
187
191
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
+
# def __set__(self, instance, value):
|
|
193
|
+
# breakpoint()
|
|
194
|
+
# setter = functional.partial(setattr, super(self.proxytype, instance))
|
|
195
|
+
# return self.handler(setter, self.name, value)
|
|
192
196
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
197
|
+
# def __delete__(self, instance):
|
|
198
|
+
# deleter = functional.partial(delattr, super(self.proxytype, instance))
|
|
199
|
+
# return self.handler(deleter, self.name)
|
|
196
200
|
|
|
197
201
|
|
|
198
202
|
def dynamic_proxytype(handler, cls):
|
|
@@ -204,14 +208,16 @@ def dynamic_proxytype(handler, cls):
|
|
|
204
208
|
|
|
205
209
|
spec = {}
|
|
206
210
|
|
|
211
|
+
def wrap(func): return utils.wrapped_function(handler = handler, target = func)
|
|
212
|
+
|
|
207
213
|
for name in superdict(cls).keys():
|
|
208
214
|
if name not in blacklist:
|
|
209
215
|
value = getattr(cls, name)
|
|
210
216
|
if is_descriptor(value):
|
|
211
217
|
if utils.is_method_descriptor(value):
|
|
212
|
-
spec[name] =
|
|
213
|
-
else:
|
|
214
|
-
|
|
218
|
+
spec[name] = wrap(value)
|
|
219
|
+
# else:
|
|
220
|
+
# spec[name] = DescriptorProxy(handler = handler, target = value)
|
|
215
221
|
|
|
216
222
|
# to_proxy = [m for m in methods(cls) if m not in blacklist]
|
|
217
223
|
|
|
@@ -219,8 +225,8 @@ def dynamic_proxytype(handler, cls):
|
|
|
219
225
|
|
|
220
226
|
# spec = { name: wrap(getattr(cls, name)) for name in to_proxy }
|
|
221
227
|
|
|
222
|
-
|
|
223
|
-
|
|
228
|
+
spec['__getattr__'] = wrap(getattr)
|
|
229
|
+
spec['__setattr__'] = wrap(setattr)
|
|
224
230
|
|
|
225
231
|
if utils.yields_callable_instances(cls):
|
|
226
232
|
spec['__call__'] = handler
|
retracesoftware/proxy/record.py
CHANGED
|
@@ -113,121 +113,38 @@ class RecordProxySystem(ProxySystem):
|
|
|
113
113
|
def write_error(cls, val, traceback):
|
|
114
114
|
error(cls, val)
|
|
115
115
|
|
|
116
|
-
self.set_thread_id = functional.partial(utils.set_thread_id, self.writer)
|
|
116
|
+
# self.set_thread_id = functional.partial(utils.set_thread_id, self.writer)
|
|
117
117
|
|
|
118
118
|
def watch(f): return functional.either(self.thread_switch_monitor, f)
|
|
119
119
|
|
|
120
|
+
# w = self.writer.handle('TRACE')
|
|
121
|
+
# def foo(name, *args):
|
|
122
|
+
# print(f'writing: {self.writer.messages_written} {name} {args}')
|
|
123
|
+
# w(self.writer.messages_written, name, *args)
|
|
124
|
+
|
|
125
|
+
# tracer = Tracer(tracing_config, writer = foo)
|
|
120
126
|
tracer = Tracer(tracing_config, writer = self.writer.handle('TRACE'))
|
|
121
127
|
|
|
122
128
|
self.wrap_int_to_ext = watch
|
|
123
129
|
|
|
124
130
|
self.on_int_call = functional.mapargs(transform = serialize, function = self.writer.handle('CALL'))
|
|
125
131
|
|
|
126
|
-
|
|
127
|
-
# functional.isinstanceof(str),
|
|
128
|
-
# self.writer.handle('RESULT'),
|
|
129
|
-
# functional.sequence(serialize, self.writer))
|
|
130
|
-
|
|
131
|
-
self.on_ext_result = functional.sequence(serialize,
|
|
132
|
-
self.writer.handle('RESULT'))
|
|
132
|
+
self.on_ext_result = functional.sequence(serialize, self.writer.handle('RESULT'))
|
|
133
133
|
|
|
134
134
|
self.on_ext_error = write_error
|
|
135
135
|
|
|
136
136
|
self.ext_apply = self.int_apply = functional.apply
|
|
137
137
|
|
|
138
|
-
super().__init__(thread_state = thread_state,
|
|
138
|
+
super().__init__(thread_state = thread_state,
|
|
139
|
+
tracer = tracer,
|
|
140
|
+
immutable_types = immutable_types)
|
|
139
141
|
|
|
140
|
-
def
|
|
142
|
+
def ext_proxytype(self, cls):
|
|
141
143
|
|
|
142
|
-
proxytype = super().
|
|
144
|
+
proxytype = super().ext_proxytype(cls)
|
|
143
145
|
|
|
144
146
|
ref = self.writer.handle(StubRef(proxytype))
|
|
145
|
-
|
|
146
|
-
# blacklist = ['__class__', '__dict__', '__module__', '__doc__']
|
|
147
|
-
|
|
148
|
-
# methods = []
|
|
149
|
-
# members = []
|
|
150
|
-
|
|
151
|
-
# for key,value in proxytype.__dict__.items():
|
|
152
|
-
# if key not in blacklist:
|
|
153
|
-
# if utils.is_method_descriptor(value):
|
|
154
|
-
# methods.append(key)
|
|
155
|
-
# elif not key.startswith("__retrace"):
|
|
156
|
-
# members.append(key)
|
|
157
|
-
|
|
158
|
-
# ref = self.writer.handle(StubRef(
|
|
159
|
-
# name = cls.__name__,
|
|
160
|
-
# module = cls.__module__,
|
|
161
|
-
# methods = methods,
|
|
162
|
-
# members = members))
|
|
163
|
-
|
|
164
|
-
# list(proxytype.__dict__.keys())
|
|
165
|
-
|
|
166
|
-
# if resolveable_name(cls):
|
|
167
|
-
# module, name = resolveable_name(cls)
|
|
168
|
-
# ref = self.writer.handle(StubRef(type = 'dynamic', name = name, module = module))
|
|
169
|
-
# else:
|
|
170
|
-
# blacklist = ['__getattribute__']
|
|
171
|
-
# descriptors = {k: v for k,v in superdict(cls).items() if k not in blacklist and is_descriptor(v) }
|
|
172
|
-
|
|
173
|
-
# methods = [k for k, v in descriptors.items() if utils.is_method_descriptor(v)]
|
|
174
|
-
# members = [k for k, v in descriptors.items() if not utils.is_method_descriptor(v)]
|
|
175
|
-
|
|
176
|
-
# ref = self.writer.handle(ProxySpec(name = cls.__name__,
|
|
177
|
-
# module = cls.__module__,
|
|
178
|
-
# methods = methods,
|
|
179
|
-
# members = members))
|
|
180
147
|
|
|
181
148
|
self.writer.type_serializer[proxytype] = functional.constantly(ref)
|
|
182
149
|
|
|
183
150
|
return proxytype
|
|
184
|
-
|
|
185
|
-
def ext_proxytype(self, cls):
|
|
186
|
-
assert isinstance(cls, type), f"record.proxytype requires a type but was passed: {cls}"
|
|
187
|
-
|
|
188
|
-
# resolved = resolve(cls)
|
|
189
|
-
|
|
190
|
-
proxytype = super().ext_proxytype(cls)
|
|
191
|
-
|
|
192
|
-
assert resolve(cls) is cls
|
|
193
|
-
|
|
194
|
-
# ref = self.writer.handle(StubRef(name = cls.__name__,
|
|
195
|
-
# module = cls.__module__))
|
|
196
|
-
|
|
197
|
-
# if resolveable_name(cls):
|
|
198
|
-
# module, name = resolveable_name(cls)
|
|
199
|
-
# ref = self.writer.handle(StubRef(name = cls.__name__, module = cls.__module__))
|
|
200
|
-
# else:
|
|
201
|
-
# blacklist = ['__getattribute__']
|
|
202
|
-
# descriptors = {k: v for k,v in superdict(cls).items() if k not in blacklist and is_descriptor(v) }
|
|
203
|
-
|
|
204
|
-
# methods = [k for k, v in descriptors.items() if utils.is_method_descriptor(v)]
|
|
205
|
-
# members = [k for k, v in descriptors.items() if not utils.is_method_descriptor(v)]
|
|
206
|
-
|
|
207
|
-
# ref = self.writer.handle(ProxySpec(name = cls.__name__,
|
|
208
|
-
# module = cls.__module__,
|
|
209
|
-
# methods = methods,
|
|
210
|
-
# members = members))
|
|
211
|
-
|
|
212
|
-
# self.writer.type_serializer[proxytype] = functional.constantly(ref)
|
|
213
|
-
return proxytype
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
def extend_type(self, cls):
|
|
217
|
-
|
|
218
|
-
if cls in self.extended_types:
|
|
219
|
-
return self.extended_types[cls]
|
|
220
|
-
|
|
221
|
-
extended = super().extend_type(cls)
|
|
222
|
-
|
|
223
|
-
self.extended_types[cls] = extended
|
|
224
|
-
|
|
225
|
-
ref = self.writer.handle(ExtendedRef(name = cls.__name__,
|
|
226
|
-
module = cls.__module__))
|
|
227
|
-
|
|
228
|
-
# for binding?
|
|
229
|
-
# self.writer(ref)
|
|
230
|
-
|
|
231
|
-
self.writer.type_serializer[extended] = functional.constantly(ref)
|
|
232
|
-
|
|
233
|
-
return extended
|
retracesoftware/proxy/replay.py
CHANGED
|
@@ -78,22 +78,6 @@ def on_stack_mismatch(last_matching, record, replay):
|
|
|
78
78
|
|
|
79
79
|
class ReplayProxySystem(ProxySystem):
|
|
80
80
|
|
|
81
|
-
# def stubtype(self, cls):
|
|
82
|
-
# assert not issubclass(cls, Proxy)
|
|
83
|
-
|
|
84
|
-
# return dynamic_proxytype(handler = self.ext_handler, cls = cls)
|
|
85
|
-
|
|
86
|
-
def create_stub(self): return True
|
|
87
|
-
|
|
88
|
-
# def stubtype_from_spec(self, spec):
|
|
89
|
-
# print (f'FOOO!!! {spec}')
|
|
90
|
-
# return stubtype_from_spec(
|
|
91
|
-
# handler = self.ext_handler,
|
|
92
|
-
# module = spec.module,
|
|
93
|
-
# name = spec.name,
|
|
94
|
-
# methods = spec.methods,
|
|
95
|
-
# members = spec.members)
|
|
96
|
-
|
|
97
81
|
@utils.striptraceback
|
|
98
82
|
def next_result(self):
|
|
99
83
|
while True:
|
|
@@ -113,6 +97,7 @@ class ReplayProxySystem(ProxySystem):
|
|
|
113
97
|
return self.messages()
|
|
114
98
|
|
|
115
99
|
elif next == 'ERROR':
|
|
100
|
+
# breakpoint()
|
|
116
101
|
err_type = self.messages()
|
|
117
102
|
err_value = self.messages()
|
|
118
103
|
utils.raise_exception(err_type, err_value)
|
|
@@ -152,6 +137,66 @@ class ReplayProxySystem(ProxySystem):
|
|
|
152
137
|
def basetype(self, cls):
|
|
153
138
|
return self.stub_factory.create_stubtype(StubRef(cls))
|
|
154
139
|
|
|
140
|
+
|
|
141
|
+
def readnext(self):
|
|
142
|
+
with self.thread_state.select('disabled'):
|
|
143
|
+
try:
|
|
144
|
+
# obj = self.messages()
|
|
145
|
+
# print(f'read {obj}')
|
|
146
|
+
# return obj
|
|
147
|
+
return self.messages()
|
|
148
|
+
except Exception as error:
|
|
149
|
+
# print(f'Error reading stream: {error}')
|
|
150
|
+
traceback.print_exc()
|
|
151
|
+
os._exit(1)
|
|
152
|
+
|
|
153
|
+
def read_required(self, required):
|
|
154
|
+
obj = self.readnext()
|
|
155
|
+
if obj != required:
|
|
156
|
+
if self.last_matching_stack:
|
|
157
|
+
for line in self.last_matching_stack:
|
|
158
|
+
print(line)
|
|
159
|
+
|
|
160
|
+
print('---------------------------------')
|
|
161
|
+
print(f'Replay: {required}')
|
|
162
|
+
print('---------------------------------')
|
|
163
|
+
print(f'Record: {obj}')
|
|
164
|
+
print('---------------------------------')
|
|
165
|
+
for i in range(15):
|
|
166
|
+
print(self.readnext())
|
|
167
|
+
|
|
168
|
+
breakpoint()
|
|
169
|
+
os._exit(1)
|
|
170
|
+
raise Exception(f'Expected: {required} but got: {obj}')
|
|
171
|
+
|
|
172
|
+
self.last_matching_stack = utils.stacktrace()
|
|
173
|
+
|
|
174
|
+
def trace_writer(self, name, *args):
|
|
175
|
+
with self.thread_state.select('disabled'):
|
|
176
|
+
# read = self.messages_read
|
|
177
|
+
|
|
178
|
+
self.read_required('TRACE')
|
|
179
|
+
# self.read_required(read)
|
|
180
|
+
self.read_required(name)
|
|
181
|
+
|
|
182
|
+
if name == 'stacktrace':
|
|
183
|
+
record = self.readnext()
|
|
184
|
+
if args[0] == record:
|
|
185
|
+
self.last_matching_stack = args[0]
|
|
186
|
+
else:
|
|
187
|
+
on_stack_mismatch(
|
|
188
|
+
last_matching = self.last_matching_stack,
|
|
189
|
+
record = record,
|
|
190
|
+
replay = args[0])
|
|
191
|
+
os._exit(1)
|
|
192
|
+
else:
|
|
193
|
+
# print(f'Trace: {self.reader.messages_read} {name} {args}')
|
|
194
|
+
for arg in args:
|
|
195
|
+
self.read_required(arg)
|
|
196
|
+
|
|
197
|
+
def sync(self, function):
|
|
198
|
+
return utils.observer(on_call = functional.always(self.read_sync), function = function)
|
|
199
|
+
|
|
155
200
|
def __init__(self,
|
|
156
201
|
thread_state,
|
|
157
202
|
immutable_types,
|
|
@@ -159,152 +204,29 @@ class ReplayProxySystem(ProxySystem):
|
|
|
159
204
|
path,
|
|
160
205
|
fork_path = []):
|
|
161
206
|
|
|
162
|
-
# self.
|
|
163
|
-
|
|
164
|
-
reader = stream.reader(path)
|
|
207
|
+
# self.messages_read = 0
|
|
208
|
+
self.reader = stream.reader(path)
|
|
165
209
|
|
|
166
210
|
self.bindings = utils.id_dict()
|
|
167
211
|
self.set_thread_id = utils.set_thread_id
|
|
168
212
|
self.fork_path = fork_path
|
|
169
213
|
deserialize = functional.walker(self.bindings.get_else_key)
|
|
170
214
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
# messages = reader
|
|
176
|
-
|
|
177
|
-
def readnext():
|
|
178
|
-
with thread_state.select('disabled'):
|
|
179
|
-
try:
|
|
180
|
-
return self.messages()
|
|
181
|
-
except Exception as error:
|
|
182
|
-
# print(f'Error reading stream: {error}')
|
|
183
|
-
traceback.print_exc()
|
|
184
|
-
|
|
185
|
-
os._exit(1)
|
|
186
|
-
|
|
187
|
-
# print(f'read: {obj}')
|
|
188
|
-
# return obj
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
# lookup = weakref.WeakKeyDictionary()
|
|
215
|
+
# def count(res):
|
|
216
|
+
# self.messages_read += 1
|
|
217
|
+
# return res
|
|
192
218
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
# int_refs = {}
|
|
196
|
-
last_matching_stack = None
|
|
197
|
-
|
|
198
|
-
def read_required(required):
|
|
199
|
-
obj = readnext()
|
|
200
|
-
if obj != required:
|
|
201
|
-
if last_matching_stack:
|
|
202
|
-
for line in last_matching_stack:
|
|
203
|
-
print(line)
|
|
204
|
-
|
|
205
|
-
print('---------------------------------')
|
|
206
|
-
print(f'Replay: {required}')
|
|
207
|
-
print('---------------------------------')
|
|
208
|
-
print(f'Record: {obj}')
|
|
209
|
-
print('---------------------------------')
|
|
210
|
-
for i in range(5):
|
|
211
|
-
print(readnext())
|
|
212
|
-
|
|
213
|
-
utils.sigtrap(None)
|
|
214
|
-
os._exit(1)
|
|
215
|
-
raise Exception(f'Expected: {required} but got: {obj}')
|
|
216
|
-
|
|
217
|
-
def trace_writer(name, *args):
|
|
218
|
-
with thread_state.select('disabled'):
|
|
219
|
-
read_required('TRACE')
|
|
220
|
-
read_required(name)
|
|
221
|
-
|
|
222
|
-
if name == 'stacktrace':
|
|
223
|
-
record = readnext()
|
|
224
|
-
if args[0] == record:
|
|
225
|
-
nonlocal last_matching_stack
|
|
226
|
-
last_matching_stack = args[0]
|
|
227
|
-
else:
|
|
228
|
-
on_stack_mismatch(
|
|
229
|
-
last_matching= last_matching_stack,
|
|
230
|
-
record = record,
|
|
231
|
-
replay = args[0])
|
|
232
|
-
os._exit(1)
|
|
233
|
-
else:
|
|
234
|
-
print(f'Trace: {name} {args}')
|
|
235
|
-
for arg in args:
|
|
236
|
-
read_required(arg)
|
|
237
|
-
|
|
238
|
-
# self.tracer = Tracer(tracing_config, writer = trace_writer)
|
|
239
|
-
# self.immutable_types = immutable_types
|
|
240
|
-
|
|
241
|
-
self.reader = reader
|
|
242
|
-
|
|
243
|
-
# def foo(cls):
|
|
244
|
-
# print(cls)
|
|
245
|
-
# assert isinstance(cls, type)
|
|
246
|
-
# immutable_types.add(cls)
|
|
247
|
-
|
|
248
|
-
# add_stubtype = functional.side_effect(foo)
|
|
249
|
-
# add_stubtype = functional.side_effect(immutable_types.add)
|
|
250
|
-
|
|
251
|
-
# reader.type_deserializer[ProxyRef] = functional.sequence(lambda ref: ref.resolve(), self.stubtype, add_stubtype)
|
|
252
|
-
|
|
253
|
-
reader.type_deserializer[StubRef] = self.stub_factory
|
|
254
|
-
# reader.type_deserializer[ProxySpec] = functional.sequence(self.stubtype_from_spec, add_stubtype)
|
|
219
|
+
self.messages = functional.sequence(per_thread_messages(self.reader),
|
|
220
|
+
deserialize)
|
|
255
221
|
|
|
256
|
-
|
|
257
|
-
# functional.is_instanceof(str), writer.handle('RESULT'), writer)
|
|
258
|
-
|
|
259
|
-
# def int_proxytype(gateway):
|
|
260
|
-
# return lambda cls: dynamic_int_proxytype(handler = gateway, cls = cls, bind = self.bind)
|
|
261
|
-
|
|
262
|
-
# create_stubs = functional.walker(functional.when(is_stub_ref, lambda stub: stub.create()))
|
|
263
|
-
# create_stubs = functional.walker(functional.when(is_stub_type, lambda cls: cls()))
|
|
222
|
+
self.stub_factory = StubFactory(thread_state = thread_state, next_result = self.next_result)
|
|
264
223
|
|
|
265
|
-
|
|
266
|
-
# self.ext_apply = functional.repeatedly(self.next_result)
|
|
267
|
-
|
|
268
|
-
def read_sync(): read_required('SYNC')
|
|
224
|
+
self.last_matching_stack = None
|
|
269
225
|
|
|
270
|
-
self.
|
|
226
|
+
self.reader.type_deserializer[StubRef] = self.stub_factory
|
|
227
|
+
|
|
228
|
+
self.read_sync = functional.always(lambda: self.read_required('SYNC'))
|
|
271
229
|
|
|
272
230
|
super().__init__(thread_state = thread_state,
|
|
273
|
-
tracer = Tracer(tracing_config, writer = trace_writer),
|
|
231
|
+
tracer = Tracer(tracing_config, writer = self.trace_writer),
|
|
274
232
|
immutable_types = immutable_types)
|
|
275
|
-
|
|
276
|
-
# super().__init__(
|
|
277
|
-
# thread_state=thread_state,
|
|
278
|
-
# immutable_types= immutable_types,
|
|
279
|
-
# tracer=self.tracer,
|
|
280
|
-
# ext_apply = ext_apply)
|
|
281
|
-
|
|
282
|
-
# self.ext_handler, self.int_handler = gateway_pair(
|
|
283
|
-
# thread_state,
|
|
284
|
-
# self.tracer,
|
|
285
|
-
# immutable_types = immutable_types,
|
|
286
|
-
# ext_apply = ext_apply,
|
|
287
|
-
# int_proxytype = int_proxytype,
|
|
288
|
-
# ext_proxytype = functional.identity)
|
|
289
|
-
|
|
290
|
-
# def extend_type(self, base):
|
|
291
|
-
|
|
292
|
-
# # ok, how to provide __getattr__ style access,
|
|
293
|
-
|
|
294
|
-
# extended = extending_proxytype(
|
|
295
|
-
# cls = base,
|
|
296
|
-
# thread_state = self.thread_state,
|
|
297
|
-
# int_handler = self.int_handler,
|
|
298
|
-
# ext_handler = self.ext_handler,
|
|
299
|
-
# on_subclass_new = self.bind,
|
|
300
|
-
# is_stub = True)
|
|
301
|
-
|
|
302
|
-
# self.immutable_types.add(extended)
|
|
303
|
-
# # proxytype = extending_proxytype(base)
|
|
304
|
-
|
|
305
|
-
# # make_extensible(cls = extended,
|
|
306
|
-
# # int_handler = self.int_handler,
|
|
307
|
-
# # ext_handler = self.ext_handler,
|
|
308
|
-
# # on_new = self.reader.supply)
|
|
309
|
-
|
|
310
|
-
# return extended
|
|
@@ -17,19 +17,15 @@ class StubRef:
|
|
|
17
17
|
blacklist = ['__class__', '__dict__', '__module__', '__doc__', '__new__']
|
|
18
18
|
|
|
19
19
|
methods = []
|
|
20
|
-
members = []
|
|
21
20
|
|
|
22
21
|
for key,value in cls.__dict__.items():
|
|
23
22
|
if key not in blacklist:
|
|
24
23
|
if utils.is_method_descriptor(value):
|
|
25
24
|
methods.append(key)
|
|
26
|
-
elif not key.startswith("__retrace"):
|
|
27
|
-
members.append(key)
|
|
28
25
|
|
|
29
26
|
self.name = cls.__name__
|
|
30
27
|
self.module = cls.__module__
|
|
31
28
|
self.methods = methods
|
|
32
|
-
self.members = members
|
|
33
29
|
|
|
34
30
|
# def __init__(self, module, name, methods, members):
|
|
35
31
|
# self.name = name
|
|
@@ -38,7 +34,7 @@ class StubRef:
|
|
|
38
34
|
# self.members = members
|
|
39
35
|
|
|
40
36
|
def __str__(self):
|
|
41
|
-
return f'StubRef(module = {self.module}, name = {self.name}, methods = {self.methods}
|
|
37
|
+
return f'StubRef(module = {self.module}, name = {self.name}, methods = {self.methods})'
|
|
42
38
|
|
|
43
39
|
def resolve(module, name):
|
|
44
40
|
try:
|
|
@@ -103,7 +99,7 @@ class StubFactory:
|
|
|
103
99
|
next_result = self.thread_state.dispatch(disabled, external = self.next_result)
|
|
104
100
|
|
|
105
101
|
return StubMemberDescriptor(name = name, next_result = next_result)
|
|
106
|
-
|
|
102
|
+
|
|
107
103
|
def create_method(self, name):
|
|
108
104
|
|
|
109
105
|
def disabled(*args, **kwargs):
|
|
@@ -133,8 +129,24 @@ class StubFactory:
|
|
|
133
129
|
slots[method] = self.create_method(method)
|
|
134
130
|
assert utils.is_method_descriptor(slots[method])
|
|
135
131
|
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
def getattr(instance, name):
|
|
133
|
+
if self.thread_state.value == 'external':
|
|
134
|
+
return self.next_result()
|
|
135
|
+
else:
|
|
136
|
+
print(f'Error trying to get attribute: {name}, when retrace mode: {self.thread_state.value} was not external')
|
|
137
|
+
utils.sigtrap(None)
|
|
138
|
+
os._exit(1)
|
|
139
|
+
|
|
140
|
+
def setattr(instance, name, value):
|
|
141
|
+
if self.thread_state.value == 'external':
|
|
142
|
+
return self.next_result()
|
|
143
|
+
else:
|
|
144
|
+
print(f'Error trying to set attribute: {name}, to: {value} when retrace mode: {self.thread_state.value} was not external')
|
|
145
|
+
utils.sigtrap(None)
|
|
146
|
+
os._exit(1)
|
|
147
|
+
|
|
148
|
+
slots['__getattr__'] = getattr
|
|
149
|
+
slots['__setattr__'] = setattr
|
|
138
150
|
|
|
139
151
|
resolved = resolve(spec.module, spec.name)
|
|
140
152
|
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
retracesoftware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
retracesoftware/config.json,sha256=
|
|
2
|
+
retracesoftware/config.json,sha256=FfKk9iTphMpe72nLDy0MgeqJwk95jq0MndI94-wfs-g,8709
|
|
3
3
|
retracesoftware/install/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
retracesoftware/install/config.py,sha256=EzE5ifQF2lo--hu2njI4T0FJ-zlnWDJV6i7x0DMkVTw,1364
|
|
5
5
|
retracesoftware/install/edgecases.py,sha256=NR3lyvad9sRsyeDv_Ya8V4xMgPsMPOi9rMcnFOJGOEA,6330
|
|
6
6
|
retracesoftware/install/globals.py,sha256=F8XvIoZQQ10gSRalk30dvdKllxlwxkaggYY6FogLDxY,510
|
|
7
7
|
retracesoftware/install/install.py,sha256=HCD_ji8XCr96b5fNzNdL_8qcEp0Jf05Em7T6GA6u8HU,4969
|
|
8
|
-
retracesoftware/install/patcher.py,sha256=
|
|
8
|
+
retracesoftware/install/patcher.py,sha256=VXYzE01SyDDw3wQ-spZRb5HEcH3MOlod56039zhpJIE,18888
|
|
9
9
|
retracesoftware/install/predicate.py,sha256=tX7NQc0rGkyyHYO3mduYHcJHbw1wczT53m_Dpkzo6do,2679
|
|
10
10
|
retracesoftware/install/record.py,sha256=tseF_jV4k4HLPTgBPJdjcahl4EQqagoiisMAdGNC52Q,3257
|
|
11
11
|
retracesoftware/install/references.py,sha256=A-G651IDOfuo00MkbAdpbIQh_15ChvJ7uAVTSmE6zd4,1721
|
|
12
12
|
retracesoftware/install/replay.py,sha256=VUiHvQK3mgAJEGmtE2TFs9kXzxdWtsjibEcGkhZVCVE,1830
|
|
13
|
-
retracesoftware/install/tracer.py,sha256=
|
|
13
|
+
retracesoftware/install/tracer.py,sha256=cHEjiVxIp2iVTJEWndwSbMuiXVyGJQxJYZSGrfpSbCw,5723
|
|
14
14
|
retracesoftware/install/typeutils.py,sha256=_a1PuwdCsYjG1Nkd77V-flqYtwbD4RkJVKn6Z-xABL4,1813
|
|
15
15
|
retracesoftware/proxy/__init__.py,sha256=ZlDZIuUmKFsE9Tvfd2EKGabTepqv8nrbr5pQhCM3IKc,193
|
|
16
16
|
retracesoftware/proxy/gateway.py,sha256=xESohWXkiNm4ZutU0RgWUwxjxcBWRQ4rQyxIGQXv_F4,1590
|
|
17
17
|
retracesoftware/proxy/proxyfactory.py,sha256=qhOqDfMJnLDNkQs26JqDB431MwjjRhGQi8xupJ45asg,12272
|
|
18
|
-
retracesoftware/proxy/proxysystem.py,sha256=
|
|
19
|
-
retracesoftware/proxy/proxytype.py,sha256=
|
|
20
|
-
retracesoftware/proxy/record.py,sha256=
|
|
21
|
-
retracesoftware/proxy/replay.py,sha256=
|
|
22
|
-
retracesoftware/proxy/stubfactory.py,sha256=
|
|
18
|
+
retracesoftware/proxy/proxysystem.py,sha256=Nf_yKa4gMvKA2RWEUBmyH9m46lbsAdyPzj5jVDh4cs8,7427
|
|
19
|
+
retracesoftware/proxy/proxytype.py,sha256=crq7idJP77Magtv58l_uJCAlTnD2aDTT-Uz14raTSIo,12767
|
|
20
|
+
retracesoftware/proxy/record.py,sha256=vtNsoTHP5gsBVJ6dTGHR7QXHGbKm0eONfGcXOb9fhFk,4696
|
|
21
|
+
retracesoftware/proxy/replay.py,sha256=m4Buxlix09aUJX9JYWG1z4jW8Yvbo2zBV353hsZE5qY,7670
|
|
22
|
+
retracesoftware/proxy/stubfactory.py,sha256=CnP0Sm0tZNwyFIQIPkk7w_soNBDcflNKwICsAoZxSD0,5128
|
|
23
23
|
retracesoftware/proxy/thread.py,sha256=-SvnyVbANkmX2lLRpOvFtkpdpAoF6DhnnYdOOs7Q8vo,1379
|
|
24
|
-
retracesoftware_proxy-0.1.
|
|
25
|
-
retracesoftware_proxy-0.1.
|
|
26
|
-
retracesoftware_proxy-0.1.
|
|
27
|
-
retracesoftware_proxy-0.1.
|
|
24
|
+
retracesoftware_proxy-0.1.10.dist-info/METADATA,sha256=iMDet9F_g7c2ifPNa8dCfHFaF_wYRS3Z8t60zAtKgVo,203
|
|
25
|
+
retracesoftware_proxy-0.1.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
26
|
+
retracesoftware_proxy-0.1.10.dist-info/top_level.txt,sha256=hYHsR6txLidmqvjBMITpIHvmJJbmoCAgr76-IpZPRz8,16
|
|
27
|
+
retracesoftware_proxy-0.1.10.dist-info/RECORD,,
|
|
File without changes
|
{retracesoftware_proxy-0.1.8.dist-info → retracesoftware_proxy-0.1.10.dist-info}/top_level.txt
RENAMED
|
File without changes
|