retracesoftware-proxy 0.2.18__py3-none-any.whl → 0.2.19__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/__main__.py +90 -15
- retracesoftware/autoenable.py +4 -0
- retracesoftware/install/patchfindspec.py +14 -108
- retracesoftware/run.py +4 -6
- {retracesoftware_proxy-0.2.18.dist-info → retracesoftware_proxy-0.2.19.dist-info}/METADATA +1 -1
- {retracesoftware_proxy-0.2.18.dist-info → retracesoftware_proxy-0.2.19.dist-info}/RECORD +8 -16
- retracesoftware/install/install.py +0 -142
- retracesoftware/install/modulepatcher.py +0 -506
- retracesoftware/install/phases.py +0 -338
- retracesoftware/install/predicate.py +0 -92
- retracesoftware/install/record.py +0 -174
- retracesoftware/install/references.py +0 -66
- retracesoftware/install/replay.py +0 -102
- retracesoftware/replay.py +0 -105
- {retracesoftware_proxy-0.2.18.dist-info → retracesoftware_proxy-0.2.19.dist-info}/WHEEL +0 -0
- {retracesoftware_proxy-0.2.18.dist-info → retracesoftware_proxy-0.2.19.dist-info}/top_level.txt +0 -0
retracesoftware/__main__.py
CHANGED
|
@@ -33,6 +33,24 @@ def dump_as_json(path, obj):
|
|
|
33
33
|
with open(path, 'w') as f:
|
|
34
34
|
json.dump(obj, f, indent=2)
|
|
35
35
|
|
|
36
|
+
def load_env(file):
|
|
37
|
+
"""Load a .env file into a dict."""
|
|
38
|
+
env = {}
|
|
39
|
+
with open(file, 'r') as f:
|
|
40
|
+
for line in f:
|
|
41
|
+
line = line.strip()
|
|
42
|
+
if not line or line.startswith('#'):
|
|
43
|
+
continue
|
|
44
|
+
if '=' in line:
|
|
45
|
+
key, value = line.split('=', 1)
|
|
46
|
+
# Remove surrounding quotes if present
|
|
47
|
+
if value.startswith('"') and value.endswith('"'):
|
|
48
|
+
value = value[1:-1]
|
|
49
|
+
# Unescape
|
|
50
|
+
value = value.replace('\\n', '\n').replace('\\"', '"').replace('\\\\', '\\')
|
|
51
|
+
env[key] = value
|
|
52
|
+
return env
|
|
53
|
+
|
|
36
54
|
vscode_workspace = {
|
|
37
55
|
"folders": [{ 'path': '.' }],
|
|
38
56
|
"settings": {
|
|
@@ -74,6 +92,28 @@ def file_md5(path):
|
|
|
74
92
|
def checksum(path):
|
|
75
93
|
return file_md5(path) if path.is_file() else {entry.name: checksum(entry) for entry in path.iterdir() if entry.name != '__pycache__'}
|
|
76
94
|
|
|
95
|
+
def diff_dicts(recorded, current, path=""):
|
|
96
|
+
"""Recursively diff two dicts, returning list of differences."""
|
|
97
|
+
diffs = []
|
|
98
|
+
all_keys = set(recorded.keys()) | set(current.keys())
|
|
99
|
+
|
|
100
|
+
for key in sorted(all_keys):
|
|
101
|
+
key_path = f"{path}.{key}" if path else key
|
|
102
|
+
|
|
103
|
+
if key not in recorded:
|
|
104
|
+
diffs.append(f" + {key_path}: (new in current)")
|
|
105
|
+
elif key not in current:
|
|
106
|
+
diffs.append(f" - {key_path}: (missing in current)")
|
|
107
|
+
elif recorded[key] != current[key]:
|
|
108
|
+
if isinstance(recorded[key], dict) and isinstance(current[key], dict):
|
|
109
|
+
diffs.extend(diff_dicts(recorded[key], current[key], key_path))
|
|
110
|
+
else:
|
|
111
|
+
diffs.append(f" ! {key_path}:")
|
|
112
|
+
diffs.append(f" recorded: {recorded[key][:16]}..." if isinstance(recorded[key], str) and len(recorded[key]) > 16 else f" recorded: {recorded[key]}")
|
|
113
|
+
diffs.append(f" current: {current[key][:16]}..." if isinstance(current[key], str) and len(current[key]) > 16 else f" current: {current[key]}")
|
|
114
|
+
|
|
115
|
+
return diffs
|
|
116
|
+
|
|
77
117
|
def retrace_extension_paths():
|
|
78
118
|
names = ['_retracesoftware_utils_release', '_retracesoftware_utils_debug',
|
|
79
119
|
'_retracesoftware_functional_release', '_retracesoftware_functional_debug',
|
|
@@ -88,36 +128,55 @@ def retrace_module_paths():
|
|
|
88
128
|
def checksums():
|
|
89
129
|
return {name: checksum(path) for name, path in retrace_module_paths().items()}
|
|
90
130
|
|
|
131
|
+
def run_create_tracedir_cmd(create_tracedir_cmd, path):
|
|
132
|
+
import subprocess
|
|
133
|
+
result = subprocess.run([create_tracedir_cmd, str(path)], capture_output=True, text=True)
|
|
134
|
+
if result.returncode != 0:
|
|
135
|
+
msg = f"create_tracedir_cmd '{create_tracedir_cmd}' failed with exit code {result.returncode}"
|
|
136
|
+
if result.stdout:
|
|
137
|
+
msg += f"\nstdout: {result.stdout}"
|
|
138
|
+
if result.stderr:
|
|
139
|
+
msg += f"\nstderr: {result.stderr}"
|
|
140
|
+
raise ConfigurationError(msg)
|
|
141
|
+
if not path.exists():
|
|
142
|
+
raise ConfigurationError(f"create_tracedir_cmd '{create_tracedir_cmd}' exited successfully but directory '{path}' does not exist")
|
|
143
|
+
|
|
91
144
|
def record(options, args):
|
|
92
145
|
|
|
93
146
|
if options.verbose:
|
|
94
147
|
print(f"Retrace enabled, recording to {options.recording}", file=sys.stderr)
|
|
95
148
|
|
|
96
149
|
path = Path(expand_recording_path(options.recording))
|
|
97
|
-
|
|
98
|
-
|
|
150
|
+
|
|
151
|
+
# Create trace directory via custom command or default mkdir
|
|
152
|
+
if options.create_tracedir_cmd:
|
|
153
|
+
run_create_tracedir_cmd(options.create_tracedir_cmd, path)
|
|
154
|
+
else:
|
|
155
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
99
156
|
|
|
100
157
|
from retracesoftware.install import edgecases
|
|
101
158
|
edgecases.recording_path = path
|
|
102
159
|
|
|
103
160
|
# write various recording files to directory
|
|
161
|
+
path_info = stream.get_path_info()
|
|
104
162
|
dump_as_json(path / 'settings.json', {
|
|
105
163
|
'argv': args,
|
|
106
164
|
'executable': sys.executable,
|
|
107
165
|
'magic_markers': options.magic_markers,
|
|
108
166
|
'trace_inputs': options.trace_inputs,
|
|
109
167
|
'trace_shutdown': options.trace_shutdown,
|
|
110
|
-
'env': dict(os.environ),
|
|
111
168
|
'python_version': sys.version,
|
|
112
|
-
'
|
|
169
|
+
'cwd': path_info['cwd'],
|
|
170
|
+
'sys_path': path_info['sys_path'],
|
|
113
171
|
})
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
172
|
+
dump_as_json(path / 'md5_checksums.json', checksums())
|
|
173
|
+
|
|
174
|
+
# Write env to standard .env file
|
|
175
|
+
with open(path / '.env', 'w') as f:
|
|
176
|
+
for key, value in os.environ.items():
|
|
177
|
+
# Escape newlines and quotes for .env format
|
|
178
|
+
escaped = value.replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"')
|
|
179
|
+
f.write(f'{key}="{escaped}"\n')
|
|
121
180
|
|
|
122
181
|
# create a .venv directory in the recording path
|
|
123
182
|
# venv_path = path / '.venv'
|
|
@@ -178,24 +237,32 @@ def record(options, args):
|
|
|
178
237
|
gc.callbacks.remove(system.on_gc_event)
|
|
179
238
|
|
|
180
239
|
def replay(args):
|
|
181
|
-
path
|
|
240
|
+
# Resolve path before any chdir
|
|
241
|
+
path = Path(args.recording).resolve()
|
|
182
242
|
|
|
183
243
|
if not path.exists():
|
|
184
244
|
raise RecordingNotFoundError(f"Recording path: {path} does not exist")
|
|
185
245
|
|
|
186
246
|
settings = load_json(path / "settings.json")
|
|
247
|
+
recorded_checksums = load_json(path / "md5_checksums.json")
|
|
187
248
|
|
|
188
|
-
|
|
189
|
-
|
|
249
|
+
current_checksums = checksums()
|
|
250
|
+
if recorded_checksums != current_checksums:
|
|
251
|
+
diffs = diff_dicts(recorded_checksums, current_checksums)
|
|
252
|
+
diff_str = "\n".join(diffs) if diffs else "(no differences found in structure)"
|
|
253
|
+
raise VersionMismatchError(f"Checksums for Retrace do not match:\n{diff_str}")
|
|
190
254
|
|
|
191
255
|
if settings['python_version'] != sys.version:
|
|
192
256
|
raise VersionMismatchError("Python version does not match, cannot run replay with different version of Python to record")
|
|
193
257
|
|
|
194
|
-
os.environ.update(
|
|
258
|
+
os.environ.update(load_env(path / '.env'))
|
|
195
259
|
|
|
196
260
|
if sys.executable != settings['executable']:
|
|
197
261
|
raise ConfigurationError(f"Stopping replay as current python executable: {sys.executable} is not what was used for record: {settings['executable']}")
|
|
198
262
|
|
|
263
|
+
# Change to recorded cwd - replay from same directory as recording
|
|
264
|
+
os.chdir(settings['cwd'])
|
|
265
|
+
|
|
199
266
|
thread_state = utils.ThreadState(*thread_states)
|
|
200
267
|
|
|
201
268
|
# with stream.reader(path = path / 'trace.bin',
|
|
@@ -226,6 +293,7 @@ def replay(args):
|
|
|
226
293
|
gc.collect()
|
|
227
294
|
gc.disable()
|
|
228
295
|
|
|
296
|
+
# Use original argv - scripts are now relative to cwd (recording/run)
|
|
229
297
|
run_with_retrace(system, settings['argv'], settings['trace_shutdown'])
|
|
230
298
|
|
|
231
299
|
def main():
|
|
@@ -272,6 +340,13 @@ def main():
|
|
|
272
340
|
help='Whether to write call parameters, used for debugging'
|
|
273
341
|
)
|
|
274
342
|
|
|
343
|
+
parser.add_argument(
|
|
344
|
+
'--create_tracedir_cmd',
|
|
345
|
+
type=str,
|
|
346
|
+
default=None,
|
|
347
|
+
help='Command to create trace directory (receives directory path as argument)'
|
|
348
|
+
)
|
|
349
|
+
|
|
275
350
|
parser.add_argument('rest', nargs = argparse.REMAINDER, help='target application and arguments')
|
|
276
351
|
|
|
277
352
|
args = parser.parse_args()
|
retracesoftware/autoenable.py
CHANGED
|
@@ -51,6 +51,10 @@ else:
|
|
|
51
51
|
if is_true('RETRACE_TRACE_INPUTS'):
|
|
52
52
|
new_argv.append('--trace_inputs')
|
|
53
53
|
|
|
54
|
+
if 'RETRACE_CREATE_TRACEDIR_CMD' in os.environ:
|
|
55
|
+
new_argv.append('--create_tracedir_cmd')
|
|
56
|
+
new_argv.append(os.environ['RETRACE_CREATE_TRACEDIR_CMD'])
|
|
57
|
+
|
|
54
58
|
new_argv.append('--')
|
|
55
59
|
new_argv.extend(sys.orig_argv[1:])
|
|
56
60
|
|
|
@@ -1,117 +1,23 @@
|
|
|
1
|
-
from functools import wraps
|
|
2
1
|
import os
|
|
3
2
|
from pathlib import Path
|
|
4
|
-
import shutil
|
|
5
|
-
import sys
|
|
6
3
|
|
|
7
|
-
# Set to track
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def get_relative_path(module_path: Path, sys_path: list) -> Path:
|
|
11
|
-
"""Compute the relative path of module_path relative to sys.path entries."""
|
|
12
|
-
module_path = module_path.resolve()
|
|
13
|
-
for base in sys_path:
|
|
14
|
-
base_path = Path(base).resolve()
|
|
15
|
-
try:
|
|
16
|
-
if module_path.is_relative_to(base_path):
|
|
17
|
-
return module_path.relative_to(base_path)
|
|
18
|
-
except ValueError:
|
|
19
|
-
continue
|
|
20
|
-
return Path(module_path.name)
|
|
4
|
+
# Set to track logged modules (avoid duplicates)
|
|
5
|
+
logged_modules = set()
|
|
21
6
|
|
|
22
7
|
class patch_find_spec:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
8
|
+
"""
|
|
9
|
+
Hook that logs accessed module file paths to a file.
|
|
10
|
+
One absolute path per line.
|
|
11
|
+
"""
|
|
12
|
+
def __init__(self, output_file):
|
|
13
|
+
self.output_file = output_file
|
|
27
14
|
|
|
28
15
|
def __call__(self, spec):
|
|
29
16
|
if spec is not None and spec.origin and spec.origin != "built-in" and os.path.isfile(spec.origin):
|
|
30
17
|
module_name = spec.name
|
|
31
|
-
if module_name not in
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
dest_path = self.run_path / module_path.relative_to(self.cwd)
|
|
38
|
-
elif self.python_path:
|
|
39
|
-
relative_path = get_relative_path(module_path, sys.path)
|
|
40
|
-
dest_path = self.python_path / relative_path
|
|
41
|
-
|
|
42
|
-
if dest_path:
|
|
43
|
-
dest_path.parent.mkdir(parents=True, exist_ok=True)
|
|
44
|
-
shutil.copy2(module_path, dest_path)
|
|
45
|
-
copied_modules.add(module_name)
|
|
46
|
-
|
|
47
|
-
# def __call__(self, fullname, path, target=None):
|
|
48
|
-
# spec = self.original_find_spec(fullname, path, target)
|
|
49
|
-
|
|
50
|
-
# if spec is not None and spec.origin and spec.origin != "built-in" and os.path.isfile(spec.origin):
|
|
51
|
-
# module_name = spec.name
|
|
52
|
-
# if module_name not in copied_modules:
|
|
53
|
-
# module_path = Path(spec.origin)
|
|
54
|
-
|
|
55
|
-
# dest_path = None
|
|
56
|
-
|
|
57
|
-
# if module_path.is_relative_to(self.cwd):
|
|
58
|
-
# dest_path = self.run_path / module_path.relative_to(self.cwd)
|
|
59
|
-
# elif self.python_path:
|
|
60
|
-
# relative_path = get_relative_path(module_path, sys.path)
|
|
61
|
-
# dest_path = self.python_path / relative_path
|
|
62
|
-
|
|
63
|
-
# if dest_path:
|
|
64
|
-
# dest_path.parent.mkdir(parents=True, exist_ok=True)
|
|
65
|
-
# shutil.copy2(module_path, dest_path)
|
|
66
|
-
# copied_modules.add(module_name)
|
|
67
|
-
|
|
68
|
-
# return spec
|
|
69
|
-
|
|
70
|
-
# def patch_find_spec(cwd, run_path, python_path, original_find_spec):
|
|
71
|
-
# """Create a patched version of find_spec that copies .py files."""
|
|
72
|
-
# @wraps(original_find_spec)
|
|
73
|
-
# def patched_find_spec(fullname, path, target=None):
|
|
74
|
-
# spec = original_find_spec(fullname, path, target)
|
|
75
|
-
|
|
76
|
-
# if spec is not None and spec.origin and spec.origin != "built-in" and os.path.isfile(spec.origin):
|
|
77
|
-
# module_name = spec.name
|
|
78
|
-
# if module_name not in copied_modules:
|
|
79
|
-
# module_path = Path(spec.origin)
|
|
80
|
-
|
|
81
|
-
# dest_path = None
|
|
82
|
-
|
|
83
|
-
# if module_path.is_relative_to(cwd):
|
|
84
|
-
# dest_path = run_path / module_path.relative_to(cwd)
|
|
85
|
-
# elif python_path:
|
|
86
|
-
# relative_path = get_relative_path(module_path, sys.path)
|
|
87
|
-
# dest_path = python_path / relative_path
|
|
88
|
-
|
|
89
|
-
# if dest_path:
|
|
90
|
-
# dest_path.parent.mkdir(parents=True, exist_ok=True)
|
|
91
|
-
# shutil.copy2(module_path, dest_path)
|
|
92
|
-
# copied_modules.add(module_name)
|
|
93
|
-
|
|
94
|
-
# # elif python_path:
|
|
95
|
-
# # relative_path = get_relative_path(module_path, sys.path)
|
|
96
|
-
# # dest_path = python_path / relative_path
|
|
97
|
-
# # dest_path.parent.mkdir(parents=True, exist_ok=True)
|
|
98
|
-
|
|
99
|
-
# # shutil.copy2(module_path, dest_path)
|
|
100
|
-
# # copied_modules.add(module_name)
|
|
101
|
-
|
|
102
|
-
# # if module_path.suffix == '.py':
|
|
103
|
-
# # elif module_path.suffix == '.py':
|
|
104
|
-
# # relative_path = get_relative_path(module_path, sys.path)
|
|
105
|
-
# # dest_path = path / relative_path
|
|
106
|
-
# # dest_path.parent.mkdir(parents=True, exist_ok=True)
|
|
107
|
-
# # try:
|
|
108
|
-
# # shutil.copy2(module_path, dest_path)
|
|
109
|
-
# # print(f"Copied {module_path} to {dest_path} (relative: {relative_path})")
|
|
110
|
-
# # copied_modules.add(module_name)
|
|
111
|
-
# # except Exception as e:
|
|
112
|
-
# # print(f"Failed to copy {module_path}: {e}")
|
|
113
|
-
# # else:
|
|
114
|
-
# # print(f"Skipped copying {module_path} (not a .py file)")
|
|
115
|
-
|
|
116
|
-
# return spec
|
|
117
|
-
# return patched_find_spec
|
|
18
|
+
if module_name not in logged_modules:
|
|
19
|
+
# Write absolute path to output file
|
|
20
|
+
abs_path = os.path.realpath(spec.origin)
|
|
21
|
+
self.output_file.write(abs_path + '\n')
|
|
22
|
+
self.output_file.flush()
|
|
23
|
+
logged_modules.add(module_name)
|
retracesoftware/run.py
CHANGED
|
@@ -133,13 +133,11 @@ def run_python_command(argv):
|
|
|
133
133
|
print(f"Error: Not a Python script: {script_path}", file=sys.stderr)
|
|
134
134
|
return 1
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
# Use the path as given (relative or absolute) to preserve cwd-relative paths
|
|
137
|
+
# for stack trace normalization during record/replay
|
|
138
|
+
sys.argv = [script_path] + script_args
|
|
138
139
|
|
|
139
|
-
|
|
140
|
-
os.chdir(path.parent)
|
|
141
|
-
|
|
142
|
-
runpy.run_path(full_path, run_name="__main__")
|
|
140
|
+
runpy.run_path(script_path, run_name="__main__")
|
|
143
141
|
return 0
|
|
144
142
|
|
|
145
143
|
except ModuleNotFoundError:
|
|
@@ -1,29 +1,21 @@
|
|
|
1
1
|
retracesoftware/__init__.py,sha256=jQw15XBREFZX93BHpvREfc-hQmMUHYtO6gO-qZmdW1o,482
|
|
2
|
-
retracesoftware/__main__.py,sha256=
|
|
3
|
-
retracesoftware/autoenable.py,sha256=
|
|
2
|
+
retracesoftware/__main__.py,sha256=oTpF0ev2yJrrhROIJroT5UqJPRQWdBYrfUWwctOywrY,13375
|
|
3
|
+
retracesoftware/autoenable.py,sha256=LVt6KfMIIScV5b4dsXP_DHlrRm1i5iIGfVauup61YtE,2001
|
|
4
4
|
retracesoftware/config.json,sha256=Cw5YZCfTo8GLmtbTH2LYwST7wNe7925DAwsTtRIGhBE,3817
|
|
5
5
|
retracesoftware/config.yaml,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
retracesoftware/exceptions.py,sha256=8jT4tJrRRRh3nRERrsqaKgIJ3itb-VYumpa9UcoxF9o,647
|
|
7
7
|
retracesoftware/modules.toml,sha256=Xu8B6H9HMM4ZaxiEPy9FGcMHBHsyBD1qR0weUXgau4Y,14613
|
|
8
8
|
retracesoftware/preload.txt,sha256=8Wm8OWnDfEp9X4FN-yNQYLfZk_h36kMgHA_QUw_7Hbs,2370
|
|
9
|
-
retracesoftware/replay.py,sha256=FEEenvRUeULmv-Zzb6g7Ub85oGonmvMT4ATE4q0yWqI,3676
|
|
10
9
|
retracesoftware/retrace.pth,sha256=umCRQITpnqAp1N-svTCi4lJxOo7GihDrLtO3pA2wwgM,35
|
|
11
|
-
retracesoftware/run.py,sha256=
|
|
10
|
+
retracesoftware/run.py,sha256=h0t4ZO9-JHXZ4mjgwXNGSGL1UFxh7pKdr_wvokkJ-PY,12253
|
|
12
11
|
retracesoftware/stackdifference.py,sha256=nM9r5YHMCNQcrWozMjUX4ZTrZL5U0rQChSGzpiXy_DU,4466
|
|
13
12
|
retracesoftware/install/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
13
|
retracesoftware/install/config.py,sha256=AnSlHI3lWQrPUg0fOS26PqXiq1hJSy56SwrNL8mbAG8,1546
|
|
15
14
|
retracesoftware/install/edgecases.py,sha256=Ry3BETJ4Hmqpw9xXTlNeUgBL9q-sumaazqjmzZBRtD4,7265
|
|
16
15
|
retracesoftware/install/globals.py,sha256=F8XvIoZQQ10gSRalk30dvdKllxlwxkaggYY6FogLDxY,510
|
|
17
|
-
retracesoftware/install/install.py,sha256=fP7E9OWiQd1Dgi4jL8rL9T5SXW5AL62BM3NEW61fisw,4969
|
|
18
|
-
retracesoftware/install/modulepatcher.py,sha256=yBXrbfr5J9JQXCVbcNpDm8H17bsPbL6DY54bImFjBKM,16715
|
|
19
16
|
retracesoftware/install/patcher.py,sha256=Z98ux8SDw53wyRKCevOT-tPOFcwcM3KH1dyR7Tg_TJ4,5859
|
|
20
|
-
retracesoftware/install/patchfindspec.py,sha256=
|
|
21
|
-
retracesoftware/install/phases.py,sha256=OWaw86xzC924tdIA9C-12Qdr3sCx67hEOn-Ih9FM--4,9359
|
|
22
|
-
retracesoftware/install/predicate.py,sha256=tX7NQc0rGkyyHYO3mduYHcJHbw1wczT53m_Dpkzo6do,2679
|
|
23
|
-
retracesoftware/install/record.py,sha256=0iV9zMnO7aMUx8HDkni1eeopC3lWR5J6sDwxY6bgeX0,5861
|
|
24
|
-
retracesoftware/install/references.py,sha256=A-G651IDOfuo00MkbAdpbIQh_15ChvJ7uAVTSmE6zd4,1721
|
|
17
|
+
retracesoftware/install/patchfindspec.py,sha256=oOjmsVsTSfex3ined3kcZ4iLh0emsx2Q5dB2_YVd62I,792
|
|
25
18
|
retracesoftware/install/replace.py,sha256=FYiSJtNrXEhl-H6M5tJm0kbliBA0sZdxE0306pr-YQg,872
|
|
26
|
-
retracesoftware/install/replay.py,sha256=bB2eMpIP2vXZzeJ98jtlkGSE1DEYWk3olUbiBQcdVj0,3539
|
|
27
19
|
retracesoftware/install/tracer.py,sha256=VfjghYepk2M2DLy1nEYgHcaCXo0616OVMxxx3A3dNhM,9363
|
|
28
20
|
retracesoftware/install/typeutils.py,sha256=GiYDPsKGBtp0_1E71AJm16u03L8eSoR1piz3yvOgAhk,2253
|
|
29
21
|
retracesoftware/proxy/__init__.py,sha256=ntIyqKhBRkKEkcW_oOPodikh-mxYl8OXRnSaj-9-Xwc,178
|
|
@@ -39,7 +31,7 @@ retracesoftware/proxy/serializer.py,sha256=S5yhHoP2iYaXBY7Jr8Ei630Z31521x0IO6Deu
|
|
|
39
31
|
retracesoftware/proxy/startthread.py,sha256=YKUcOSjA-9_5ZsDHhyP0fXJSP3RWDKV-ajX-I0SI-bU,1270
|
|
40
32
|
retracesoftware/proxy/stubfactory.py,sha256=fyQtCZnkXvLaTlGcxE0Lx8od09ZOgnPWPn0YvNFfVeQ,6219
|
|
41
33
|
retracesoftware/proxy/thread.py,sha256=AAj6BL4kw-KMHX4fV66LuePQbTYvPmI3IY8ZwV069nI,3073
|
|
42
|
-
retracesoftware_proxy-0.2.
|
|
43
|
-
retracesoftware_proxy-0.2.
|
|
44
|
-
retracesoftware_proxy-0.2.
|
|
45
|
-
retracesoftware_proxy-0.2.
|
|
34
|
+
retracesoftware_proxy-0.2.19.dist-info/METADATA,sha256=sUiA5tyrwKB5INk9509ZpTYDjFSbR_2x60bPC9cIOpY,227
|
|
35
|
+
retracesoftware_proxy-0.2.19.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
36
|
+
retracesoftware_proxy-0.2.19.dist-info/top_level.txt,sha256=hYHsR6txLidmqvjBMITpIHvmJJbmoCAgr76-IpZPRz8,16
|
|
37
|
+
retracesoftware_proxy-0.2.19.dist-info/RECORD,,
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import retracesoftware.functional as functional
|
|
4
|
-
import retracesoftware.utils as utils
|
|
5
|
-
|
|
6
|
-
# from retracesoftware_functional import mapargs, walker, first_arg, if_then_else, compose, observer, anyargs, memoize_one_arg, side_effect, partial, threadwatcher, firstof, notinstance_test, instance_test,typeof, isinstanceof, always
|
|
7
|
-
# from retracesoftware.proxy.proxy import ProxyFactory, InternalProxy, ProxySpec, WrappingProxySpec, ExtendingProxySpec, ExtendingProxy
|
|
8
|
-
from retracesoftware_proxy import thread_id
|
|
9
|
-
# from retracesoftware_stream import ObjectWriter, ObjectReader
|
|
10
|
-
import retracesoftware.stream as stream
|
|
11
|
-
|
|
12
|
-
# from retracesoftware_utils import visitor
|
|
13
|
-
from retracesoftware.install.tracer import Tracer
|
|
14
|
-
from retracesoftware.proxy.record import RecordProxySystem
|
|
15
|
-
from retracesoftware.proxy.replay import ReplayProxySystem
|
|
16
|
-
from datetime import datetime
|
|
17
|
-
|
|
18
|
-
import os
|
|
19
|
-
import sys
|
|
20
|
-
import json
|
|
21
|
-
import enum
|
|
22
|
-
import _thread
|
|
23
|
-
import pickle
|
|
24
|
-
import weakref
|
|
25
|
-
import types
|
|
26
|
-
from pathlib import Path
|
|
27
|
-
import glob, os
|
|
28
|
-
import re
|
|
29
|
-
|
|
30
|
-
# from retracesoftware_proxy import *
|
|
31
|
-
# from retracesoftware_utils import *
|
|
32
|
-
# from retracesoftware.proxy import references
|
|
33
|
-
from retracesoftware.install import patcher
|
|
34
|
-
from retracesoftware.install.config import load_config
|
|
35
|
-
# from retracesoftware.proxy.immutabletypes import ImmutableTypes
|
|
36
|
-
# from retracesoftware.proxy import edgecases
|
|
37
|
-
from retracesoftware.install import globals
|
|
38
|
-
# from retracesoftware.proxy.record import RecordProxyFactory
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
class DebugWriter:
|
|
42
|
-
__slot__ = ['checkpoint']
|
|
43
|
-
|
|
44
|
-
def __init__(self, checkpoint):
|
|
45
|
-
self.checkpoint = checkpoint
|
|
46
|
-
|
|
47
|
-
def write_call(self, func, *args, **kwargs):
|
|
48
|
-
self.checkpoint({'type': 'call', 'func': ...})
|
|
49
|
-
|
|
50
|
-
def write_result(self, res):
|
|
51
|
-
self.checkpoint({'type': 'result', 'result': res})
|
|
52
|
-
|
|
53
|
-
def write_error(self, *args):
|
|
54
|
-
self.checkpoint({'type': 'error', 'error': tuple(args)})
|
|
55
|
-
|
|
56
|
-
class MethodDescriptor:
|
|
57
|
-
def __init__(self, descriptor):
|
|
58
|
-
self.cls = descriptor.__objclass__
|
|
59
|
-
self.name = descriptor.name
|
|
60
|
-
|
|
61
|
-
def once(*args): return functional.memoize_one_arg(functional.sequence(*args))
|
|
62
|
-
|
|
63
|
-
any = functional.firstof
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def compose(*args):
|
|
67
|
-
new_args = [item for item in args if item is not None]
|
|
68
|
-
if len(new_args) == 0:
|
|
69
|
-
raise Exception('TODO')
|
|
70
|
-
elif len(new_args) == 1:
|
|
71
|
-
return new_args[0]
|
|
72
|
-
else:
|
|
73
|
-
return functional.compose(*new_args)
|
|
74
|
-
|
|
75
|
-
class SerializedWrappedFunction:
|
|
76
|
-
def __init__(self, func):
|
|
77
|
-
if hasattr(func, '__objclass__'):
|
|
78
|
-
self.cls = func.__objclass__
|
|
79
|
-
elif hasattr(func, '__module__'):
|
|
80
|
-
self.module = func.__module__
|
|
81
|
-
|
|
82
|
-
if hasattr(func, '__name__'):
|
|
83
|
-
self.name = func.__name__
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def replaying_proxy_factory(thread_state, is_immutable_type, tracer, next, bind, checkpoint):
|
|
87
|
-
|
|
88
|
-
# def on_new_ext_proxytype(proxytype):
|
|
89
|
-
# assert not issubclass(proxytype, DynamicProxy)
|
|
90
|
-
# bind(proxytype)
|
|
91
|
-
# writer.add_type_serializer(cls = proxytype, serializer = functional.typeof)
|
|
92
|
-
|
|
93
|
-
# bind_new_int_proxy = functional.if_then_else(functional.isinstanceof(InternalProxy), functional.memoize_one_arg(bind), None)
|
|
94
|
-
|
|
95
|
-
# on_ext_call = utils.visitor(from_arg = 1, function = bind_new_int_proxy)
|
|
96
|
-
|
|
97
|
-
def wrap_int_call(handler):
|
|
98
|
-
return functional.observer(
|
|
99
|
-
on_call = tracer('proxy.int.call'),
|
|
100
|
-
on_result = tracer('proxy.int.result'),
|
|
101
|
-
on_error = tracer('proxy.int.error'),
|
|
102
|
-
function = handler)
|
|
103
|
-
|
|
104
|
-
# def is_stub_type(obj):
|
|
105
|
-
# return type(obj) == type and issubclass(obj, (WrappingProxy, ExtendingProxy))
|
|
106
|
-
|
|
107
|
-
def is_stub_type(obj):
|
|
108
|
-
return type(obj) == type
|
|
109
|
-
|
|
110
|
-
create_stubs = functional.walker(functional.when(is_stub_type, utils.create_stub_object))
|
|
111
|
-
# create_stubs = functional.walker(functional.when(is_stub_type, utils.create_stub_object))
|
|
112
|
-
|
|
113
|
-
def wrap_ext_call(handler):
|
|
114
|
-
return functional.observer(
|
|
115
|
-
on_call = tracer('proxy.ext.call'),
|
|
116
|
-
on_result = tracer('proxy.ext.result'),
|
|
117
|
-
on_error = tracer('proxy.ext.error'),
|
|
118
|
-
function = functional.sequence(functional.always(next), create_stubs))
|
|
119
|
-
|
|
120
|
-
return ProxyFactory(thread_state = thread_state,
|
|
121
|
-
is_immutable_type = is_immutable_type,
|
|
122
|
-
tracer = tracer,
|
|
123
|
-
on_new_int_proxy = bind,
|
|
124
|
-
# on_new_ext_proxytype = on_new_ext_proxytype,
|
|
125
|
-
wrap_int_call = wrap_int_call,
|
|
126
|
-
wrap_ext_call = wrap_ext_call)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
# class Reader:
|
|
130
|
-
|
|
131
|
-
# def __init__(self, objectreader):
|
|
132
|
-
# self.objectreader = objectreader
|
|
133
|
-
|
|
134
|
-
# self.objectreader()
|
|
135
|
-
|
|
136
|
-
def tracing_config(config):
|
|
137
|
-
level = os.environ.get('RETRACE_DEBUG', config['default_tracing_level'])
|
|
138
|
-
return config['tracing_levels'].get(level, {})
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def install(create_system):
|
|
142
|
-
return patcher.install(config = load_config('config.json'), create_system = create_system)
|