retracesoftware-proxy 0.1.22__py3-none-any.whl → 0.2.0__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.
@@ -5,21 +5,29 @@ from retracesoftware.install import globals
5
5
  import os, json, re, glob
6
6
  from pathlib import Path
7
7
  from datetime import datetime
8
+ from retracesoftware.install.config import env_truthy
8
9
 
9
- def latest_from_pattern(pattern: str) -> str | None:
10
- """
11
- Given a strftime-style filename pattern (e.g. "recordings/%Y%m%d_%H%M%S_%f"),
12
- return the path to the most recent matching file, or None if no files exist.
13
- """
10
+ def recordings(pattern):
14
11
  # Turn strftime placeholders into '*' for globbing
15
12
  # (very simple replacement: %... -> *)
16
13
  glob_pattern = re.sub(r"%[a-zA-Z]", "*", pattern)
17
14
 
15
+ base_pattern = os.path.basename(pattern)
16
+
18
17
  # Find all matching files
19
- candidates = glob.glob(glob_pattern)
20
- if not candidates:
21
- return None
18
+ for path in glob.glob(glob_pattern):
19
+ try:
20
+ name = os.path.basename(path)
21
+ datetime.strptime(name, base_pattern)
22
+ yield path
23
+ except:
24
+ pass
22
25
 
26
+ def latest_from_pattern(pattern: str) -> str | None:
27
+ """
28
+ Given a strftime-style filename pattern (e.g. "recordings/%Y%m%d_%H%M%S_%f"),
29
+ return the path to the most recent matching file, or None if no files exist.
30
+ """
23
31
  # Derive the datetime format from the pattern (basename only)
24
32
  base_pattern = os.path.basename(pattern)
25
33
 
@@ -28,11 +36,11 @@ def latest_from_pattern(pattern: str) -> str | None:
28
36
  return datetime.strptime(name, base_pattern)
29
37
 
30
38
  # Find the latest by parsed timestamp
31
- latest = max(candidates, key=parse_time)
32
- return latest
39
+ return max(recordings(pattern), key=parse_time)
33
40
 
34
41
  def replay_system(thread_state, immutable_types, config):
35
42
 
43
+ verbose = env_truthy('RETRACE_VERBOSE', False)
36
44
  recording_path = Path(latest_from_pattern(config['recording_path']))
37
45
 
38
46
  # print(f"replay running against path: {recording_path}")
@@ -51,8 +59,44 @@ def replay_system(thread_state, immutable_types, config):
51
59
  with open(recording_path / "mainscript", "r", encoding="utf-8") as f:
52
60
  mainscript = f.read()
53
61
 
62
+ call_trace_file = recording_path / "call_trace.txt"
63
+
64
+ if call_trace_file.exists():
65
+ class CallTracer:
66
+ def __init__(self):
67
+ self.file = open(call_trace_file, 'r')
68
+
69
+ def __call__(self, obj):
70
+ recording = json.loads(self.file.readline())
71
+ if obj != recording:
72
+ breakpoint()
73
+
74
+ def close(self):
75
+ self.file.close()
76
+
77
+ # def on_call(self, function_name):
78
+ # recording = self.file.readline()
79
+ # if f'call: {function_name}\n' != recording:
80
+ # breakpoint()
81
+
82
+ # assert f'call: {function_name}\n' == recording
83
+
84
+ # def on_return(self, function_name):
85
+ # recording = self.file.readline()
86
+ # if f'return: {function_name}\n' != recording:
87
+ # breakpoint()
88
+
89
+ # assert f'return: {function_name}\n' == recording
90
+
91
+ call_tracer = CallTracer()
92
+ else:
93
+ call_tracer = None
94
+
54
95
  return ReplayProxySystem(thread_state = thread_state,
55
96
  immutable_types = immutable_types,
56
97
  tracing_config = tracing_config,
57
98
  mainscript = mainscript,
58
- path = recording_path / 'trace.bin')
99
+ path = recording_path / 'trace.bin',
100
+ tracecalls = env_truthy('RETRACE_ALL', False),
101
+ verbose = verbose,
102
+ magic_markers = env_truthy('RETRACE_MAGIC_MARKERS', False))
@@ -2,9 +2,12 @@ import retracesoftware.functional as functional
2
2
  import retracesoftware_utils as utils
3
3
  from retracesoftware.proxy.proxytype import Proxy
4
4
 
5
+ from retracesoftware.proxy.serializer import serializer
6
+
5
7
  import types
