retracesoftware-proxy 0.2.18__py3-none-any.whl → 0.2.20__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.
@@ -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,59 +128,72 @@ 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
 
146
+ # Check if recording is disabled (for performance testing)
147
+ recording_disabled = (options.recording == 'disable')
148
+
93
149
  if options.verbose:
94
- print(f"Retrace enabled, recording to {options.recording}", file=sys.stderr)
150
+ if recording_disabled:
151
+ print(f"Retrace enabled, recording DISABLED (performance testing mode)", file=sys.stderr)
152
+ else:
153
+ print(f"Retrace enabled, recording to {options.recording}", file=sys.stderr)
95
154
 
96
- path = Path(expand_recording_path(options.recording))
97
- # ensure the path exists
98
- path.mkdir(parents=True, exist_ok=True)
155
+ if recording_disabled:
156
+ path = None
157
+ else:
158
+ path = Path(expand_recording_path(options.recording))
159
+
160
+ # Create trace directory via custom command or default mkdir
161
+ if options.create_tracedir_cmd:
162
+ run_create_tracedir_cmd(options.create_tracedir_cmd, path)
163
+ else:
164
+ path.mkdir(parents=True, exist_ok=True)
99
165
 
100
166
  from retracesoftware.install import edgecases
101
167
  edgecases.recording_path = path
102
168
 
