retracesoftware-proxy 0.1.6__py3-none-any.whl → 0.1.8__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 +34 -12
- retracesoftware/install/patcher.py +52 -14
- retracesoftware/proxy/proxysystem.py +16 -16
- retracesoftware/proxy/proxytype.py +8 -1
- retracesoftware/proxy/record.py +10 -3
- {retracesoftware_proxy-0.1.6.dist-info → retracesoftware_proxy-0.1.8.dist-info}/METADATA +1 -1
- {retracesoftware_proxy-0.1.6.dist-info → retracesoftware_proxy-0.1.8.dist-info}/RECORD +9 -9
- {retracesoftware_proxy-0.1.6.dist-info → retracesoftware_proxy-0.1.8.dist-info}/WHEEL +0 -0
- {retracesoftware_proxy-0.1.6.dist-info → retracesoftware_proxy-0.1.8.dist-info}/top_level.txt +0 -0
retracesoftware/config.json
CHANGED
|
@@ -160,12 +160,24 @@
|
|
|
160
160
|
"_imp": {
|
|
161
161
|
"patch_extension_exec": ["exec_dynamic", "exec_builtin"]
|
|
162
162
|
},
|
|
163
|
+
"bdb": {
|
|
164
|
+
"methods_with_state": {
|
|
165
|
+
"disabled": {
|
|
166
|
+
"Bdb": ["trace_dispatch"]
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"with_state": {
|
|
170
|
+
"disabled": ["Bdb.trace_dispatch"]
|
|
171
|
+
}
|
|
172
|
+
},
|
|
163
173
|
"sys": {
|
|
164
174
|
"with_state": {
|
|
165
175
|
"disabled": ["excepthook"]
|
|
166
176
|
},
|
|
167
|
-
"
|
|
168
|
-
"
|
|
177
|
+
"comment": {
|
|
178
|
+
"with_state_recursive": {
|
|
179
|
+
"disabled": ["settrace", "setprofile"]
|
|
180
|
+
}
|
|
169
181
|
}
|
|
170
182
|
},
|
|
171
183
|
|
|
@@ -264,10 +276,16 @@
|
|
|
264
276
|
"open_code": "path",
|
|
265
277
|
"open": "file"
|
|
266
278
|
},
|
|
267
|
-
"
|
|
268
|
-
"FileIO
|
|
269
|
-
|
|
270
|
-
|
|
279
|
+
"patchtype": {
|
|
280
|
+
"FileIO": {
|
|
281
|
+
"readinfo": "retracesoftware.install.edgecases.readinto"
|
|
282
|
+
},
|
|
283
|
+
"BufferedReader": {
|
|
284
|
+
"readinfo": "retracesoftware.install.edgecases.readinto"
|
|
285
|
+
},
|
|
286
|
+
"BufferedRandom": {
|
|
287
|
+
"readinfo": "retracesoftware.install.edgecases.readinto"
|
|
288
|
+
}
|
|
271
289
|
}
|
|
272
290
|
},
|
|
273
291
|
"pathlib": {
|
|
@@ -323,10 +341,12 @@
|
|
|
323
341
|
"gaierror",
|
|
324
342
|
"timeout"
|
|
325
343
|
],
|
|
326
|
-
"
|
|
327
|
-
"socket
|
|
328
|
-
|
|
329
|
-
|
|
344
|
+
"patchtype": {
|
|
345
|
+
"socket": {
|
|
346
|
+
"recvfrom_into": "retracesoftware.install.edgecases.recvfrom_into",
|
|
347
|
+
"recv_into": "retracesoftware.install.edgecases.recv_into",
|
|
348
|
+
"recvmsg_into": "retracesoftware.install.edgecases.recvmsg_into"
|
|
349
|
+
}
|
|
330
350
|
}
|
|
331
351
|
},
|
|
332
352
|
"select": {
|
|
@@ -349,8 +369,10 @@
|
|
|
349
369
|
"_SSLSocket.write": "write"
|
|
350
370
|
}
|
|
351
371
|
},
|
|
352
|
-
"
|
|
353
|
-
"_SSLSocket
|
|
372
|
+
"patchtype": {
|
|
373
|
+
"_SSLSocket": {
|
|
374
|
+
"read": "retracesoftware.install.edgecases.read"
|
|
375
|
+
}
|
|
354
376
|
}
|
|
355
377
|
},
|
|
356
378
|
"_random": {
|
|
@@ -25,7 +25,7 @@ from retracesoftware.install.config import load_config
|
|
|
25
25
|
from functools import wraps
|
|
26
26
|
|
|
27
27
|
import retracesoftware.functional as functional
|
|
28
|
-
import
|
|
28
|
+
import retracesoftware.utils as utils
|
|
29
29
|
|
|
30
30
|
from retracesoftware.install import edgecases
|
|
31
31
|
from functools import partial
|
|
@@ -137,9 +137,9 @@ def superdict(cls):
|
|
|
137
137
|
|
|
138
138
|
return result
|
|
139
139
|
|
|
140
|
-
def is_method_descriptor(obj):
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
# def is_method_descriptor(obj):
|
|
141
|
+
# return isinstance(obj, types.FunctionType) or \
|
|
142
|
+
# (isinstance(obj, (types.WrapperDescriptorType, types.MethodDescriptorType)) and obj.__objclass__ != object)
|
|
143
143
|
|
|
144
144
|
def wrap_method_descriptors(wrapper, prefix, base):
|
|
145
145
|
slots = {"__slots__": () }
|
|
@@ -150,7 +150,7 @@ def wrap_method_descriptors(wrapper, prefix, base):
|
|
|
150
150
|
|
|
151
151
|
for name,value in superdict(base).items():
|
|
152
152
|
if name not in blacklist:
|
|
153
|
-
if is_method_descriptor(value):
|
|
153
|
+
if utils.is_method_descriptor(value):
|
|
154
154
|
setattr(extended, name, wrapper(value))
|
|
155
155
|
|
|
156
156
|
return extended
|
|
@@ -179,6 +179,7 @@ class Patcher:
|
|
|
179
179
|
self.type_attribute_filter = self.predicate(config['type_attribute_filter'])
|
|
180
180
|
self.post_commit = post_commit
|
|
181
181
|
self.exclude_paths = [re.compile(s) for s in config.get('exclude_paths', [])]
|
|
182
|
+
self.typepatcher = {}
|
|
182
183
|
|
|
183
184
|
def is_phase(name): return getattr(getattr(self, name, None), "is_phase", False)
|
|
184
185
|
|
|
@@ -193,7 +194,21 @@ class Patcher:
|
|
|
193
194
|
# print(f'in path_predicate, excluding {path}')
|
|
194
195
|
return False
|
|
195
196
|
return True
|
|
196
|
-
|
|
197
|
+
|
|
198
|
+
def on_proxytype(self, cls):
|
|
199
|
+
|
|
200
|
+
def patch(spec):
|
|
201
|
+
for method, transform in spec.items():
|
|
202
|
+
setattr(cls, method, resolve(transform)(getattr(cls, method)))
|
|
203
|
+
|
|
204
|
+
if cls.__module__ in self.modules:
|
|
205
|
+
spec = self.modules[cls.__module__]
|
|
206
|
+
|
|
207
|
+
if 'patchtype' in spec:
|
|
208
|
+
patchtype = spec['patchtype']
|
|
209
|
+
if cls.__name__ in patchtype:
|
|
210
|
+
patch(patchtype[cls.__name__])
|
|
211
|
+
|
|
197
212
|
@property
|
|
198
213
|
def disable(self):
|
|
199
214
|
return self.thread_state.select('disabled')
|
|
@@ -314,15 +329,35 @@ class Patcher:
|
|
|
314
329
|
for state,elems in spec.items():
|
|
315
330
|
|
|
316
331
|
def wrap(obj):
|
|
317
|
-
return functional.
|
|
318
|
-
|
|
319
|
-
lambda f: self.thread_state.wrap(state, f),
|
|
332
|
+
return functional.recurive_wrap_function(
|
|
333
|
+
functional.partial(self.thread_state.wrap, state),
|
|
320
334
|
obj)
|
|
321
335
|
|
|
322
336
|
updates.update(map_values(wrap, select_keys(elems, mod_dict)))
|
|
323
337
|
|
|
324
338
|
return updates
|
|
325
339
|
|
|
340
|
+
@phase
|
|
341
|
+
def methods_with_state(self, spec, mod_dict):
|
|
342
|
+
|
|
343
|
+
# updates = {}
|
|
344
|
+
|
|
345
|
+
def update(cls, name, f):
|
|
346
|
+
setattr(cls, name, f(getattr(cls, name)))
|
|
347
|
+
|
|
348
|
+
for state,cls_methods in spec.items():
|
|
349
|
+
def wrap(obj):
|
|
350
|
+
assert callable(obj)
|
|
351
|
+
return self.thread_state.wrap(desired_state = state, function = obj)
|
|
352
|
+
|
|
353
|
+
for typename,methodnames in cls_methods.items():
|
|
354
|
+
cls = mod_dict[typename]
|
|
355
|
+
|
|
356
|
+
for methodname in methodnames:
|
|
357
|
+
update(cls, methodname, wrap)
|
|
358
|
+
|
|
359
|
+
return {}
|
|
360
|
+
|
|
326
361
|
@phase
|
|
327
362
|
def with_state(self, spec, mod_dict):
|
|
328
363
|
|
|
@@ -330,7 +365,8 @@ class Patcher:
|
|
|
330
365
|
|
|
331
366
|
for state,elems in spec.items():
|
|
332
367
|
|
|
333
|
-
def wrap(obj):
|
|
368
|
+
def wrap(obj):
|
|
369
|
+
return self.thread_state.wrap(desired_state = state, function = obj)
|
|
334
370
|
|
|
335
371
|
updates.update(map_values(wrap, select_keys(elems, mod_dict)))
|
|
336
372
|
|
|
@@ -377,7 +413,9 @@ class Patcher:
|
|
|
377
413
|
name = parts[0]
|
|
378
414
|
if name in mod_dict:
|
|
379
415
|
value = mod_dict[name]
|
|
380
|
-
assert not isinstance(value, utils.wrapped_function),
|
|
416
|
+
assert not isinstance(value, utils.wrapped_function), \
|
|
417
|
+
f"value for key: {name} is already wrapped"
|
|
418
|
+
|
|
381
419
|
if len(parts) == 1:
|
|
382
420
|
updates[name] = resolve(wrapper_name)(value)
|
|
383
421
|
elif len(parts) == 2:
|
|
@@ -436,9 +474,6 @@ class Patcher:
|
|
|
436
474
|
|
|
437
475
|
def __call__(self, module):
|
|
438
476
|
|
|
439
|
-
# if module.__name__ == 'locale':
|
|
440
|
-
# utils.sigtrap(None)
|
|
441
|
-
|
|
442
477
|
if not hasattr(module, '__retrace__'):
|
|
443
478
|
configs = list(self.configs(module))
|
|
444
479
|
|
|
@@ -446,6 +481,7 @@ class Patcher:
|
|
|
446
481
|
if len(configs) > 1:
|
|
447
482
|
raise Exception(f'TODO')
|
|
448
483
|
else:
|
|
484
|
+
module.__retrace__ = None
|
|
449
485
|
try:
|
|
450
486
|
self.patch_module_with_name(configs[0], module)
|
|
451
487
|
except Exception as error:
|
|
@@ -518,6 +554,8 @@ def install(mode):
|
|
|
518
554
|
system = system,
|
|
519
555
|
post_commit = getattr(system, 'on_patched', None),
|
|
520
556
|
immutable_types = immutable_types)
|
|
557
|
+
|
|
558
|
+
system.on_proxytype = patcher.on_proxytype
|
|
521
559
|
|
|
522
560
|
def at_exit(): thread_state.value = 'disabled'
|
|
523
561
|
|
|
@@ -54,7 +54,7 @@ class ProxySystem:
|
|
|
54
54
|
|
|
55
55
|
def on_ext_error(self, err_type, err_value, err_traceback):
|
|
56
56
|
pass
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
# def stacktrace(self):
|
|
59
59
|
# self.tracer.stacktrace()
|
|
60
60
|
|
|
@@ -120,18 +120,20 @@ class ProxySystem:
|
|
|
120
120
|
def create_stub(self): return False
|
|
121
121
|
|
|
122
122
|
def int_proxytype(self, cls):
|
|
123
|
-
|
|
123
|
+
proxytype = dynamic_int_proxytype(
|
|
124
124
|
handler = self.int_dispatch,
|
|
125
125
|
cls = cls,
|
|
126
126
|
bind = self.bind)
|
|
127
|
+
|
|
128
|
+
if self.on_proxytype: self.on_proxytype(proxytype)
|
|
129
|
+
return proxytype
|
|
130
|
+
|
|
127
131
|
|
|
128
132
|
def dynamic_ext_proxytype(self, cls):
|
|
129
133
|
|
|
130
|
-
proxytype = dynamic_proxytype(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if self.on_proxytype:
|
|
134
|
-
self.on_proxytype(proxytype)
|
|
134
|
+
proxytype = dynamic_proxytype(handler = self.ext_dispatch, cls = cls)
|
|
135
|
+
|
|
136
|
+
if self.on_proxytype: self.on_proxytype(proxytype)
|
|
135
137
|
|
|
136
138
|
return proxytype
|
|
137
139
|
|
|
@@ -146,15 +148,12 @@ class ProxySystem:
|
|
|
146
148
|
def ext_proxytype(self, cls):
|
|
147
149
|
assert isinstance(cls, type)
|
|
148
150
|
if utils.is_extendable(cls):
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
# cls = cls,
|
|
156
|
-
# thread_state = self.thread_state,
|
|
157
|
-
# create_stub = self.create_stub())
|
|
151
|
+
proxytype = self.extend_type(cls)
|
|
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})
|
|
158
157
|
|
|
159
158
|
def basetype(self, cls):
|
|
160
159
|
return cls
|
|
@@ -199,6 +198,7 @@ class ProxySystem:
|
|
|
199
198
|
|
|
200
199
|
else:
|
|
201
200
|
proxytype = dynamic_proxytype(handler = self.ext_dispatch, cls = type(obj))
|
|
201
|
+
if self.on_proxytype: self.on_proxytype(proxytype)
|
|
202
202
|
|
|
203
203
|
return utils.create_wrapped(proxytype, obj)
|
|
204
204
|
# raise Exception(f'object {obj} was not proxied as its not a extensible type and is not callable')
|
|
@@ -186,6 +186,7 @@ class ExtendingDescriptorProxy:
|
|
|
186
186
|
return self.handler(getter, self.name)
|
|
187
187
|
|
|
188
188
|
def __set__(self, instance, value):
|
|
189
|
+
breakpoint()
|
|
189
190
|
setter = functional.partial(setattr, super(self.proxytype, instance))
|
|
190
191
|
return self.handler(setter, self.name, value)
|
|
191
192
|
|
|
@@ -314,6 +315,11 @@ def create_unproxied_type(cls):
|
|
|
314
315
|
|
|
315
316
|
bases = tuple(map(unproxy_type, cls.__bases__))
|
|
316
317
|
slots = dict(cls.__dict__)
|
|
318
|
+
|
|
319
|
+
if '__slots__' in slots:
|
|
320
|
+
for slot in slots['__slots__']:
|
|
321
|
+
slots.pop(slot)
|
|
322
|
+
|
|
317
323
|
# del slots['__init_subclass__']
|
|
318
324
|
return type(cls.__name__, tuple(bases), slots)
|
|
319
325
|
|
|
@@ -357,7 +363,8 @@ def extending_proxytype(cls, base, thread_state, ext_handler, int_handler, on_su
|
|
|
357
363
|
extended = type(cls.__name__, (base, ExtendingProxy), slots)
|
|
358
364
|
|
|
359
365
|
for name in descriptors:
|
|
360
|
-
proxy = ExtendingDescriptorProxy(handler = ext_handler, name = name, proxytype = extended)
|
|
366
|
+
# proxy = ExtendingDescriptorProxy(handler = ext_handler, name = name, proxytype = extended)
|
|
367
|
+
proxy = DescriptorProxy(handler = ext_handler, target = getattr(cls, name))
|
|
361
368
|
setattr(extended, name, proxy)
|
|
362
369
|
|
|
363
370
|
def unproxied__new__(subclass, *args, **kwargs):
|
retracesoftware/proxy/record.py
CHANGED
|
@@ -70,6 +70,13 @@ class RecordProxySystem(ProxySystem):
|
|
|
70
70
|
self.thread_state.value = self.saved_thread_state
|
|
71
71
|
self.writer.reopen()
|
|
72
72
|
|
|
73
|
+
def sync(self, function):
|
|
74
|
+
write_sync = functional.always(self.writer.handle('SYNC'))
|
|
75
|
+
|
|
76
|
+
return utils.observer(
|
|
77
|
+
on_call = functional.firstof(self.thread_switch_monitor, write_sync),
|
|
78
|
+
function = function)
|
|
79
|
+
|
|
73
80
|
def __init__(self, thread_state,
|
|
74
81
|
immutable_types,
|
|
75
82
|
tracing_config,
|
|
@@ -95,11 +102,11 @@ class RecordProxySystem(ProxySystem):
|
|
|
95
102
|
|
|
96
103
|
serialize = functional.walker(self.bindings.get_else_key)
|
|
97
104
|
|
|
98
|
-
thread_switch_monitor = \
|
|
105
|
+
self.thread_switch_monitor = \
|
|
99
106
|
utils.thread_switch_monitor(
|
|
100
107
|
functional.repeatedly(functional.sequence(utils.thread_id, self.writer)))
|
|
101
108
|
|
|
102
|
-
self.sync = lambda function: functional.firstof(thread_switch_monitor, functional.always(self.writer.handle('SYNC')), function)
|
|
109
|
+
# self.sync = lambda function: functional.firstof(self.thread_switch_monitor, functional.always(self.writer.handle('SYNC')), function)
|
|
103
110
|
|
|
104
111
|
error = self.writer.handle('ERROR')
|
|
105
112
|
|
|
@@ -108,7 +115,7 @@ class RecordProxySystem(ProxySystem):
|
|
|
108
115
|
|
|
109
116
|
self.set_thread_id = functional.partial(utils.set_thread_id, self.writer)
|
|
110
117
|
|
|
111
|
-
def watch(f): return functional.either(thread_switch_monitor, f)
|
|
118
|
+
def watch(f): return functional.either(self.thread_switch_monitor, f)
|
|
112
119
|
|
|
113
120
|
tracer = Tracer(tracing_config, writer = self.writer.handle('TRACE'))
|
|
114
121
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
retracesoftware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
retracesoftware/config.json,sha256=
|
|
2
|
+
retracesoftware/config.json,sha256=_GTEhl9ba5ed9io_sWAR3nO30T-w66qU6Q-fHKguEHg,8638
|
|
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=aDFSUfR8ZWAkLKm5xMuilTxtQ9-uUrHeFHZmozMkRSU,18756
|
|
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
|
|
@@ -15,13 +15,13 @@ retracesoftware/install/typeutils.py,sha256=_a1PuwdCsYjG1Nkd77V-flqYtwbD4RkJVKn6
|
|
|
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=
|
|
18
|
+
retracesoftware/proxy/proxysystem.py,sha256=F0YSsF6BlDjWrjiApfy12GBopD647ML-UXP8Ovn_CL8,6953
|
|
19
|
+
retracesoftware/proxy/proxytype.py,sha256=nwOhAqcVIG4h9uonXWBvQidKSbF4YSuMzrGJFlonk0s,12595
|
|
20
|
+
retracesoftware/proxy/record.py,sha256=Ukjrzsv7WMA-2oC6Ji-JgIr0R8pRLyQGkHc8grzKtpE,8000
|
|
21
21
|
retracesoftware/proxy/replay.py,sha256=RVsezEZcy4bFdPQAAztfEHz6adm8t5lBDMhpnNAqeok,10510
|
|
22
22
|
retracesoftware/proxy/stubfactory.py,sha256=UnRDQHgWv2xTYaMPZPXvsa7WBh10CyItc_hsQdtOhcM,4607
|
|
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.8.dist-info/METADATA,sha256=MiCu-FDSk5wmZv30Kz-R-A8UKJxP-0sLHent41c__5o,202
|
|
25
|
+
retracesoftware_proxy-0.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
26
|
+
retracesoftware_proxy-0.1.8.dist-info/top_level.txt,sha256=hYHsR6txLidmqvjBMITpIHvmJJbmoCAgr76-IpZPRz8,16
|
|
27
|
+
retracesoftware_proxy-0.1.8.dist-info/RECORD,,
|
|
File without changes
|
{retracesoftware_proxy-0.1.6.dist-info → retracesoftware_proxy-0.1.8.dist-info}/top_level.txt
RENAMED
|
File without changes
|