6
8
  import os
7
9
  import sys
10
+ import functools
8
11
 
9
12
  def format_kwargs(kwargs):
10
13
  result = []
@@ -49,7 +52,8 @@ class Tracer:
49
52
 
50
53
  def __init__(self, config, writer):
51
54
  self.config = config
52
- serialize = functional.walker(self.serialize)
55
+ serialize = serializer
56
+ # functional.walker(self.serialize)
53
57
  self.writer = functional.mapargs(transform = serialize, function = writer)
54
58
 
55
59
  def systrace(self, frame, event, arg):
@@ -74,101 +78,101 @@ class Tracer:
74
78
  print(f'systrace RAISED ERROR!')
75
79
  raise
76
80
 
77
- def trace_calls(self, thread_state):
78
- if 'tracecalls' in self.config:
79
- # def on_call(frame):
81
+ # def trace_calls(self, thread_state):
82
+ # if 'tracecalls' in self.config:
83
+ # # def on_call(frame):
80
84
 
81
- # func = frame.function
85
+ # # func = frame.function
82
86
 
83
- # key = (func.__module__, func.__name__)
87
+ # # key = (func.__module__, func.__name__)
84
88
 
85
- # ignore = set([('abc', '__subclasscheck__'),
86
- # ('threading', '_shutdown')])
89
+ # # ignore = set([('abc', '__subclasscheck__'),
90
+ # # ('threading', '_shutdown')])
87
91
 
88
- # if key in ignore:
89
- # print('About to throw!!!')
90
- # raise Exception()
92
+ # # if key in ignore:
93
+ # # print('About to throw!!!')
94
+ # # raise Exception()
91
95
 
92
- # objtype = None
96
+ # # objtype = None
93
97
 
94
- # if 'self' in frame.locals:
95
- # this = frame.locals['self']
96
- # objtype = type(this)
98
+ # # if 'self' in frame.locals:
99
+ # # this = frame.locals['self']
100
+ # # objtype = type(this)
97
101
 
98
- # # if objtype:
99
- # # print(f'Called!!!!: {func.__module__}.{objtype.__name__}.{func.__name__}')
100
- # # else:
101
- # # print(f'Called!!!!: {func.__module__}.{func.__name__}')
102
+ # # # if objtype:
103
+ # # # print(f'Called!!!!: {func.__module__}.{objtype.__name__}.{func.__name__}')
104
+ # # # else:
105
+ # # # print(f'Called!!!!: {func.__module__}.{func.__name__}')
102
106
 
103
- # qualname = (func.__module__, objtype, func.__name__)
107
+ # # qualname = (func.__module__, objtype, func.__name__)
104
108
 
105
- # self.writer(f'{func.__module__}.{func.__name__}')
109
+ # # self.writer(f'{func.__module__}.{func.__name__}')
106
110
 
107
- # # if func.__name__ == '_path_stat':
108
- # # utils.sigtrap('_path_stat start')
111
+ # # # if func.__name__ == '_path_stat':
112
+ # # # utils.sigtrap('_path_stat start')
109
113
 
110
- # return qualname
114
+ # # return qualname
111
115
 
112
- # def on_result(qualname, res):
113
- # mod, obj, func = qualname
116
+ # # def on_result(qualname, res):
117
+ # # mod, obj, func = qualname
114
118
 
115
- # # if obj:
116
- # # print(f'Returning!!!!: {mod}.{obj}.{func}')
117
- # # else:
118
- # # print(f'Returning!!!!: {mod}.{func}')
119
+ # # # if obj:
120
+ # # # print(f'Returning!!!!: {mod}.{obj}.{func}')
121
+ # # # else:
122
+ # # # print(f'Returning!!!!: {mod}.{func}')
119
123
 
120
- # # if func == '_path_stat':
121
- # # utils.sigtrap('_path_stat res')
124
+ # # # if func == '_path_stat':
125
+ # # # utils.sigtrap('_path_stat res')
122
126
 
123
- # if func != '__hash__':
124
- # ignore = set(('typing', 'inner'))
127
+ # # if func != '__hash__':
128
+ # # ignore = set(('typing', 'inner'))
125
129
 
126
- # if qualname not in ignore:
127
- # if type(res) in [str, int]:
128
- # self.writer(res)
129
- # else:
130
- # self.writer(str(type(res)))
130
+ # # if qualname not in ignore:
131
+ # # if type(res) in [str, int]:
132
+ # # self.writer(res)
133
+ # # else:
134
+ # # self.writer(str(type(res)))
131
135
 