103
- # write various recording files to directory
104
- dump_as_json(path / 'settings.json', {
105
- 'argv': args,
106
- 'executable': sys.executable,
107
- 'magic_markers': options.magic_markers,
108
- 'trace_inputs': options.trace_inputs,
109
- 'trace_shutdown': options.trace_shutdown,
110
- 'env': dict(os.environ),
111
- 'python_version': sys.version,
112
- 'md5_checksums': checksums(),
113
- })
114
-
115
- rundir = path / 'run'
116
- rundir.mkdir(exist_ok=True)
117
-
118
- script = Path(scriptname(args))
119
- if script.exists():
120
- copy2(script, rundir)
121
-
122
- # create a .venv directory in the recording path
123
- # venv_path = path / '.venv'
124
- # venv_path.mkdir(exist_ok=True)
125
-
126
- # create a pyvenv.cfg file in the .venv directory
127
- # with open(venv_path / 'pyvenv.cfg', 'w') as f:
128
- # f.write(f'home = {sys.executable}\n')
129
- # f.write('include-system-site-packages = false\n')
130
- # f.write(f'version = {sys.version}\n')
131
-
132
- # bindir = venv_path / 'bin'
133
- # bindir.mkdir(exist_ok=True)
134
-
135
- # create a symlink to the python executable in the .venv directory
136
- # python_link = bindir / 'python'
137
- # if python_link.exists() or python_link.is_symlink():
138
- # python_link.unlink()
139
- # python_link.symlink_to(sys.executable)
140
-
141
- dump_as_json(path / 'replay.code-workspace', vscode_workspace)
142
-
143
- with stream.writer(path = path / 'trace.bin',
169
+ # Write recording files (skip if disabled)
170
+ if path:
171
+ path_info = stream.get_path_info()
172
+ dump_as_json(path / 'settings.json', {
173
+ 'argv': args,
174
+ 'executable': sys.executable,
175
+ 'magic_markers': options.magic_markers,
176
+ 'trace_inputs': options.trace_inputs,
177
+ 'trace_shutdown': options.trace_shutdown,
178
+ 'python_version': sys.version,
179
+ 'cwd': path_info['cwd'],
180
+ 'sys_path': path_info['sys_path'],
181
+ })
182
+ dump_as_json(path / 'md5_checksums.json', checksums())
183
+
184
+ # Write env to standard .env file
185
+ with open(path / '.env', 'w') as f:
186
+ for key, value in os.environ.items():
187
+ # Escape newlines and quotes for .env format
188
+ escaped = value.replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"')
189
+ f.write(f'{key}="{escaped}"\n')
190
+
191
+ dump_as_json(path / 'replay.code-workspace', vscode_workspace)
192
+
193
+ # path=None disables all trace writes (performance testing mode)
194
+ trace_path = None if recording_disabled else path / 'trace.bin'
195
+
196
+ with stream.writer(path = trace_path,
144
197
  thread = thread_id,
145
198
  verbose = options.verbose,
146
199
  stacktraces = options.stacktraces,
@@ -178,24 +231,32 @@ def record(options, args):
178
231
  gc.callbacks.remove(system.on_gc_event)
179
232
 
180
233
  def replay(args):
181
- path = Path(args.recording)
234
+ # Resolve path before any chdir
235
+ path = Path(args.recording).resolve()
182
236
 
183
237
  if not path.exists():
184
238
  raise RecordingNotFoundError(f"Recording path: {path} does not exist")
185
239
 
186
240
  settings = load_json(path / "settings.json")
241
+ recorded_checksums = load_json(path / "md5_checksums.json")
187
242
 
188
- if settings['md5_checksums'] != checksums():
189
- raise VersionMismatchError("Checksums for Retrace do not match, cannot run replay with different version of retrace to record")
243
+ current_checksums = checksums()
244
+ if recorded_checksums != current_checksums:
245
+ diffs = diff_dicts(recorded_checksums, current_checksums)
246
+ diff_str = "\n".join(diffs) if diffs else "(no differences found in structure)"
247
+ raise VersionMismatchError(f"Checksums for Retrace do not match:\n{diff_str}")
190
248
 
191
249
  if settings['python_version'] != sys.version:
192
250
  raise VersionMismatchError("Python version does not match, cannot run replay with different version of Python to record")
193
251
 
194
- os.environ.update(settings['env'])
252
+ os.environ.update(load_env(path / '.env'))
195
253
 
196
254
  if sys.executable != settings['executable']:
197
255
  raise ConfigurationError(f"Stopping replay as current python executable: {sys.executable} is not what was used for record: {settings['executable']}")
198
256
 
257
+ # Change to recorded cwd - replay from same directory as recording
258
+ os.chdir(settings['cwd'])
259
+
199
260
  thread_state = utils.ThreadState(*thread_states)
200
261
 
201
262
  # with stream.reader(path = path / 'trace.bin',
@@ -226,6 +287,7 @@ def replay(args):
226
287
  gc.collect()
227
288
  gc.disable()
228
289
 
290
+ # Use original argv - scripts are now relative to cwd (recording/run)
229
291
  run_with_retrace(system, settings['argv'], settings['trace_shutdown'])
230
292
 
231
293
  def main():
@@ -272,11 +334,19 @@ def main():
272
334
  help='Whether to write call parameters, used for debugging'
273
335
  )
274
336
 
337
+ parser.add_argument(
338
+ '--create_tracedir_cmd',
339
+ type=str,
340
+ default=None,
341
+ help='Command to create trace directory (receives directory path as argument)'
342
+ )
343
+
275
344
  parser.add_argument('rest', nargs = argparse.REMAINDER, help='target application and arguments')
276
345
 
277
346
  args = parser.parse_args()
278
347
 
279
348
  record(args, args.rest[1:])
349
+
280
350
  else:
281
351
 
282
352
  parser.add_argument(
@@ -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 copied modules
8
- copied_modules = set()
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
- def __init__(self, cwd, run_path, python_path):
24
- self.cwd = cwd
25
- self.run_path = run_path
26
- self.python_path = python_path
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 copied_modules:
32
- module_path = Path(spec.origin)
33
-
34
- dest_path = None
35
-
36
- if module_path.is_relative_to(self.cwd):
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
- full_path = str(path.resolve())
137
- sys.argv = [full_path] + script_args
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
- # Change to script's directory
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: retracesoftware_proxy
3
- Version: 0.2.18
3
+ Version: 0.2.20
4
4
  License: Apache-2.0
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: retracesoftware_utils
@@ -1,29 +1,21 @@
1
1
  retracesoftware/__init__.py,sha256=jQw15XBREFZX93BHpvREfc-hQmMUHYtO6gO-qZmdW1o,482
2
- retracesoftware/__main__.py,sha256=FwxTltjG1CnARYD4bdPLNiTTc8cF7WryLdBSDSg0zF0,9871
3
- retracesoftware/autoenable.py,sha256=6KxpaPpeleSN7-qmekA4w2HJQaet_9Flt9WikQvyN04,1808
2
+ retracesoftware/__main__.py,sha256=ac1FZidru6ziYfPgWM4gJHGLfT4MZT8nKHDwBHRgPIQ,13258
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=Gi1TpMF30QLmiziCU7hu3zR_8Hr1R7Qx0TsiQOjLmzA,12216
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=uQkfdOQOY20hFAcwDAqx7m8rbtGM2rBKOfC3Szb1zhw,4942
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.18.dist-info/METADATA,sha256=KZeS6LA5Mqcp9H-ofq3949xU3ad9DmQdhp7sDmuw1k0,227
43
- retracesoftware_proxy-0.2.18.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
44
- retracesoftware_proxy-0.2.18.dist-info/top_level.txt,sha256=hYHsR6txLidmqvjBMITpIHvmJJbmoCAgr76-IpZPRz8,16
45
- retracesoftware_proxy-0.2.18.dist-info/RECORD,,
34
+ retracesoftware_proxy-0.2.20.dist-info/METADATA,sha256=tD9fuv-lSdfinDCoh3NY9yjQUL2YUeKQsSL9kg1zeMQ,227
35
+ retracesoftware_proxy-0.2.20.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
36
+ retracesoftware_proxy-0.2.20.dist-info/top_level.txt,sha256=hYHsR6txLidmqvjBMITpIHvmJJbmoCAgr76-IpZPRz8,16
37
+ retracesoftware_proxy-0.2.20.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)