retracesoftware-proxy 0.1.12__py3-none-any.whl → 0.1.14__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 +21 -6
- retracesoftware/config.yaml +0 -0
- retracesoftware/install/patcher.py +56 -10
- retracesoftware/install/record.py +9 -3
- retracesoftware/proxy/__init__.py +1 -1
- retracesoftware/proxy/globalref.py +31 -0
- retracesoftware/proxy/proxytype.py +10 -4
- retracesoftware/proxy/record.py +37 -19
- retracesoftware/proxy/replay.py +32 -9
- retracesoftware/proxy/thread.py +16 -4
- {retracesoftware_proxy-0.1.12.dist-info → retracesoftware_proxy-0.1.14.dist-info}/METADATA +1 -1
- {retracesoftware_proxy-0.1.12.dist-info → retracesoftware_proxy-0.1.14.dist-info}/RECORD +14 -12
- {retracesoftware_proxy-0.1.12.dist-info → retracesoftware_proxy-0.1.14.dist-info}/WHEEL +0 -0
- {retracesoftware_proxy-0.1.12.dist-info → retracesoftware_proxy-0.1.14.dist-info}/top_level.txt +0 -0
retracesoftware/config.json
CHANGED
|
@@ -158,7 +158,12 @@
|
|
|
158
158
|
|
|
159
159
|
"modules": {
|
|
160
160
|
"_imp": {
|
|
161
|
-
"patch_extension_exec": ["exec_dynamic", "exec_builtin"]
|
|
161
|
+
"patch_extension_exec": ["exec_dynamic", "exec_builtin"],
|
|
162
|
+
"comment": {
|
|
163
|
+
"with_state": {
|
|
164
|
+
"internal": ["create_dynamic"]
|
|
165
|
+
}
|
|
166
|
+
}
|
|
162
167
|
},
|
|
163
168
|
"bdb": {
|
|
164
169
|
"methods_with_state": {
|
|
@@ -183,7 +188,11 @@
|
|
|
183
188
|
|
|
184
189
|
"importlib._bootstrap": {
|
|
185
190
|
"with_state": {
|
|
186
|
-
"bootstrap": [
|
|
191
|
+
"bootstrap": [
|
|
192
|
+
"_load_unlocked",
|
|
193
|
+
"_find_spec",
|
|
194
|
+
"_lock_unlock_module",
|
|
195
|
+
"_get_module_lock"]
|
|
187
196
|
}
|
|
188
197
|
},
|
|
189
198
|
|
|
@@ -215,14 +224,20 @@
|
|
|
215
224
|
]
|
|
216
225
|
},
|
|
217
226
|
"types": {
|
|
227
|
+
"patch_hash": ["FunctionType"],
|
|
218
228
|
"immutable_types": [
|
|
219
|
-
"TracebackType"
|
|
229
|
+
"TracebackType",
|
|
230
|
+
"ModuleType"
|
|
220
231
|
]
|
|
221
232
|
},
|
|
222
233
|
"builtins": {
|
|
223
|
-
"
|
|
224
|
-
|
|
225
|
-
|
|
234
|
+
"patch_hash": ["object"],
|
|
235
|
+
|
|
236
|
+
"comment": {
|
|
237
|
+
"replace": {
|
|
238
|
+
"set": "retracesoftware_utils.set",
|
|
239
|
+
"frozenset": "retracesoftware_utils.frozenset"
|
|
240
|
+
}
|
|
226
241
|
},
|
|
227
242
|
"immutable_types": [
|
|
228
243
|
"BaseException",
|
|
File without changes
|
|
@@ -121,9 +121,22 @@ def patch(func):
|
|
|
121
121
|
if isinstance(spec, str):
|
|
122
122
|
return wrapper(self, [spec], mod_dict)
|
|
123
123
|
elif isinstance(spec, list):
|
|
124
|
-
|
|
124
|
+
res = {}
|
|
125
|
+
for name in spec:
|
|
126
|
+
if name in mod_dict:
|
|
127
|
+
value = func(self, mod_dict[name])
|
|
128
|
+
if value is not None:
|
|
129
|
+
res[name] = value
|
|
130
|
+
return res
|
|
125
131
|
elif isinstance(spec, dict):
|
|
126
|
-
return {name: func(self, mod_dict[name], value) for name, value in spec.items() if name in mod_dict}
|
|
132
|
+
# return {name: func(self, mod_dict[name], value) for name, value in spec.items() if name in mod_dict}
|
|
133
|
+
res = {}
|
|
134
|
+
for name,value in spec.items():
|
|
135
|
+
if name in mod_dict:
|
|
136
|
+
value = func(self, mod_dict[name], value)
|
|
137
|
+
if value is not None:
|
|
138
|
+
res[name] = value
|
|
139
|
+
return res
|
|
127
140
|
else:
|
|
128
141
|
raise Exception('TODO')
|
|
129
142
|
|
|
@@ -155,6 +168,11 @@ def wrap_method_descriptors(wrapper, prefix, base):
|
|
|
155
168
|
|
|
156
169
|
return extended
|
|
157
170
|
|
|
171
|
+
class PerThread(threading.local):
|
|
172
|
+
def __init__(self):
|
|
173
|
+
self.internal = utils.counter()
|
|
174
|
+
self.externak = utils.counter()
|
|
175
|
+
|
|
158
176
|
class Patcher:
|
|
159
177
|
|
|
160
178
|
def __init__(self, thread_state, config, system,
|
|
@@ -164,7 +182,7 @@ class Patcher:
|
|
|
164
182
|
post_commit = None):
|
|
165
183
|
|
|
166
184
|
# validate(config)
|
|
167
|
-
|
|
185
|
+
system.set_thread_id(0)
|
|
168
186
|
# utils.set_thread_id(0)
|
|
169
187
|
self.thread_counter = system.sync(utils.counter(1))
|
|
170
188
|
# self.set_thread_number = set_thread_number
|
|
@@ -181,6 +199,13 @@ class Patcher:
|
|
|
181
199
|
self.exclude_paths = [re.compile(s) for s in config.get('exclude_paths', [])]
|
|
182
200
|
self.typepatcher = {}
|
|
183
201
|
|
|
202
|
+
per_thread = PerThread()
|
|
203
|
+
|
|
204
|
+
self.hashfunc = self.thread_state.dispatch(
|
|
205
|
+
functional.constantly(None),
|
|
206
|
+
internal = functional.repeatedly(functional.partial(getattr, per_thread, 'internal')),
|
|
207
|
+
external = functional.repeatedly(functional.partial(getattr, per_thread, 'external')))
|
|
208
|
+
|
|
184
209
|
def is_phase(name): return getattr(getattr(self, name, None), "is_phase", False)
|
|
185
210
|
|
|
186
211
|
self.phases = [(name, getattr(self, name)) for name in Patcher.__dict__.keys() if is_phase(name)]
|
|
@@ -303,19 +328,35 @@ class Patcher:
|
|
|
303
328
|
source.co_name == '<module>' and inspect.getmodule(source)
|
|
304
329
|
|
|
305
330
|
def exec_wrapper(source, *args,**kwargs):
|
|
306
|
-
|
|
307
|
-
|
|
331
|
+
module = None
|
|
332
|
+
|
|
333
|
+
with self.thread_state.select('disabled'):
|
|
334
|
+
if is_module_exec(source):
|
|
308
335
|
module = inspect.getmodule(source)
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
336
|
+
|
|
337
|
+
if module:
|
|
338
|
+
result = exec(source, *args, **kwargs)
|
|
312
339
|
self(module)
|
|
313
|
-
|
|
314
340
|
return result
|
|
315
341
|
else:
|
|
316
342
|
return exec(source, *args,**kwargs)
|
|
317
343
|
|
|
318
|
-
|
|
344
|
+
# if self.thread_state.value != 'bootstrap':
|
|
345
|
+
|
|
346
|
+
# and is_module_exec(source):
|
|
347
|
+
# with self.thread_state.select('disabled'):
|
|
348
|
+
# module = inspect.getmodule(source)
|
|
349
|
+
# with self.thread_state.select('internal'):
|
|
350
|
+
# result = exec(source, *args, **kwargs)
|
|
351
|
+
|
|
352
|
+
# self(module)
|
|
353
|
+
|
|
354
|
+
# return result
|
|
355
|
+
# else:
|
|
356
|
+
# return exec(source, *args,**kwargs)
|
|
357
|
+
|
|
358
|
+
return self.thread_state.dispatch(exec, internal = exec_wrapper)
|
|
359
|
+
# self.thread_state.wrap(desired_state = 'disabled', function = exec_wrapper)
|
|
319
360
|
|
|
320
361
|
@patch
|
|
321
362
|
def sync_types(self, value):
|
|
@@ -372,6 +413,11 @@ class Patcher:
|
|
|
372
413
|
|
|
373
414
|
return updates
|
|
374
415
|
|
|
416
|
+
@patch
|
|
417
|
+
def patch_hash(self, cls):
|
|
418
|
+
print(f'patching hash for: {cls}')
|
|
419
|
+
utils.patch_hash(cls = cls, hashfunc = self.hashfunc)
|
|
420
|
+
|
|
375
421
|
@patch
|
|
376
422
|
def patch_extension_exec(self, exec):
|
|
377
423
|
|
|
@@ -13,9 +13,15 @@ from datetime import datetime
|
|
|
13
13
|
import json
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
|
-
class ThreadSwitch:
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
# class ThreadSwitch:
|
|
17
|
+
# def __init__(self, id):
|
|
18
|
+
# self.id = id
|
|
19
|
+
|
|
20
|
+
# def __repr__(self):
|
|
21
|
+
# return f'ThreadSwitch<{self.id}>'
|
|
22
|
+
|
|
23
|
+
# def __str__(self):
|
|
24
|
+
# return f'ThreadSwitch<{self.id}>'
|
|
19
25
|
|
|
20
26
|
def write_files(recording_path):
|
|
21
27
|
with open(recording_path / 'env', 'w') as f:
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import types
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
def find_module_name(mod):
|
|
5
|
+
for name,value in sys.modules.items():
|
|
6
|
+
if value is mod:
|
|
7
|
+
return name
|
|
8
|
+
|
|
9
|
+
raise Exception(f"Cannot create GlobalRef as module {mod} not found in sys.modules")
|
|
10
|
+
|
|
11
|
+
class GlobalRef:
|
|
12
|
+
__slots__ = ['parts']
|
|
13
|
+
|
|
14
|
+
def __init__(self, obj):
|
|
15
|
+
if isinstance(obj, types.ModuleType):
|
|
16
|
+
self.parts = (find_module_name(obj),)
|
|
17
|
+
else:
|
|
18
|
+
raise Exception(f"Cannot create GlobalRef from {obj}")
|
|
19
|
+
|
|
20
|
+
def __call__(self):
|
|
21
|
+
module = self.parts[0]
|
|
22
|
+
|
|
23
|
+
if len(self.parts) == 0:
|
|
24
|
+
return module
|
|
25
|
+
else:
|
|
26
|
+
obj = getattr(module, self.parts[1])
|
|
27
|
+
|
|
28
|
+
if len(self.parts) == 1:
|
|
29
|
+
return obj
|
|
30
|
+
else:
|
|
31
|
+
raise Exception(f"TODO")
|
|
@@ -214,10 +214,16 @@ def dynamic_proxytype(handler, cls):
|
|
|
214
214
|
|
|
215
215
|
for name in superdict(cls).keys():
|
|
216
216
|
if name not in blacklist:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
if
|
|
220
|
-
|
|
217
|
+
try:
|
|
218
|
+
value = getattr(cls, name)
|
|
219
|
+
if is_descriptor(value):
|
|
220
|
+
if utils.is_method_descriptor(value):
|
|
221
|
+
spec[name] = wrap(value)
|
|
222
|
+
except Exception as error:
|
|
223
|
+
print(f'FOO! {cls} {name} {error}')
|
|
224
|
+
breakpoint()
|
|
225
|
+
raise
|
|
226
|
+
|
|
221
227
|
# else:
|
|
222
228
|
# spec[name] = DescriptorProxy(handler = handler, target = value)
|
|
223
229
|
|
retracesoftware/proxy/record.py
CHANGED
|
@@ -5,9 +5,10 @@ import retracesoftware.stream as stream
|
|
|
5
5
|
from retracesoftware.proxy.proxytype import *
|
|
6
6
|
# from retracesoftware.proxy.gateway import gateway_pair
|
|
7
7
|
from retracesoftware.proxy.proxysystem import ProxySystem
|
|
8
|
-
from retracesoftware.proxy.thread import write_thread_switch
|
|
8
|
+
from retracesoftware.proxy.thread import write_thread_switch, ThreadSwitch
|
|
9
9
|
from retracesoftware.install.tracer import Tracer
|
|
10
10
|
from retracesoftware.proxy.stubfactory import StubRef, ExtendedRef
|
|
11
|
+
from retracesoftware.proxy.globalref import GlobalRef
|
|
11
12
|
|
|
12
13
|
import sys
|
|
13
14
|
import os
|
|
@@ -69,14 +70,11 @@ class RecordProxySystem(ProxySystem):
|
|
|
69
70
|
super().after_fork_in_parent()
|
|
70
71
|
self.thread_state.value = self.saved_thread_state
|
|
71
72
|
self.writer.reopen()
|
|
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
|
|
|
74
|
+
def set_thread_id(self, id):
|
|
75
|
+
utils.set_thread_id(self.writer.handle(ThreadSwitch(id)))
|
|
76
|
+
# utils.set_thread_id(id)
|
|
77
|
+
|
|
80
78
|
def __init__(self, thread_state,
|
|
81
79
|
immutable_types,
|
|
82
80
|
tracing_config,
|
|
@@ -91,6 +89,15 @@ class RecordProxySystem(ProxySystem):
|
|
|
91
89
|
|
|
92
90
|
self.writer = stream.writer(path)
|
|
93
91
|
|
|
92
|
+
def on_switch():
|
|
93
|
+
print(f"On thread switch!!!")
|
|
94
|
+
# print(f"On thread switch!!!: {utils.thread_id().id}")
|
|
95
|
+
# utils.sigtrap(utils.thread_id())
|
|
96
|
+
self.writer(utils.thread_id())
|
|
97
|
+
# utils.sigtrap(utils.thread_id())
|
|
98
|
+
|
|
99
|
+
write = utils.observer(on_call = utils.thread_switch_monitor(on_switch), function = self.writer)
|
|
100
|
+
|
|
94
101
|
# w = self.writer.handle('TRACE')
|
|
95
102
|
# def trace_writer(*args):
|
|
96
103
|
# print(f'Trace: {args}')
|
|
@@ -102,39 +109,50 @@ class RecordProxySystem(ProxySystem):
|
|
|
102
109
|
|
|
103
110
|
serialize = functional.walker(self.bindings.get_else_key)
|
|
104
111
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
112
|
+
# def on_switch():
|
|
113
|
+
# print("On thread switch!!!")
|
|
114
|
+
# # utils.sigtrap(utils.thread_id())
|
|
115
|
+
# utils.thread_id()()
|
|
116
|
+
# # utils.sigtrap(utils.thread_id())
|
|
117
|
+
|
|
118
|
+
# self.thread_switch_monitor = utils.thread_switch_monitor(on_switch)
|
|
119
|
+
|
|
120
|
+
# self.thread_switch_monitor = utils.thread_switch_monitor(functional.repeatedly(utils.thread_id))
|
|
108
121
|
|
|
109
122
|
# self.sync = lambda function: functional.firstof(self.thread_switch_monitor, functional.always(self.writer.handle('SYNC')), function)
|
|
110
|
-
|
|
123
|
+
|
|
124
|
+
self.sync = lambda function: \
|
|
125
|
+
utils.observer(
|
|
126
|
+
on_call = functional.lazy(write, self.writer.handle('SYNC')),
|
|
127
|
+
function = function)
|
|
128
|
+
|
|
111
129
|
error = self.writer.handle('ERROR')
|
|
112
130
|
|
|
113
131
|
def write_error(cls, val, traceback):
|
|
114
|
-
error
|
|
132
|
+
write(error, cls, val)
|
|
115
133
|
|
|
116
134
|
# self.set_thread_id = functional.partial(utils.set_thread_id, self.writer)
|
|
117
135
|
|
|
118
|
-
def watch(f): return functional.either(self.thread_switch_monitor, f)
|
|
119
|
-
|
|
120
136
|
# w = self.writer.handle('TRACE')
|
|
121
137
|
# def foo(name, *args):
|
|
122
138
|
# print(f'writing: {self.writer.messages_written} {name} {args}')
|
|
123
139
|
# w(self.writer.messages_written, name, *args)
|
|
124
140
|
|
|
125
141
|
# tracer = Tracer(tracing_config, writer = foo)
|
|
126
|
-
tracer = Tracer(tracing_config, writer = self.writer.handle('TRACE'))
|
|
142
|
+
tracer = Tracer(tracing_config, writer = functional.partial(write, self.writer.handle('TRACE')))
|
|
127
143
|
|
|
128
|
-
self.wrap_int_to_ext =
|
|
144
|
+
# self.wrap_int_to_ext = self.sync
|
|
129
145
|
|
|
130
|
-
self.on_int_call = functional.mapargs(transform = serialize, function = self.writer.handle('CALL'))
|
|
146
|
+
self.on_int_call = functional.mapargs(transform = serialize, function = functional.partial(write, self.writer.handle('CALL')))
|
|
131
147
|
|
|
132
|
-
self.on_ext_result = functional.sequence(serialize, self.writer.handle('RESULT'))
|
|
148
|
+
self.on_ext_result = functional.sequence(serialize, functional.partial(write, self.writer.handle('RESULT')))
|
|
133
149
|
|
|
134
150
|
self.on_ext_error = write_error
|
|
135
151
|
|
|
136
152
|
self.ext_apply = self.int_apply = functional.apply
|
|
137
153
|
|
|
154
|
+
self.writer.type_serializer[types.ModuleType] = GlobalRef
|
|
155
|
+
|
|
138
156
|
super().__init__(thread_state = thread_state,
|
|
139
157
|
tracer = tracer,
|
|
140
158
|
immutable_types = immutable_types)
|
retracesoftware/proxy/replay.py
CHANGED
|
@@ -8,7 +8,8 @@ from retracesoftware.proxy.proxytype import *
|
|
|
8
8
|
# from retracesoftware.proxy.gateway import gateway_pair
|
|
9
9
|
from retracesoftware.proxy.record import StubRef, Placeholder
|
|
10
10
|
from retracesoftware.proxy.proxysystem import ProxySystem, RetraceError
|
|
11
|
-
from retracesoftware.proxy.stubfactory import StubFactory, StubFunction
|
|
11
|
+
from retracesoftware.proxy.stubfactory import StubFactory, Stub, StubFunction
|
|
12
|
+
from retracesoftware.proxy.globalref import GlobalRef
|
|
12
13
|
|
|
13
14
|
import os
|
|
14
15
|
import weakref
|
|
@@ -153,6 +154,9 @@ class ReplayProxySystem(ProxySystem):
|
|
|
153
154
|
def read_required(self, required):
|
|
154
155
|
obj = self.readnext()
|
|
155
156
|
if obj != required:
|
|
157
|
+
print('---------------------------------')
|
|
158
|
+
print('last matching stack')
|
|
159
|
+
print('---------------------------------')
|
|
156
160
|
if self.last_matching_stack:
|
|
157
161
|
for line in self.last_matching_stack:
|
|
158
162
|
print(line)
|
|
@@ -160,6 +164,9 @@ class ReplayProxySystem(ProxySystem):
|
|
|
160
164
|
print('---------------------------------')
|
|
161
165
|
print(f'Replay: {required}')
|
|
162
166
|
print('---------------------------------')
|
|
167
|
+
for line in utils.stacktrace():
|
|
168
|
+
print(line)
|
|
169
|
+
print('---------------------------------')
|
|
163
170
|
print(f'Record: {obj}')
|
|
164
171
|
print('---------------------------------')
|
|
165
172
|
for i in range(15):
|
|
@@ -194,9 +201,6 @@ class ReplayProxySystem(ProxySystem):
|
|
|
194
201
|
for arg in args:
|
|
195
202
|
self.read_required(arg)
|
|
196
203
|
|
|
197
|
-
def sync(self, function):
|
|
198
|
-
return utils.observer(on_call = functional.always(self.read_sync), function = function)
|
|
199
|
-
|
|
200
204
|
def __init__(self,
|
|
201
205
|
thread_state,
|
|
202
206
|
immutable_types,
|
|
@@ -208,25 +212,44 @@ class ReplayProxySystem(ProxySystem):
|
|
|
208
212
|
self.reader = stream.reader(path)
|
|
209
213
|
|
|
210
214
|
self.bindings = utils.id_dict()
|
|
211
|
-
self.set_thread_id = utils.set_thread_id
|
|
215
|
+
# self.set_thread_id = utils.set_thread_id
|
|
212
216
|
self.fork_path = fork_path
|
|
213
217
|
deserialize = functional.walker(self.bindings.get_else_key)
|
|
214
218
|
|
|
215
219
|
# def count(res):
|
|
216
220
|
# self.messages_read += 1
|
|
217
221
|
# return res
|
|
222
|
+
|
|
223
|
+
read_res = functional.vector(functional.lazy(getattr, self.reader, 'messages_read'), self.reader)
|
|
224
|
+
|
|
225
|
+
def foo():
|
|
226
|
+
try:
|
|
227
|
+
messages_read, res = read_res()
|
|
228
|
+
if issubclass(type(res), Stub):
|
|
229
|
+
print(f'res: {utils.thread_id()} {messages_read} stub: {type(res)}')
|
|
230
|
+
else:
|
|
231
|
+
print(f'res: {utils.thread_id()} {messages_read} {res}')
|
|
232
|
+
|
|
233
|
+
return res
|
|
234
|
+
except Exception as error:
|
|
235
|
+
print(f'Error reading next result: {error}')
|
|
236
|
+
raise(error)
|
|
218
237
|
|
|
219
|
-
self.messages = functional.sequence(per_thread_messages(
|
|
220
|
-
|
|
238
|
+
self.messages = functional.sequence(per_thread_messages(foo), deserialize)
|
|
239
|
+
|
|
240
|
+
# self.messages = functional.sequence(per_thread_messages(self.reader), deserialize)
|
|
221
241
|
|
|
222
242
|
self.stub_factory = StubFactory(thread_state = thread_state, next_result = self.next_result)
|
|
223
243
|
|
|
224
244
|
self.last_matching_stack = None
|
|
225
245
|
|
|
226
246
|
self.reader.type_deserializer[StubRef] = self.stub_factory
|
|
247
|
+
self.reader.type_deserializer[GlobalRef] = lambda ref: ref()
|
|
227
248
|
|
|
228
|
-
|
|
229
|
-
|
|
249
|
+
read_sync = functional.lazy(self.read_required, 'SYNC')
|
|
250
|
+
|
|
251
|
+
self.sync = lambda function: utils.observer(on_call = read_sync, function = function)
|
|
252
|
+
|
|
230
253
|
super().__init__(thread_state = thread_state,
|
|
231
254
|
tracer = Tracer(tracing_config, writer = self.trace_writer),
|
|
232
255
|
immutable_types = immutable_types)
|
retracesoftware/proxy/thread.py
CHANGED
|
@@ -11,17 +11,28 @@ class ThreadSwitch:
|
|
|
11
11
|
def __init__(self, id):
|
|
12
12
|
self.id = id
|
|
13
13
|
|
|
14
|
-
def
|
|
15
|
-
|
|
14
|
+
def __repr__(self):
|
|
15
|
+
return f'ThreadSwitch<{self.id}>'
|
|
16
|
+
|
|
17
|
+
def __str__(self):
|
|
18
|
+
return f'ThreadSwitch<{self.id}>'
|
|
19
|
+
|
|
20
|
+
# def set_thread_id(writer, id):
|
|
21
|
+
# utils.sigtrap(id)
|
|
22
|
+
# utils.set_thread_id(writer.handle(ThreadSwitch(id)))
|
|
16
23
|
|
|
17
24
|
def write_thread_switch(writer):
|
|
18
25
|
on_thread_switch = functional.repeatedly(functional.sequence(utils.thread_id, writer))
|
|
19
26
|
|
|
20
27
|
return lambda f: utils.thread_aware_proxy(target = f, on_thread_switch = on_thread_switch, sticky = False)
|
|
21
28
|
|
|
22
|
-
def prefix_with_thread_id(f,
|
|
29
|
+
def prefix_with_thread_id(f, thread_id):
|
|
30
|
+
current = None
|
|
31
|
+
|
|
23
32
|
def next():
|
|
24
33
|
nonlocal current, f
|
|
34
|
+
if current is None: current = thread_id()
|
|
35
|
+
|
|
25
36
|
obj = f()
|
|
26
37
|
|
|
27
38
|
while issubclass(type(obj), ThreadSwitch):
|
|
@@ -36,7 +47,8 @@ def per_thread_messages(messages):
|
|
|
36
47
|
thread_id = utils.thread_id
|
|
37
48
|
# thread_id = lambda: 'FOOOOO!!!'
|
|
38
49
|
|
|
39
|
-
demux = utils.demux(source = prefix_with_thread_id(messages, thread_id
|
|
50
|
+
demux = utils.demux(source = prefix_with_thread_id(messages, thread_id),
|
|
51
|
+
key_function = lambda obj: obj[0])
|
|
40
52
|
|
|
41
53
|
# def next():
|
|
42
54
|
# thread,message = demux(thread_id())
|
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
retracesoftware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
retracesoftware/config.json,sha256=
|
|
2
|
+
retracesoftware/config.json,sha256=JU3LYWZbqBLqiHXDc9fBYVh0owMUcKGw3W-vaVm-roo,9024
|
|
3
|
+
retracesoftware/config.yaml,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
4
|
retracesoftware/install/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
5
|
retracesoftware/install/config.py,sha256=EzE5ifQF2lo--hu2njI4T0FJ-zlnWDJV6i7x0DMkVTw,1364
|
|
5
6
|
retracesoftware/install/edgecases.py,sha256=NR3lyvad9sRsyeDv_Ya8V4xMgPsMPOi9rMcnFOJGOEA,6330
|
|
6
7
|
retracesoftware/install/globals.py,sha256=F8XvIoZQQ10gSRalk30dvdKllxlwxkaggYY6FogLDxY,510
|
|
7
8
|
retracesoftware/install/install.py,sha256=HCD_ji8XCr96b5fNzNdL_8qcEp0Jf05Em7T6GA6u8HU,4969
|
|
8
|
-
retracesoftware/install/patcher.py,sha256=
|
|
9
|
+
retracesoftware/install/patcher.py,sha256=ryX73_KjdcUCC0oy0Uqel_L3bwfZZldS3CIYQ-XAl_k,20520
|
|
9
10
|
retracesoftware/install/predicate.py,sha256=tX7NQc0rGkyyHYO3mduYHcJHbw1wczT53m_Dpkzo6do,2679
|
|
10
|
-
retracesoftware/install/record.py,sha256=
|
|
11
|
+
retracesoftware/install/record.py,sha256=R2GOIA_WAggrNmVwZJh9r1xp-GVu43iKq-ykQ1VKEHE,3408
|
|
11
12
|
retracesoftware/install/references.py,sha256=A-G651IDOfuo00MkbAdpbIQh_15ChvJ7uAVTSmE6zd4,1721
|
|
12
13
|
retracesoftware/install/replay.py,sha256=VUiHvQK3mgAJEGmtE2TFs9kXzxdWtsjibEcGkhZVCVE,1830
|
|
13
14
|
retracesoftware/install/tracer.py,sha256=cHEjiVxIp2iVTJEWndwSbMuiXVyGJQxJYZSGrfpSbCw,5723
|
|
14
15
|
retracesoftware/install/typeutils.py,sha256=_a1PuwdCsYjG1Nkd77V-flqYtwbD4RkJVKn6Z-xABL4,1813
|
|
15
|
-
retracesoftware/proxy/__init__.py,sha256=
|
|
16
|
+
retracesoftware/proxy/__init__.py,sha256=ntIyqKhBRkKEkcW_oOPodikh-mxYl8OXRnSaj-9-Xwc,178
|
|
16
17
|
retracesoftware/proxy/gateway.py,sha256=xESohWXkiNm4ZutU0RgWUwxjxcBWRQ4rQyxIGQXv_F4,1590
|
|
18
|
+
retracesoftware/proxy/globalref.py,sha256=yXtJsOeBHN9xoEgJWA3MJco-jD2SQUef_fDatA4A6rg,803
|
|
17
19
|
retracesoftware/proxy/proxyfactory.py,sha256=qhOqDfMJnLDNkQs26JqDB431MwjjRhGQi8xupJ45asg,12272
|
|
18
20
|
retracesoftware/proxy/proxysystem.py,sha256=ZX6eNT8go-YDbLWD2pq5j_V8DZAHteu-iNfkMO8jLWg,7567
|
|
19
|
-
retracesoftware/proxy/proxytype.py,sha256=
|
|
20
|
-
retracesoftware/proxy/record.py,sha256=
|
|
21
|
-
retracesoftware/proxy/replay.py,sha256=
|
|
21
|
+
retracesoftware/proxy/proxytype.py,sha256=hP-1vJmWBa9KgZFB3CnZy0UbC4u8Wr2e76lGI0JM2SA,12992
|
|
22
|
+
retracesoftware/proxy/record.py,sha256=QBx3G8mXjUiB9vCXJZ0tZdt3Mi1WEtRhuZ7HOUroNNQ,5505
|
|
23
|
+
retracesoftware/proxy/replay.py,sha256=vVFkhYOOZSprLD_mjx-p6SpDB8fy81SK3x2A5H0odUs,8614
|
|
22
24
|
retracesoftware/proxy/stubfactory.py,sha256=37UX1r8HCAbASTwPdz8QKCrg72NQmM5PsiCho7N2nzg,5129
|
|
23
|
-
retracesoftware/proxy/thread.py,sha256
|
|
24
|
-
retracesoftware_proxy-0.1.
|
|
25
|
-
retracesoftware_proxy-0.1.
|
|
26
|
-
retracesoftware_proxy-0.1.
|
|
27
|
-
retracesoftware_proxy-0.1.
|
|
25
|
+
retracesoftware/proxy/thread.py,sha256=idkJwJ8rR1kpRHfo81uCi6Y0LEIChAdfc0GqK_bFqTA,1635
|
|
26
|
+
retracesoftware_proxy-0.1.14.dist-info/METADATA,sha256=Y6QfA5aDmUke1rEvUWSOgRIwbEAk7YbbcpW-7m00kQM,203
|
|
27
|
+
retracesoftware_proxy-0.1.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
28
|
+
retracesoftware_proxy-0.1.14.dist-info/top_level.txt,sha256=hYHsR6txLidmqvjBMITpIHvmJJbmoCAgr76-IpZPRz8,16
|
|
29
|
+
retracesoftware_proxy-0.1.14.dist-info/RECORD,,
|
|
File without changes
|
{retracesoftware_proxy-0.1.12.dist-info → retracesoftware_proxy-0.1.14.dist-info}/top_level.txt
RENAMED
|
File without changes
|