132
- # def on_call_disabled(frame):
133
- # func = frame.function
134
- # print(f'disabled: {func.__module__}.{func.__name__}')
136
+ # # def on_call_disabled(frame):
137
+ # # func = frame.function
138
+ # # print(f'disabled: {func.__module__}.{func.__name__}')
135
139
 
136
- callback = CallTracer(writer = self.writer, thread_state = thread_state)
137
- utils.intercept_frame_eval(callback)
140
+ # callback = CallTracer(writer = self.writer, thread_state = thread_state)
141
+ # utils.intercept_frame_eval(callback)
138
142
 
139
- def serialize(self, obj):
140
- try:
141
- if obj is None: return None
143
+ # def serialize(self, obj):
144
+ # try:
145
+ # if obj is None: return None
142
146
 
143
- cls = functional.typeof(obj)
147
+ # cls = functional.typeof(obj)
144
148
 
145
- if issubclass(cls, Proxy):
146
- return str(cls)
149
+ # if issubclass(cls, Proxy):
150
+ # return str(cls)
147
151
 
148
- if issubclass(cls, (int, str)):
149
- return obj
152
+ # if issubclass(cls, (int, str)):
153
+ # return obj
150
154
 
151
- return str(cls)
155
+ # return str(cls)
152
156
 
153
- # if issubclass(cls, Proxy):
154
- # return f'<Proxy>'
157
+ # # if issubclass(cls, Proxy):
158
+ # # return f'<Proxy>'
155
159
 
156
- # if issubclass(cls, types.TracebackType):
157
- # return '<traceback>'
160
+ # # if issubclass(cls, types.TracebackType):
161
+ # # return '<traceback>'
158
162
 
159
- # elif issubclass(cls, utils.wrapped_function):
160
- # return utils.unwrap(obj).__name__
163
+ # # elif issubclass(cls, utils.wrapped_function):
164
+ # # return utils.unwrap(obj).__name__
161
165
 
162
- # elif hasattr(obj, '__module__') and hasattr(obj, '__name__'):
163
- # return f'{obj.__module__}.{obj.__name__}'
164
- # # elif isinstance(obj, type):
165
- # # return f'{obj.__module__}.{obj.__name__}'
166
- # else:
167
- # return '<other>'
168
- # # return f'instance type: {str(self.serialize(type(obj)))}'
169
- except:
170
- print("ERROR in tracer serialize!!!!")
171
- os._exit(1)
166
+ # # elif hasattr(obj, '__module__') and hasattr(obj, '__name__'):
167
+ # # return f'{obj.__module__}.{obj.__name__}'
168
+ # # # elif isinstance(obj, type):
169
+ # # # return f'{obj.__module__}.{obj.__name__}'
170
+ # # else:
171
+ # # return '<other>'
172
+ # # # return f'instance type: {str(self.serialize(type(obj)))}'
173
+ # except:
174
+ # print("ERROR in tracer serialize!!!!")
175
+ # os._exit(1)
172
176
 
173
177
  def log(self, name, message):
174
178
  if name in self.config:
@@ -180,17 +184,23 @@ class Tracer:
180
184
  # def stacktrace(self):
181
185
  # self.writer('stacktrace', utils.stacktrace())
182
186
 
187
+ def _write_call(self, name, *args, **kwargs):
188
+ # self.stacktrace()
189
+ if len(args) > 0:
190
+ funcname = args[0].__name__
191
+ # if funcname == '__del__':
192
+ # utils.sigtrap('FOO')
193
+
194
+ self.writer(name, funcname, args[1:], kwargs)
195
+ else:
196
+ utils.sigtrap('FOO')
197
+ breakpoint()
198
+
183
199
  def __call__(self, name, func = None):
184
200
  if name in self.config:
185
201
  if name.endswith('.call'):
186
- def write_call(*args, **kwargs):
187
- # self.stacktrace()
188
- if len(args) > 0:
189
- self.writer(name, args[0].__name__, args[1:], kwargs)
190
- else:
191
- breakpoint()
192
-
193
- return functional.firstof(write_call, func) if func else write_call
202
+ f = functools.partial(self._write_call, name)
203
+ return functional.firstof(f, func) if func else f
194
204
 
195
205
  elif name.endswith('.result'):
196
206
  def write_result(obj):