retracesoftware-proxy 0.1.0__py3-none-any.whl → 0.1.2__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 +7 -0
- retracesoftware/install/install.py +2 -26
- retracesoftware/install/patcher.py +52 -9
- retracesoftware/install/record.py +15 -40
- retracesoftware/install/replay.py +4 -101
- retracesoftware/install/tracer.py +18 -16
- retracesoftware/proxy/__init__.py +1 -1
- retracesoftware/proxy/gateway.py +25 -76
- retracesoftware/proxy/proxyfactory.py +194 -194
- retracesoftware/proxy/proxysystem.py +192 -10
- retracesoftware/proxy/proxytype.py +235 -96
- retracesoftware/proxy/record.py +184 -96
- retracesoftware/proxy/replay.py +184 -60
- retracesoftware/proxy/stubfactory.py +141 -0
- retracesoftware/proxy/thread.py +40 -5
- {retracesoftware_proxy-0.1.0.dist-info → retracesoftware_proxy-0.1.2.dist-info}/METADATA +1 -6
- retracesoftware_proxy-0.1.2.dist-info/RECORD +27 -0
- retracesoftware_proxy-0.1.0.dist-info/RECORD +0 -26
- {retracesoftware_proxy-0.1.0.dist-info → retracesoftware_proxy-0.1.2.dist-info}/WHEEL +0 -0
- {retracesoftware_proxy-0.1.0.dist-info → retracesoftware_proxy-0.1.2.dist-info}/top_level.txt +0 -0
retracesoftware/config.json
CHANGED
|
@@ -164,6 +164,9 @@
|
|
|
164
164
|
"sys": {
|
|
165
165
|
"with_state": {
|
|
166
166
|
"disabled": ["excepthook"]
|
|
167
|
+
},
|
|
168
|
+
"with_state_recursive0": {
|
|
169
|
+
"disabled": ["settrace", "setprofile"]
|
|
167
170
|
}
|
|
168
171
|
},
|
|
169
172
|
|
|
@@ -293,6 +296,10 @@
|
|
|
293
296
|
"_path_normpath"
|
|
294
297
|
],
|
|
295
298
|
|
|
299
|
+
"with_state_recursive0": {
|
|
300
|
+
"disabled": ["register_at_fork"]
|
|
301
|
+
},
|
|
302
|
+
|
|
296
303
|
"wrappers": {
|
|
297
304
|
"fork_exec": "retracesoftware.install.edgecases.fork_exec",
|
|
298
305
|
"posix_spawn": "retracesoftware.install.edgecases.posix_spawn"
|
|
@@ -58,7 +58,7 @@ class MethodDescriptor:
|
|
|
58
58
|
self.cls = descriptor.__objclass__
|
|
59
59
|
self.name = descriptor.name
|
|
60
60
|
|
|
61
|
-
def once(*args): return functional.memoize_one_arg(functional.
|
|
61
|
+
def once(*args): return functional.memoize_one_arg(functional.sequence(*args))
|
|
62
62
|
|
|
63
63
|
any = functional.firstof
|
|
64
64
|
|
|
@@ -121,7 +121,7 @@ def replaying_proxy_factory(thread_state, is_immutable_type, tracer, next, bind,
|
|
|
121
121
|
on_call = tracer('proxy.ext.call'),
|
|
122
122
|
on_result = tracer('proxy.ext.result'),
|
|
123
123
|
on_error = tracer('proxy.ext.error'),
|
|
124
|
-
function = functional.
|
|
124
|
+
function = functional.sequence(functional.always(next), create_stubs))
|
|
125
125
|
|
|
126
126
|
return ProxyFactory(thread_state = thread_state,
|
|
127
127
|
is_immutable_type = is_immutable_type,
|
|
@@ -131,30 +131,6 @@ def replaying_proxy_factory(thread_state, is_immutable_type, tracer, next, bind,
|
|
|
131
131
|
wrap_int_call = wrap_int_call,
|
|
132
132
|
wrap_ext_call = wrap_ext_call)
|
|
133
133
|
|
|
134
|
-
def latest_from_pattern(pattern: str) -> str | None:
|
|
135
|
-
"""
|
|
136
|
-
Given a strftime-style filename pattern (e.g. "recordings/%Y%m%d_%H%M%S_%f"),
|
|
137
|
-
return the path to the most recent matching file, or None if no files exist.
|
|
138
|
-
"""
|
|
139
|
-
# Turn strftime placeholders into '*' for globbing
|
|
140
|
-
# (very simple replacement: %... -> *)
|
|
141
|
-
glob_pattern = re.sub(r"%[a-zA-Z]", "*", pattern)
|
|
142
|
-
|
|
143
|
-
# Find all matching files
|
|
144
|
-
candidates = glob.glob(glob_pattern)
|
|
145
|
-
if not candidates:
|
|
146
|
-
return None
|
|
147
|
-
|
|
148
|
-
# Derive the datetime format from the pattern (basename only)
|
|
149
|
-
base_pattern = os.path.basename(pattern)
|
|
150
|
-
|
|
151
|
-
def parse_time(path: str):
|
|
152
|
-
name = os.path.basename(path)
|
|
153
|
-
return datetime.strptime(name, base_pattern)
|
|
154
|
-
|
|
155
|
-
# Find the latest by parsed timestamp
|
|
156
|
-
latest = max(candidates, key=parse_time)
|
|
157
|
-
return latest
|
|
158
134
|
|
|
159
135
|
# class Reader:
|
|
160
136
|
|
|
@@ -24,7 +24,7 @@ from retracesoftware.install.config import load_config
|
|
|
24
24
|
|
|
25
25
|
from functools import wraps
|
|
26
26
|
|
|
27
|
-
import
|
|
27
|
+
import retracesoftware.functional as functional
|
|
28
28
|
import retracesoftware_utils as utils
|
|
29
29
|
|
|
30
30
|
from retracesoftware.install import edgecases
|
|
@@ -158,13 +158,14 @@ def wrap_method_descriptors(wrapper, prefix, base):
|
|
|
158
158
|
class Patcher:
|
|
159
159
|
|
|
160
160
|
def __init__(self, thread_state, config, system,
|
|
161
|
-
immutable_types,
|
|
161
|
+
immutable_types,
|
|
162
162
|
on_function_proxy = None,
|
|
163
163
|
debug_level = 0,
|
|
164
164
|
post_commit = None):
|
|
165
165
|
|
|
166
166
|
# validate(config)
|
|
167
|
-
|
|
167
|
+
# system.set_thread_id(0)
|
|
168
|
+
# utils.set_thread_id(0)
|
|
168
169
|
self.thread_counter = system.sync(utils.counter(1))
|
|
169
170
|
# self.set_thread_number = set_thread_number
|
|
170
171
|
|
|
@@ -217,6 +218,7 @@ class Patcher:
|
|
|
217
218
|
for name in spec:
|
|
218
219
|
if name in mod_dict:
|
|
219
220
|
if isinstance(mod_dict[name], type):
|
|
221
|
+
assert isinstance(mod_dict[name], type)
|
|
220
222
|
self.immutable_types_set.add(mod_dict[name])
|
|
221
223
|
else:
|
|
222
224
|
raise Exception(f'Tried to add "{name}" - {mod_dict[name]} which isn\'t a type to immutable')
|
|
@@ -264,7 +266,7 @@ class Patcher:
|
|
|
264
266
|
|
|
265
267
|
def threadrunner(*args, **kwargs):
|
|
266
268
|
nonlocal thread_id
|
|
267
|
-
|
|
269
|
+
self.system.set_thread_id(thread_id)
|
|
268
270
|
|
|
269
271
|
with self.thread_state.select('internal'):
|
|
270
272
|
# if self.tracing:
|
|
@@ -304,6 +306,23 @@ class Patcher:
|
|
|
304
306
|
def sync_types(self, value):
|
|
305
307
|
return wrap_method_descriptors(self.system.sync, "retrace", value)
|
|
306
308
|
|
|
309
|
+
@phase
|
|
310
|
+
def with_state_recursive(self, spec, mod_dict):
|
|
311
|
+
|
|
312
|
+
updates = {}
|
|
313
|
+
|
|
314
|
+
for state,elems in spec.items():
|
|
315
|
+
|
|
316
|
+
def wrap(obj):
|
|
317
|
+
return functional.recursive_wrap(
|
|
318
|
+
callable,
|
|
319
|
+
lambda f: self.thread_state.wrap(state, f),
|
|
320
|
+
obj)
|
|
321
|
+
|
|
322
|
+
updates.update(map_values(wrap, select_keys(elems, mod_dict)))
|
|
323
|
+
|
|
324
|
+
return updates
|
|
325
|
+
|
|
307
326
|
@phase
|
|
308
327
|
def with_state(self, spec, mod_dict):
|
|
309
328
|
|
|
@@ -321,7 +340,9 @@ class Patcher:
|
|
|
321
340
|
def patch_extension_exec(self, exec):
|
|
322
341
|
|
|
323
342
|
def wrapper(module):
|
|
324
|
-
|
|
343
|
+
with self.thread_state.select('internal'):
|
|
344
|
+
res = exec(module)
|
|
345
|
+
|
|
325
346
|
self(module)
|
|
326
347
|
return res
|
|
327
348
|
|
|
@@ -342,7 +363,7 @@ class Patcher:
|
|
|
342
363
|
assert callable(param)
|
|
343
364
|
|
|
344
365
|
return functional.if_then_else(
|
|
345
|
-
test = functional.
|
|
366
|
+
test = functional.sequence(param, self.path_predicate),
|
|
346
367
|
then = func,
|
|
347
368
|
otherwise = self.thread_state.wrap('disabled', func))
|
|
348
369
|
|
|
@@ -356,13 +377,14 @@ class Patcher:
|
|
|
356
377
|
name = parts[0]
|
|
357
378
|
if name in mod_dict:
|
|
358
379
|
value = mod_dict[name]
|
|
359
|
-
|
|
380
|
+
assert not isinstance(value, utils.wrapped_function), f"value for key: {name} is already wrapped"
|
|
360
381
|
if len(parts) == 1:
|
|
361
382
|
updates[name] = resolve(wrapper_name)(value)
|
|
362
383
|
elif len(parts) == 2:
|
|
363
384
|
member = getattr(value, parts[1], None)
|
|
364
385
|
if member:
|
|
365
|
-
|
|
386
|
+
new_value = resolve(wrapper_name)(member)
|
|
387
|
+
setattr(value, parts[1], new_value)
|
|
366
388
|
else:
|
|
367
389
|
raise Exception('TODO')
|
|
368
390
|
|
|
@@ -434,6 +456,23 @@ def env_truthy(key, default=False):
|
|
|
434
456
|
return default
|
|
435
457
|
return value.strip().lower() in ("1", "true", "yes", "on")
|
|
436
458
|
|
|
459
|
+
class ImmutableTypes(set):
|
|
460
|
+
def __init__(self, *args, **kwargs):
|
|
461
|
+
super().__init__(*args, **kwargs)
|
|
462
|
+
|
|
463
|
+
def __contains__(self, item):
|
|
464
|
+
assert isinstance(item, type)
|
|
465
|
+
|
|
466
|
+
if super().__contains__(item):
|
|
467
|
+
return True
|
|
468
|
+
|
|
469
|
+
for elem in self:
|
|
470
|
+
if issubclass(item, elem):
|
|
471
|
+
self.add(item)
|
|
472
|
+
return True
|
|
473
|
+
|
|
474
|
+
return False
|
|
475
|
+
|
|
437
476
|
def install(mode):
|
|
438
477
|
|
|
439
478
|
create_system = None
|
|
@@ -451,7 +490,7 @@ def install(mode):
|
|
|
451
490
|
|
|
452
491
|
thread_state = utils.ThreadState(*states)
|
|
453
492
|
|
|
454
|
-
immutable_types =
|
|
493
|
+
immutable_types = ImmutableTypes()
|
|
455
494
|
|
|
456
495
|
if 'RETRACE_RECORDING_PATH' in os.environ:
|
|
457
496
|
config['recording_path'] = os.environ['RETRACE_RECORDING_PATH']
|
|
@@ -463,6 +502,10 @@ def install(mode):
|
|
|
463
502
|
immutable_types = immutable_types,
|
|
464
503
|
config = config)
|
|
465
504
|
|
|
505
|
+
os.register_at_fork(before = system.before_fork,
|
|
506
|
+
after_in_parent = system.after_fork_in_parent,
|
|
507
|
+
after_in_child = system.after_fork_in_child)
|
|
508
|
+
|
|
466
509
|
patcher = Patcher(thread_state = thread_state,
|
|
467
510
|
config = config,
|
|
468
511
|
system = system,
|
|
@@ -13,6 +13,10 @@ from datetime import datetime
|
|
|
13
13
|
import json
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
|
+
class ThreadSwitch:
|
|
17
|
+
def __init__(self, id):
|
|
18
|
+
self.id = id
|
|
19
|
+
|
|
16
20
|
def write_files(recording_path):
|
|
17
21
|
with open(recording_path / 'env', 'w') as f:
|
|
18
22
|
json.dump(dict(os.environ), f, indent=2)
|
|
@@ -38,9 +42,12 @@ def tracing_level(config):
|
|
|
38
42
|
# level = os.environ.get('RETRACE_DEBUG', config['default_tracing_level'])
|
|
39
43
|
# return config['tracing_levels'].get(level, {})
|
|
40
44
|
|
|
41
|
-
def
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
def merge_config(base, override):
|
|
46
|
+
if isinstance(base, dict) and isinstance(override, dict):
|
|
47
|
+
...
|
|
48
|
+
else:
|
|
49
|
+
return override
|
|
50
|
+
|
|
44
51
|
|
|
45
52
|
def record_system(thread_state, immutable_types, config):
|
|
46
53
|
|
|
@@ -57,7 +64,7 @@ def record_system(thread_state, immutable_types, config):
|
|
|
57
64
|
with open(recording_path / 'tracing_config.json', 'w') as f:
|
|
58
65
|
json.dump(tracing_config, f, indent=2)
|
|
59
66
|
|
|
60
|
-
writer =
|
|
67
|
+
# writer = stream.writer(path = recording_path / 'trace.bin')
|
|
61
68
|
|
|
62
69
|
# os.register_at_fork(
|
|
63
70
|
# # before = self.thread_state.wrap('disabled', self.before_fork),
|
|
@@ -86,43 +93,11 @@ def record_system(thread_state, immutable_types, config):
|
|
|
86
93
|
# self.gc_end()
|
|
87
94
|
# gc.callbacks.append(self.gc_hook)
|
|
88
95
|
|
|
89
|
-
w = writer.handle('TRACE')
|
|
90
|
-
def trace_writer(*args):
|
|
91
|
-
print(f'Trace: {args}')
|
|
92
|
-
w(*args)
|
|
93
|
-
|
|
94
96
|
# print(f'Tracing config: {tracing_config(config)}')
|
|
95
97
|
|
|
96
|
-
tracer = Tracer(tracing_config, writer = trace_writer)
|
|
97
98
|
# tracer = Tracer(config = tracing_config(config), writer = writer.handle('TRACE'))
|
|
98
99
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
# factory.proxy_type = compose(factory.proxy_type, side_effect(...))
|
|
105
|
-
|
|
106
|
-
def on_patched(module_name, updates):
|
|
107
|
-
...
|
|
108
|
-
# for name, value in updates.items():
|
|
109
|
-
# if isinstance(value, type) and \
|
|
110
|
-
# issubclass(value, ExtendingProxy) and \
|
|
111
|
-
# not issubclass(value, InternalProxy):
|
|
112
|
-
|
|
113
|
-
# ref = writer.handle(ExtendingProxySpec(module = module_name, name = name))
|
|
114
|
-
# try:
|
|
115
|
-
# writer.add_type_serializer(cls = value, serializer = functional.constantly(ref))
|
|
116
|
-
# except:
|
|
117
|
-
# pass
|
|
118
|
-
|
|
119
|
-
factory.on_patched = on_patched
|
|
120
|
-
|
|
121
|
-
factory.sync = lambda function: functional.observer(on_call = functional.always(writer.handle('SYNC')), function = function)
|
|
122
|
-
|
|
123
|
-
# factory.set_thread_number = writer.thread_number
|
|
124
|
-
factory.tracer = tracer
|
|
125
|
-
|
|
126
|
-
factory.log = functional.partial(writer, 'LOG')
|
|
127
|
-
|
|
128
|
-
return factory
|
|
100
|
+
return RecordProxySystem(thread_state = thread_state,
|
|
101
|
+
immutable_types = immutable_types,
|
|
102
|
+
tracing_config = tracing_config,
|
|
103
|
+
path = recording_path / 'trace.bin')
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
from retracesoftware.proxy import *
|
|
2
2
|
|
|
3
|
-
import retracesoftware.functional as functional
|
|
4
|
-
import retracesoftware_utils as utils
|
|
5
|
-
import retracesoftware.stream as stream
|
|
6
|
-
from retracesoftware.install.tracer import Tracer
|
|
7
3
|
from retracesoftware.install import globals
|
|
8
4
|
|
|
9
|
-
import os, json, re, glob
|
|
5
|
+
import os, json, re, glob
|
|
10
6
|
from pathlib import Path
|
|
11
7
|
from datetime import datetime
|
|
12
8
|
|
|
@@ -35,15 +31,6 @@ def latest_from_pattern(pattern: str) -> str | None:
|
|
|
35
31
|
latest = max(candidates, key=parse_time)
|
|
36
32
|
return latest
|
|
37
33
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def thread_aware_reader(reader):
|
|
41
|
-
def on_thread_switch():
|
|
42
|
-
...
|
|
43
|
-
|
|
44
|
-
return utils.threadawareproxy(on_thread_switch = on_thread_switch, target = reader)
|
|
45
|
-
|
|
46
|
-
|
|
47
34
|
def replay_system(thread_state, immutable_types, config):
|
|
48
35
|
|
|
49
36
|
recording_path = Path(latest_from_pattern(config['recording_path']))
|
|
@@ -61,91 +48,7 @@ def replay_system(thread_state, immutable_types, config):
|
|
|
61
48
|
with open(recording_path / "tracing_config.json", "r", encoding="utf-8") as f:
|
|
62
49
|
tracing_config = json.load(f)
|
|
63
50
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
# def create_stub_type(proxyspec):
|
|
67
|
-
# if isinstance(proxyspec, ExtendingProxySpec):
|
|
68
|
-
# mod = sys.modules[proxyspec.module]
|
|
69
|
-
# resolved = getattr(mod, proxyspec.name)
|
|
70
|
-
# assert issubclass(resolved, ExtendingProxy)
|
|
71
|
-
|
|
72
|
-
# return resolved
|
|
73
|
-
# # unproxied = resolved.__base__
|
|
74
|
-
# # print(f'base: {unproxied} has_generic_new: {utils.has_generic_new(unproxied)}')
|
|
75
|
-
# # print(f'base: {unproxied} has_generic_alloc: {utils.has_generic_alloc(unproxied)}')
|
|
76
|
-
# # utils.create_stub_object(resolved)
|
|
77
|
-
# # os._exit(1)
|
|
78
|
-
# # return resolved
|
|
79
|
-
|
|
80
|
-
# elif isinstance(proxyspec, WrappingProxySpec):
|
|
81
|
-
# nonlocal handler
|
|
82
|
-
# return proxyspec.create_type(handler)
|
|
83
|
-
# else:
|
|
84
|
-
# print(f'In create_stub_type!!!! {proxyspec}')
|
|
85
|
-
# os._exit(1)
|
|
86
|
-
|
|
87
|
-
# deserializer = functional.compose(pickle.loads, functional.when_instanceof(ProxySpec, create_stub_type))
|
|
88
|
-
|
|
89
|
-
reader = thread_aware_reader(stream.reader(path = recording_path / 'trace.bin'))
|
|
90
|
-
|
|
91
|
-
# reader = utils.threadawareproxy(on_thread_switch = ..., target = reader)
|
|
92
|
-
|
|
93
|
-
def readnext():
|
|
94
|
-
return reader()
|
|
95
|
-
# print(f'read: {obj}')
|
|
96
|
-
# return obj
|
|
97
|
-
|
|
98
|
-
lookup = weakref.WeakKeyDictionary()
|
|
99
|
-
|
|
100
|
-
# debug = debug_level(config)
|
|
101
|
-
|
|
102
|
-
# int_refs = {}
|
|
103
|
-
|
|
104
|
-
def checkpoint(replay):
|
|
105
|
-
...
|
|
106
|
-
|
|
107
|
-
def read_required(required):
|
|
108
|
-
obj = readnext()
|
|
109
|
-
if obj != required:
|
|
110
|
-
print(f'Expected: {required} but got: {obj}')
|
|
111
|
-
for i in range(5):
|
|
112
|
-
readnext()
|
|
113
|
-
|
|
114
|
-
utils.sigtrap(None)
|
|
115
|
-
os._exit(1)
|
|
116
|
-
raise Exception(f'Expected: {required} but got: {obj}')
|
|
117
|
-
|
|
118
|
-
def trace_writer(name, *args):
|
|
119
|
-
print(f'Trace: {name} {args}')
|
|
120
|
-
|
|
121
|
-
read_required('TRACE')
|
|
122
|
-
read_required(name)
|
|
123
|
-
|
|
124
|
-
for arg in args:
|
|
125
|
-
read_required(arg)
|
|
126
|
-
|
|
127
|
-
tracer = Tracer(tracing_config, writer = trace_writer)
|
|
128
|
-
|
|
129
|
-
factory = ReplayProxySystem(thread_state = thread_state,
|
|
51
|
+
return ReplayProxySystem(thread_state = thread_state,
|
|
130
52
|
immutable_types = immutable_types,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
# factory = replaying_proxy_factory(thread_state = thread_state,
|
|
135
|
-
# is_immutable_type = is_immutable_type,
|
|
136
|
-
# tracer = tracer,
|
|
137
|
-
# bind = reader.supply,
|
|
138
|
-
# next = next_result,
|
|
139
|
-
# checkpoint = checkpoint)
|
|
140
|
-
|
|
141
|
-
factory.tracer = tracer
|
|
142
|
-
|
|
143
|
-
def read_sync(): read_required('SYNC')
|
|
144
|
-
|
|
145
|
-
factory.sync = lambda function: functional.observer(on_call = functional.always(read_sync), function = function)
|
|
146
|
-
|
|
147
|
-
# factory.set_thread_number = writer.thread_number
|
|
148
|
-
|
|
149
|
-
factory.log = lambda message: checkpoint({'type': 'log_message', 'message': message})
|
|
150
|
-
|
|
151
|
-
return factory
|
|
53
|
+
tracing_config = tracing_config,
|
|
54
|
+
path = recording_path / 'trace.bin')
|
|
@@ -24,28 +24,30 @@ class Tracer:
|
|
|
24
24
|
|
|
25
25
|
cls = functional.typeof(obj)
|
|
26
26
|
|
|
27
|
+
if issubclass(cls, Proxy):
|
|
28
|
+
return str(cls)
|
|
29
|
+
|
|
27
30
|
if issubclass(cls, (int, str)):
|
|
28
31
|
return obj
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
return 'FOO!!!!'
|
|
33
|
+
return str(cls)
|
|
32
34
|
|
|
33
|
-
if issubclass(cls, Proxy):
|
|
34
|
-
|
|
35
|
+
# if issubclass(cls, Proxy):
|
|
36
|
+
# return f'<Proxy>'
|
|
35
37
|
|
|
36
|
-
if issubclass(cls, types.TracebackType):
|
|
37
|
-
|
|
38
|
+
# if issubclass(cls, types.TracebackType):
|
|
39
|
+
# return '<traceback>'
|
|
38
40
|
|
|
39
|
-
elif issubclass(cls, utils.wrapped_function):
|
|
40
|
-
|
|
41
|
+
# elif issubclass(cls, utils.wrapped_function):
|
|
42
|
+
# return utils.unwrap(obj).__name__
|
|
41
43
|
|
|
42
|
-
elif hasattr(obj, '__module__') and hasattr(obj, '__name__'):
|
|
43
|
-
return f'{obj.__module__}.{obj.__name__}'
|
|
44
|
-
# elif isinstance(obj, type):
|
|
44
|
+
# elif hasattr(obj, '__module__') and hasattr(obj, '__name__'):
|
|
45
45
|
# return f'{obj.__module__}.{obj.__name__}'
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
# # elif isinstance(obj, type):
|
|
47
|
+
# # return f'{obj.__module__}.{obj.__name__}'
|
|
48
|
+
# else:
|
|
49
|
+
# return '<other>'
|
|
50
|
+
# # return f'instance type: {str(self.serialize(type(obj)))}'
|
|
49
51
|
except:
|
|
50
52
|
print("ERROR in tracer serialize!!!!")
|
|
51
53
|
os._exit(1)
|
|
@@ -120,7 +122,7 @@ class Tracer:
|
|
|
120
122
|
writer = functional.partial(self.writer, name)
|
|
121
123
|
|
|
122
124
|
if name in self.config:
|
|
123
|
-
return functional.
|
|
125
|
+
return functional.sequence(func, functional.side_effect(writer))
|
|
124
126
|
else:
|
|
125
127
|
return func
|
|
126
128
|
|
|
@@ -139,6 +141,6 @@ class Tracer:
|
|
|
139
141
|
|
|
140
142
|
def event_after(self, name, func):
|
|
141
143
|
if name in self.config:
|
|
142
|
-
return functional.
|
|
144
|
+
return functional.sequence(func, functional.side_effect(self.event(name)))
|
|
143
145
|
else:
|
|
144
146
|
return func
|
retracesoftware/proxy/gateway.py
CHANGED
|
@@ -1,100 +1,49 @@
|
|
|
1
1
|
import retracesoftware.functional as functional
|
|
2
2
|
import retracesoftware_utils as utils
|
|
3
3
|
|
|
4
|
+
from retracesoftware.proxy.proxytype import ExtendingProxy
|
|
5
|
+
|
|
4
6
|
# from retracesoftware.proxy.proxytype import ExtendingProxy
|
|
5
7
|
|
|
6
|
-
unproxy_execute = functional.mapargs(starting = 1,
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
# unproxy_execute = functional.mapargs(starting = 1,
|
|
9
|
+
# transform = functional.walker(utils.try_unwrap),
|
|
10
|
+
# function = functional.apply)
|
|
9
11
|
|
|
10
|
-
def adapter(
|
|
12
|
+
def adapter(function,
|
|
13
|
+
proxy_input,
|
|
11
14
|
proxy_output,
|
|
12
|
-
function,
|
|
13
15
|
on_call = None,
|
|
14
16
|
on_result = None,
|
|
15
17
|
on_error = None):
|
|
16
18
|
|
|
17
19
|
# function = functional.apply
|
|
18
20
|
|
|
19
|
-
if on_call: function =
|
|
21
|
+
if on_call: function = utils.observer(on_call = on_call, function = function)
|
|
22
|
+
|
|
23
|
+
#functional.observer(on_call = on_call, function = function)
|
|
20
24
|
|
|
21
25
|
function = functional.mapargs(starting = 1, transform = proxy_input, function = function)
|
|
22
26
|
|
|
23
|
-
function = functional.
|
|
27
|
+
function = functional.sequence(function, proxy_output)
|
|
24
28
|
|
|
25
29
|
if on_result or on_error:
|
|
26
|
-
function =
|
|
30
|
+
function = utils.observer(on_result = on_result, on_error = on_error, function = function)
|
|
27
31
|
|
|
28
32
|
return function
|
|
29
33
|
|
|
30
|
-
def adapter_pair(
|
|
31
|
-
proxy_ext,
|
|
32
|
-
int_apply,
|
|
33
|
-
ext_apply,
|
|
34
|
-
tracer,
|
|
35
|
-
on_int_call,
|
|
36
|
-
on_ext_result,
|
|
37
|
-
on_ext_error):
|
|
34
|
+
def adapter_pair(int, ext):
|
|
38
35
|
return (
|
|
39
36
|
adapter(
|
|
40
|
-
function =
|
|
41
|
-
proxy_input =
|
|
42
|
-
proxy_output =
|
|
43
|
-
on_call =
|
|
44
|
-
on_result =
|
|
45
|
-
on_error =
|
|
46
|
-
# on_result = tracer('proxy.ext.result', on_ext_result),
|
|
47
|
-
# on_error = tracer('proxy.ext.error', on_ext_error)),
|
|
37
|
+
function = ext.apply,
|
|
38
|
+
proxy_input = int.proxy,
|
|
39
|
+
proxy_output = ext.proxy,
|
|
40
|
+
on_call = ext.on_call,
|
|
41
|
+
on_result = ext.on_result,
|
|
42
|
+
on_error = ext.on_error),
|
|
48
43
|
adapter(
|
|
49
|
-
function =
|
|
50
|
-
proxy_input =
|
|
51
|
-
proxy_output =
|
|
52
|
-
on_call =
|
|
53
|
-
on_result =
|
|
54
|
-
on_error =
|
|
55
|
-
|
|
56
|
-
def proxy(proxytype):
|
|
57
|
-
return functional.selfapply(functional.compose(functional.typeof, proxytype))
|
|
58
|
-
|
|
59
|
-
def maybe_proxy(proxytype):
|
|
60
|
-
return functional.if_then_else(
|
|
61
|
-
functional.isinstanceof(utils.Wrapped),
|
|
62
|
-
utils.unwrap,
|
|
63
|
-
proxy(functional.memoize_one_arg(proxytype)))
|
|
64
|
-
|
|
65
|
-
def gateway_pair(thread_state,
|
|
66
|
-
tracer,
|
|
67
|
-
immutable_types,
|
|
68
|
-
int_proxytype,
|
|
69
|
-
ext_proxytype,
|
|
70
|
-
int_apply = functional.apply,
|
|
71
|
-
ext_apply = functional.apply,
|
|
72
|
-
on_int_call = None,
|
|
73
|
-
on_ext_result = None,
|
|
74
|
-
on_ext_error = None):
|
|
75
|
-
|
|
76
|
-
def is_immutable_type(cls):
|
|
77
|
-
return issubclass(cls, tuple(immutable_types))
|
|
78
|
-
|
|
79
|
-
is_immutable = functional.sequence(functional.typeof, functional.memoize_one_arg(is_immutable_type))
|
|
80
|
-
|
|
81
|
-
def create_proxier(proxytype):
|
|
82
|
-
return functional.walker(functional.when_not(is_immutable, maybe_proxy(proxytype)))
|
|
83
|
-
|
|
84
|
-
int_to_ext_dispatch = thread_state.dispatch(tracer('proxy.int.disabled.event', unproxy_execute))
|
|
85
|
-
ext_to_int_dispatch = thread_state.dispatch(tracer('proxy.ext.disabled.event', unproxy_execute))
|
|
86
|
-
|
|
87
|
-
int_to_ext, ext_to_int = adapter_pair(
|
|
88
|
-
proxy_int = create_proxier(int_proxytype(ext_to_int_dispatch)),
|
|
89
|
-
proxy_ext = create_proxier(ext_proxytype(int_to_ext_dispatch)),
|
|
90
|
-
int_apply = thread_state.wrap(desired_state = 'internal', function = int_apply),
|
|
91
|
-
ext_apply = thread_state.wrap(desired_state = 'external', function = ext_apply),
|
|
92
|
-
tracer = tracer,
|
|
93
|
-
on_int_call = on_int_call,
|
|
94
|
-
on_ext_result = on_ext_result,
|
|
95
|
-
on_ext_error = on_ext_error)
|
|
96
|
-
|
|
97
|
-
thread_state.set_dispatch(int_to_ext_dispatch, external = functional.apply, internal = tracer('proxy.int_to_ext.stack', int_to_ext))
|
|
98
|
-
thread_state.set_dispatch(ext_to_int_dispatch, internal = functional.apply, external = tracer('proxy.ext_to_int.wrap', ext_to_int))
|
|
99
|
-
|
|
100
|
-
return (int_to_ext_dispatch, ext_to_int_dispatch)
|
|
44
|
+
function = int.apply,
|
|
45
|
+
proxy_input = ext.proxy,
|
|
46
|
+
proxy_output = int.proxy,
|
|
47
|
+
on_call = int.on_call,
|
|
48
|
+
on_result = int.on_result,
|
|
49
|
+
on_error = int.on_error))
|