retracesoftware-proxy 0.1.7__py3-none-any.whl → 0.1.9__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.
@@ -160,19 +160,33 @@
160
160
  "_imp": {
161
161
  "patch_extension_exec": ["exec_dynamic", "exec_builtin"]
162
162
  },
163
+ "bdb": {
164
+ "methods_with_state": {
165
+ "disabled": {
166
+ "Bdb": ["trace_dispatch"]
167
+ }
168
+ },
169
+ "with_state": {
170
+ "disabled": ["Bdb.trace_dispatch"]
171
+ }
172
+ },
163
173
  "sys": {
164
174
  "with_state": {
165
175
  "disabled": ["excepthook"]
166
176
  },
167
- "with_state_recursive0": {
168
- "disabled": ["settrace", "setprofile"]
177
+ "comment": {
178
+ "with_state_recursive": {
179
+ "disabled": ["settrace", "setprofile"]
180
+ }
169
181
  }
170
182
  },
171
183
 
172
184
  "importlib._bootstrap": {
185
+ "comment": {
173
186
  "with_state": {
174
187
  "bootstrap": ["_load_unlocked", "_find_spec"]
175
188
  }
189
+ }
176
190
  },
177
191
 
178
192
  "encodings": {
@@ -264,10 +278,16 @@
264
278
  "open_code": "path",
265
279
  "open": "file"
266
280
  },
267
- "wrap": {
268
- "FileIO.readinfo": "retracesoftware.install.edgecases.readinto",
269
- "BufferedReader.readinfo": "retracesoftware.install.edgecases.readinto",
270
- "BufferedRandom.readinfo": "retracesoftware.install.edgecases.readinto"
281
+ "patchtype": {
282
+ "FileIO": {
283
+ "readinfo": "retracesoftware.install.edgecases.readinto"
284
+ },
285
+ "BufferedReader": {
286
+ "readinfo": "retracesoftware.install.edgecases.readinto"
287
+ },
288
+ "BufferedRandom": {
289
+ "readinfo": "retracesoftware.install.edgecases.readinto"
290
+ }
271
291
  }
272
292
  },
273
293
  "pathlib": {
@@ -323,10 +343,12 @@
323
343
  "gaierror",
324
344
  "timeout"
325
345
  ],
326
- "wrap": {
327
- "socket.recvfrom_into": "retracesoftware.install.edgecases.recvfrom_into",
328
- "socket.recv_into": "retracesoftware.install.edgecases.recv_into",
329
- "socket.recvmsg_into": "retracesoftware.install.edgecases.recvmsg_into"
346
+ "patchtype": {
347
+ "socket": {
348
+ "recvfrom_into": "retracesoftware.install.edgecases.recvfrom_into",
349
+ "recv_into": "retracesoftware.install.edgecases.recv_into",
350
+ "recvmsg_into": "retracesoftware.install.edgecases.recvmsg_into"
351
+ }
330
352
  }
331
353
  },
332
354
  "select": {
@@ -349,8 +371,10 @@
349
371
  "_SSLSocket.write": "write"
350
372
  }
351
373
  },
352
- "wrap": {
353
- "_SSLSocket.read": "retracesoftware.install.edgecases.read"
374
+ "patchtype": {
375
+ "_SSLSocket": {
376
+ "read": "retracesoftware.install.edgecases.read"
377
+ }
354
378
  }
355
379
  },
356
380
  "_random": {
@@ -25,7 +25,7 @@ from retracesoftware.install.config import load_config
25
25
  from functools import wraps
26
26
 
27
27
  import retracesoftware.functional as functional
28
- import retracesoftware_utils as utils
28
+ import retracesoftware.utils as utils
29
29
 
30
30
  from retracesoftware.install import edgecases
31
31
  from functools import partial
@@ -137,9 +137,9 @@ def superdict(cls):
137
137
 
138
138
  return result
139
139
 
140
- def is_method_descriptor(obj):
141
- return isinstance(obj, types.FunctionType) or \
142
- (isinstance(obj, (types.WrapperDescriptorType, types.MethodDescriptorType)) and obj.__objclass__ != object)
140
+ # def is_method_descriptor(obj):
141
+ # return isinstance(obj, types.FunctionType) or \
142
+ # (isinstance(obj, (types.WrapperDescriptorType, types.MethodDescriptorType)) and obj.__objclass__ != object)
143
143
 
144
144
  def wrap_method_descriptors(wrapper, prefix, base):
145
145
  slots = {"__slots__": () }
@@ -150,7 +150,7 @@ def wrap_method_descriptors(wrapper, prefix, base):
150
150
 
151
151
  for name,value in superdict(base).items():
152
152
  if name not in blacklist:
153
- if is_method_descriptor(value):
153
+ if utils.is_method_descriptor(value):
154
154
  setattr(extended, name, wrapper(value))
155
155
 
156
156
  return extended
@@ -179,6 +179,7 @@ class Patcher:
179
179
  self.type_attribute_filter = self.predicate(config['type_attribute_filter'])
180
180
  self.post_commit = post_commit
181
181
  self.exclude_paths = [re.compile(s) for s in config.get('exclude_paths', [])]
182
+ self.typepatcher = {}
182
183
 
183
184
  def is_phase(name): return getattr(getattr(self, name, None), "is_phase", False)
184
185
 
@@ -193,7 +194,21 @@ class Patcher:
193
194
  # print(f'in path_predicate, excluding {path}')
194
195
  return False
195
196
  return True
196
-
197
+
198
+ def on_proxytype(self, cls):
199
+
200
+ def patch(spec):
201
+ for method, transform in spec.items():
202
+ setattr(cls, method, resolve(transform)(getattr(cls, method)))
203
+
204
+ if cls.__module__ in self.modules:
205
+ spec = self.modules[cls.__module__]
206
+
207
+ if 'patchtype' in spec:
208
+ patchtype = spec['patchtype']
209
+ if cls.__name__ in patchtype:
210
+ patch(patchtype[cls.__name__])
211
+
197
212
  @property
198
213
  def disable(self):
199
214
  return self.thread_state.select('disabled')
@@ -260,7 +275,7 @@ class Patcher:
260
275
 
261
276
  @patch
262
277
  def patch_start_new_thread(self, value):
263
- def start_new_thread(self, function, *args):
278
+ def start_new_thread(function, *args):
264
279
  # synchronized, replay shoudl yield correct number
265
280
  thread_id = self.thread_counter()
266
281
 
@@ -314,15 +329,35 @@ class Patcher:
314
329
  for state,elems in spec.items():
315
330
 
316
331
  def wrap(obj):
317
- return functional.recursive_wrap(
318
- callable,
319
- lambda f: self.thread_state.wrap(state, f),
332
+ return functional.recurive_wrap_function(
333
+ functional.partial(self.thread_state.wrap, state),
320
334
  obj)
321
335
 
322
336
  updates.update(map_values(wrap, select_keys(elems, mod_dict)))
323
337
 
324
338
  return updates
325
339
 
340
+ @phase
341
+ def methods_with_state(self, spec, mod_dict):
342
+
343
+ # updates = {}
344
+
345
+ def update(cls, name, f):
346
+ setattr(cls, name, f(getattr(cls, name)))
347
+
348
+ for state,cls_methods in spec.items():
349
+ def wrap(obj):
350
+ assert callable(obj)
351
+ return self.thread_state.wrap(desired_state = state, function = obj)
352
+
353
+ for typename,methodnames in cls_methods.items():
354
+ cls = mod_dict[typename]
355
+
356
+ for methodname in methodnames:
357
+ update(cls, methodname, wrap)
358
+
359
+ return {}
360
+
326
361
  @phase
327
362
  def with_state(self, spec, mod_dict):
328
363
 
@@ -330,7 +365,8 @@ class Patcher:
330
365
 
331
366
  for state,elems in spec.items():
332
367
 
333
- def wrap(obj): return self.thread_state.wrap(desired_state = state, function = obj)
368
+ def wrap(obj):
369
+ return self.thread_state.wrap(desired_state = state, function = obj)
334
370
 
335
371
  updates.update(map_values(wrap, select_keys(elems, mod_dict)))
336
372
 
@@ -377,7 +413,9 @@ class Patcher:
377
413
  name = parts[0]
378
414
  if name in mod_dict:
379
415
  value = mod_dict[name]
380
- assert not isinstance(value, utils.wrapped_function), f"value for key: {name} is already wrapped"
416
+ assert not isinstance(value, utils.wrapped_function), \
417
+ f"value for key: {name} is already wrapped"
418
+
381
419
  if len(parts) == 1:
382
420
  updates[name] = resolve(wrapper_name)(value)
383
421
  elif len(parts) == 2:
@@ -436,20 +474,19 @@ class Patcher:
436
474
 
437
475
  def __call__(self, module):
438
476
 
439
- # if module.__name__ == 'locale':
440
- # utils.sigtrap(None)
477
+ if self.thread_state.value == 'internal' and not hasattr(module, '__retrace__'):
478
+ with self.thread_state.select('bootstrap'):
479
+ configs = list(self.configs(module))
441
480
 
442
- if not hasattr(module, '__retrace__'):
443
- configs = list(self.configs(module))
444
-
445
- if len(configs) > 0:
446
- if len(configs) > 1:
447
- raise Exception(f'TODO')
448
- else:
449
- try:
450
- self.patch_module_with_name(configs[0], module)
451
- except Exception as error:
452
- raise Exception(f'Error patching module: {configs[0]}') from error
481
+ if len(configs) > 0:
482
+ if len(configs) > 1:
483
+ raise Exception(f'TODO')
484
+ else:
485
+ module.__retrace__ = None
486
+ try:
487
+ self.patch_module_with_name(configs[0], module)
488
+ except Exception as error:
489
+ raise Exception(f'Error patching module: {configs[0]}') from error
453
490
 
454
491
  return module
455
492
 
@@ -518,6 +555,8 @@ def install(mode):
518
555
  system = system,
519
556
  post_commit = getattr(system, 'on_patched', None),
520
557
  immutable_types = immutable_types)
558
+
559
+ system.on_proxytype = patcher.on_proxytype
521
560
 
522
561
  def at_exit(): thread_state.value = 'disabled'
523
562
 
@@ -13,11 +13,34 @@ def format_kwargs(kwargs):
13
13
  return tuple(result)
14
14
 
15
15
  class Tracer:
16
+
16
17
  def __init__(self, config, writer):
17
18
  self.config = config
18
19
  serialize = functional.walker(self.serialize)
19
20
  self.writer = functional.mapargs(transform = serialize, function = writer)
20
21
 
22
+ def systrace(self, frame, event, arg):
23
+ try:
24
+ if event in ['line', 'call']:
25
+ print(f'In systrace: {event} {frame.f_code.co_filename}:{frame.f_lineno}')
26
+ self.writer(event, frame.f_code.co_filename, frame.f_code.co_name, frame.f_lineno)
27
+
28
+ elif event == 'return':
29
+ print(f'In systrace: {event}')
30
+ self.writer(event)
31
+ # self.writer(event, self.serialize(arg))
32
+
33
+ elif event == 'exception':
34
+ print(f'In systrace: {event}')
35
+ self.writer(event)
36
+ else:
37
+ print(f'In systrace: {event}')
38
+
39
+ return self.systrace
40
+ except:
41
+ print(f'systrace RAISED ERROR!')
42
+ raise
43
+
21
44
  def serialize(self, obj):
22
45
  try:
23
46
  if obj is None: return None
@@ -56,6 +79,9 @@ class Tracer:
56
79
  if name in self.config:
57
80
  self.writer(name, message)
58
81
 
82
+ def checkpoint(self, obj):
83
+ self.writer(obj)
84
+
59
85
  def stacktrace(self):
60
86
  self.writer('stacktrace', utils.stacktrace())
61
87
 
@@ -63,8 +89,11 @@ class Tracer:
63
89
  if name in self.config:
64
90
  if name.endswith('.call'):
65
91
  def write_call(*args, **kwargs):
66
- # self.stacktrace()
67
- self.writer(name, args[0].__name__, args[1:], kwargs)
92
+ self.stacktrace()
93
+ if len(args) > 0:
94
+ self.writer(name, args[0].__name__, args[1:], kwargs)
95
+ else:
96
+ breakpoint()
68
97
 
69
98
  return functional.firstof(write_call, func) if func else write_call
70
99
 
@@ -36,13 +36,14 @@ def resolve(obj):
36
36
  def is_function_type(cls):
37
37
  return cls in [types.BuiltinFunctionType, types.FunctionType]
38
38
 
39
+ def is_instance_method(obj):
40
+ return isinstance(obj, types.MethodDescriptorType) or isinstance(obj, types.FunctionType)
41
+
39
42
  class ProxySystem:
40
43
 
41
44
  def bind(self, obj): pass
42
45
 
43
- def wrap_int_to_ext(self, obj):
44
- return obj
45
- # return functional.sequence(functional.side_effect(functional.repeatedly(gc.collect)), obj)
46
+ def wrap_int_to_ext(self, obj): return obj
46
47
 
47
48
  def wrap_ext_to_int(self, obj): return obj
48
49
 
@@ -54,10 +55,13 @@ class ProxySystem:
54
55
 
55
56
  def on_ext_error(self, err_type, err_value, err_traceback):
56
57
  pass
57
-
58
+
58
59
  # def stacktrace(self):
59
60
  # self.tracer.stacktrace()
60
61
 
62
+ def set_thread_id(self, id):
63
+ utils.set_thread_id(id)
64
+
61
65
  def __init__(self, thread_state, immutable_types, tracer):
62
66
 
63
67
  self.thread_state = thread_state
@@ -67,7 +71,7 @@ class ProxySystem:
67
71
  self.on_proxytype = None
68
72
 
69
73
  def is_immutable_type(cls):
70
- return issubclass(cls, tuple(immutable_types))
74
+ return cls is object or issubclass(cls, tuple(immutable_types))
71
75
 
72
76
  is_immutable = functional.sequence(functional.typeof, functional.memoize_one_arg(is_immutable_type))
73
77
 
@@ -84,7 +88,7 @@ class ProxySystem:
84
88
 
85
89
  ext_spec = SimpleNamespace(
86
90
  apply = thread_state.wrap('external', functional.apply),
87
- proxy = proxyfactory(thread_state.wrap('disabled', self.dynamic_ext_proxytype)),
91
+ proxy = proxyfactory(thread_state.wrap('disabled', self.ext_proxytype)),
88
92
  on_call = tracer('proxy.ext.call'),
89
93
  on_result = self.on_ext_result,
90
94
  on_error = self.on_ext_error,
@@ -102,6 +106,11 @@ class ProxySystem:
102
106
  self.ext_dispatch = gateway('proxy.int.disabled.event', internal = self.ext_handler)
103
107
  self.int_dispatch = gateway('proxy.ext.disabled.event', external = self.int_handler)
104
108
 
109
+ if 'systrace' in tracer.config:
110
+ func = thread_state.wrap(desired_state = 'disabled', function = tracer.systrace)
111
+ func = self.thread_state.dispatch(lambda *args: None, internal = func)
112
+ sys.settrace(func)
113
+
105
114
  def new_child_path(self, path):
106
115
  return path.parent / f'fork-{self.fork_counter}' / path.name
107
116
 
@@ -117,76 +126,78 @@ class ProxySystem:
117
126
  self.thread_state.value = self.saved_thread_state
118
127
  self.fork_counter += 1
119
128
 
120
- def create_stub(self): return False
129
+ # def create_stub(self): return False
121
130
 
122
131
  def int_proxytype(self, cls):
123
- return dynamic_int_proxytype(
132
+ if cls is object:
133
+ breakpoint()
134
+
135
+ proxytype = dynamic_int_proxytype(
124
136
  handler = self.int_dispatch,
125
137
  cls = cls,
126
138
  bind = self.bind)
127
-
128
- def dynamic_ext_proxytype(self, cls):
129
-
130
- proxytype = dynamic_proxytype(
131
- handler = self.ext_dispatch,
132
- cls = cls)
133
- if self.on_proxytype:
134
- self.on_proxytype(proxytype)
135
139
 
140
+ if self.on_proxytype: self.on_proxytype(proxytype)
136
141
  return proxytype
137
-
138
- # resolved = resolve(cls)
139
- # if isinstance(resolved, ExtendingProxy):
140
- # return dynamic_from_extended(resolved)
141
- # elif isinstance(resolved, DynamicProxy):
142
- # return resolved
143
- # else:
144
- # return dynamic_proxytype(handler = self.ext_dispatch, cls = cls)
145
142
 
146
143
  def ext_proxytype(self, cls):
147
- assert isinstance(cls, type)
148
- if utils.is_extendable(cls):
149
- return self.extend_type(cls)
150
- else:
151
- return self.proxy_function(cls)
144
+ if cls is object:
145
+ breakpoint()
146
+
147
+ proxytype = dynamic_proxytype(handler = self.ext_dispatch, cls = cls)
152
148
 
153
- # return instantiable_dynamic_proxytype(
154
- # handler = self.ext_dispatch,
155
- # cls = cls,
156
- # thread_state = self.thread_state,
157
- # create_stub = self.create_stub())
158
-
159
- def basetype(self, cls):
160
- return cls
161
-
162
- def extend_type(self, cls):
163
- extended = extending_proxytype(
164
- cls = cls,
165
- base = self.basetype(cls),
166
- thread_state = self.thread_state,
167
- ext_handler = self.ext_dispatch,
168
- int_handler = self.int_dispatch,
169
- on_subclass_new = self.bind)
149
+ if self.on_proxytype: self.on_proxytype(proxytype)
170
150
 
171
- self.immutable_types.add(extended)
172
-
173
- return extended
174
-
151
+ return proxytype
152
+
175
153
  def function_target(self, obj): return obj
176
154
 
177
155
  def proxy_function(self, obj):
178
156
  return utils.wrapped_function(handler = self.ext_handler, target = obj)
179
157
 
158
+ def patchtype(self, cls):
159
+ if cls in self.immutable_types or issubclass(cls, tuple):
160
+ return cls
161
+
162
+ def wrap(func):
163
+ return self.thread_state.dispatch(func, internal = self.proxy_function(func))
164
+
165
+ def wrap_new(func):
166
+ proxied = self.proxy_function(func)
167
+
168
+ def new(cls, *args, **kwargs):
169
+ instance = proxied(cls, *args, **kwargs)
170
+ instance.__init__(*args, **kwargs)
171
+ return instance
172
+
173
+ return self.thread_state.dispatch(func, internal = new)
174
+
175
+ if utils.is_extendable(cls):
176
+ slots = {'__module__': cls.__module__, '__slots__': []}
177
+
178
+ for name, value in superdict(cls).items():
179
+ if callable(value) and not is_instance_method(value):
180
+ slots[name] = wrap_new(value) if name == '__new__' else wrap(value)
181
+
182
+ return type(cls.__name__, (cls,), slots)
183
+
184
+ elif not utils.is_immutable(cls):
185
+ def update(name, f):
186
+ setattr(cls, name, f(getattr(cls, name)))
187
+
188
+ for name, value in superdict(cls).items():
189
+ if callable(value) and not is_instance_method(value):
190
+ update(name, wrap_new if name == '__new__' else wrap)
191
+ else:
192
+ return wrap(cls)
193
+
180
194
  def __call__(self, obj):
181
195
  assert not isinstance(obj, BaseException)
182
196
  assert not isinstance(obj, Proxy)
183
197
  assert not isinstance(obj, utils.wrapped_function)
184
198
 
185
- if type(obj) == type:
186
- if obj in self.immutable_types or issubclass(obj, tuple):
187
- return obj
188
-
189
- return self.ext_proxytype(obj)
199
+ if type(obj) == type:
200
+ return self.patchtype(obj)
190
201
 
191
202
  elif type(obj) in self.immutable_types:
192
203
  return obj
@@ -199,6 +210,7 @@ class ProxySystem:
199
210
 
200
211
  else:
201
212
  proxytype = dynamic_proxytype(handler = self.ext_dispatch, cls = type(obj))
213
+ if self.on_proxytype: self.on_proxytype(proxytype)
202
214
 
203
215
  return utils.create_wrapped(proxytype, obj)
204
216
  # raise Exception(f'object {obj} was not proxied as its not a extensible type and is not callable')
@@ -163,7 +163,11 @@ class DescriptorProxy:
163
163
  self.target = target
164
164
 
165
165
  def __get__(self, obj, cls):
166
- return self.handler(self.target.__get__, obj, cls)
166
+ try:
167
+ return self.handler(self.target.__get__, obj, cls)
168
+ except:
169
+ print(f'error calling __get__')
170
+ raise
167
171
 
168
172
  def __set__(self, obj, value):
169
173
  return self.handler(self.target.__set__, obj, value)
@@ -171,27 +175,28 @@ class DescriptorProxy:
171
175
  def __delete__(self, obj):
172
176
  return self.handler(self.target.__delete__, obj)
173
177
 
174
- class ExtendingDescriptorProxy:
178
+ # class ExtendingDescriptorProxy:
175
179
 
176
- __slots__ = ['handler', 'proxytype', 'name']
180
+ # __slots__ = ['handler', 'proxytype', 'name']
177
181
 
178
- def __init__(self, proxytype, handler, name):
179
- self.proxytype = proxytype
180
- self.handler = handler
181
- self.name = name
182
+ # def __init__(self, proxytype, handler, name):
183
+ # self.proxytype = proxytype
184
+ # self.handler = handler
185
+ # self.name = name
182
186
 
183
- def __get__(self, instance, owner):
184
- inst = owner if instance is None else instance
185
- getter = functional.partial(getattr, super(self.proxytype, inst))
186
- return self.handler(getter, self.name)
187
+ # def __get__(self, instance, owner):
188
+ # inst = owner if instance is None else instance
189
+ # getter = functional.partial(getattr, super(self.proxytype, inst))
190
+ # return self.handler(getter, self.name)
187
191
 
188
- def __set__(self, instance, value):
189
- setter = functional.partial(setattr, super(self.proxytype, instance))
190
- return self.handler(setter, self.name, value)
192
+ # def __set__(self, instance, value):
193
+ # breakpoint()
194
+ # setter = functional.partial(setattr, super(self.proxytype, instance))
195
+ # return self.handler(setter, self.name, value)
191
196
 
192
- def __delete__(self, instance):
193
- deleter = functional.partial(delattr, super(self.proxytype, instance))
194
- return self.handler(deleter, self.name)
197
+ # def __delete__(self, instance):
198
+ # deleter = functional.partial(delattr, super(self.proxytype, instance))
199
+ # return self.handler(deleter, self.name)
195
200
 
196
201
 
197
202
  def dynamic_proxytype(handler, cls):
@@ -203,14 +208,16 @@ def dynamic_proxytype(handler, cls):
203
208
 
204
209
  spec = {}
205
210
 
211
+ def wrap(func): return utils.wrapped_function(handler = handler, target = func)
212
+
206
213
  for name in superdict(cls).keys():
207
214
  if name not in blacklist:
208
215
  value = getattr(cls, name)
209
216
  if is_descriptor(value):
210
217
  if utils.is_method_descriptor(value):
211
- spec[name] = utils.wrapped_function(handler = handler, target = value)
212
- else:
213
- spec[name] = DescriptorProxy(handler = handler, target = value)
218
+ spec[name] = wrap(value)
219
+ # else:
220
+ # spec[name] = DescriptorProxy(handler = handler, target = value)
214
221
 
215
222
  # to_proxy = [m for m in methods(cls) if m not in blacklist]
216
223
 
@@ -218,8 +225,8 @@ def dynamic_proxytype(handler, cls):
218
225
 
219
226
  # spec = { name: wrap(getattr(cls, name)) for name in to_proxy }
220
227
 
221
- # spec['__getattr__'] = wrap(getattr)
222
- # spec['__setattr__'] = wrap(setattr)
228
+ spec['__getattr__'] = wrap(getattr)
229
+ spec['__setattr__'] = wrap(setattr)
223
230
 
224
231
  if utils.yields_callable_instances(cls):
225
232
  spec['__call__'] = handler
@@ -362,7 +369,8 @@ def extending_proxytype(cls, base, thread_state, ext_handler, int_handler, on_su
362
369
  extended = type(cls.__name__, (base, ExtendingProxy), slots)
363
370
 
364
371
  for name in descriptors:
365
- proxy = ExtendingDescriptorProxy(handler = ext_handler, name = name, proxytype = extended)
372
+ # proxy = ExtendingDescriptorProxy(handler = ext_handler, name = name, proxytype = extended)
373
+ proxy = DescriptorProxy(handler = ext_handler, target = getattr(cls, name))
366
374
  setattr(extended, name, proxy)
367
375
 
368
376
  def unproxied__new__(subclass, *args, **kwargs):
@@ -70,6 +70,13 @@ class RecordProxySystem(ProxySystem):
70
70
  self.thread_state.value = self.saved_thread_state
71
71
  self.writer.reopen()
72
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
80
  def __init__(self, thread_state,
74
81
  immutable_types,
75
82
  tracing_config,
@@ -95,132 +102,49 @@ class RecordProxySystem(ProxySystem):
95
102
 
96
103
  serialize = functional.walker(self.bindings.get_else_key)
97
104
 
98
- thread_switch_monitor = \
105
+ self.thread_switch_monitor = \
99
106
  utils.thread_switch_monitor(
100
107
  functional.repeatedly(functional.sequence(utils.thread_id, self.writer)))
101
108
 
102
- self.sync = lambda function: functional.firstof(thread_switch_monitor, functional.always(self.writer.handle('SYNC')), function)
109
+ # self.sync = lambda function: functional.firstof(self.thread_switch_monitor, functional.always(self.writer.handle('SYNC')), function)
103
110
 
104
111
  error = self.writer.handle('ERROR')
105
112
 
106
113
  def write_error(cls, val, traceback):
107
114
  error(cls, val)
108
115
 
109
- self.set_thread_id = functional.partial(utils.set_thread_id, self.writer)
116
+ # self.set_thread_id = functional.partial(utils.set_thread_id, self.writer)
110
117
 
111
- def watch(f): return functional.either(thread_switch_monitor, f)
118
+ def watch(f): return functional.either(self.thread_switch_monitor, f)
112
119
 
120
+ # w = self.writer.handle('TRACE')
121
+ # def foo(name, *args):
122
+ # print(f'writing: {self.writer.messages_written} {name} {args}')
123
+ # w(self.writer.messages_written, name, *args)
124
+
125
+ # tracer = Tracer(tracing_config, writer = foo)
113
126
  tracer = Tracer(tracing_config, writer = self.writer.handle('TRACE'))
114
127
 
115
128
  self.wrap_int_to_ext = watch
116
129
 
117
130
  self.on_int_call = functional.mapargs(transform = serialize, function = self.writer.handle('CALL'))
118
131
 
119
- # self.on_ext_result = functional.if_then_else(
120
- # functional.isinstanceof(str),
121
- # self.writer.handle('RESULT'),
122
- # functional.sequence(serialize, self.writer))
123
-
124
- self.on_ext_result = functional.sequence(serialize,
125
- self.writer.handle('RESULT'))
132
+ self.on_ext_result = functional.sequence(serialize, self.writer.handle('RESULT'))
126
133
 
127
134
  self.on_ext_error = write_error
128
135
 
129
136
  self.ext_apply = self.int_apply = functional.apply
130
137
 
131
- super().__init__(thread_state = thread_state, tracer = tracer, immutable_types = immutable_types)
138
+ super().__init__(thread_state = thread_state,
139
+ tracer = tracer,
140
+ immutable_types = immutable_types)
132
141
 
133
- def dynamic_ext_proxytype(self, cls):
142
+ def ext_proxytype(self, cls):
134
143
 
135
- proxytype = super().dynamic_ext_proxytype(cls)
144
+ proxytype = super().ext_proxytype(cls)
136
145
 
137
146
  ref = self.writer.handle(StubRef(proxytype))
138
-
139
- # blacklist = ['__class__', '__dict__', '__module__', '__doc__']
140
-
141
- # methods = []
142
- # members = []
143
-
144
- # for key,value in proxytype.__dict__.items():
145
- # if key not in blacklist:
146
- # if utils.is_method_descriptor(value):
147
- # methods.append(key)
148
- # elif not key.startswith("__retrace"):
149
- # members.append(key)
150
-
151
- # ref = self.writer.handle(StubRef(
152
- # name = cls.__name__,
153
- # module = cls.__module__,
154
- # methods = methods,
155
- # members = members))
156
-
157
- # list(proxytype.__dict__.keys())
158
-
159
- # if resolveable_name(cls):
160
- # module, name = resolveable_name(cls)
161
- # ref = self.writer.handle(StubRef(type = 'dynamic', name = name, module = module))
162
- # else:
163
- # blacklist = ['__getattribute__']
164
- # descriptors = {k: v for k,v in superdict(cls).items() if k not in blacklist and is_descriptor(v) }
165
-
166
- # methods = [k for k, v in descriptors.items() if utils.is_method_descriptor(v)]
167
- # members = [k for k, v in descriptors.items() if not utils.is_method_descriptor(v)]
168
-
169
- # ref = self.writer.handle(ProxySpec(name = cls.__name__,
170
- # module = cls.__module__,
171
- # methods = methods,
172
- # members = members))
173
147
 
174
148
  self.writer.type_serializer[proxytype] = functional.constantly(ref)
175
149
 
176
150
  return proxytype
177
-
178
- def ext_proxytype(self, cls):
179
- assert isinstance(cls, type), f"record.proxytype requires a type but was passed: {cls}"
180
-
181
- # resolved = resolve(cls)
182
-
183
- proxytype = super().ext_proxytype(cls)
184
-
185
- assert resolve(cls) is cls
186
-
187
- # ref = self.writer.handle(StubRef(name = cls.__name__,
188
- # module = cls.__module__))
189
-
190
- # if resolveable_name(cls):
191
- # module, name = resolveable_name(cls)
192
- # ref = self.writer.handle(StubRef(name = cls.__name__, module = cls.__module__))
193
- # else:
194
- # blacklist = ['__getattribute__']
195
- # descriptors = {k: v for k,v in superdict(cls).items() if k not in blacklist and is_descriptor(v) }
196
-
197
- # methods = [k for k, v in descriptors.items() if utils.is_method_descriptor(v)]
198
- # members = [k for k, v in descriptors.items() if not utils.is_method_descriptor(v)]
199
-
200
- # ref = self.writer.handle(ProxySpec(name = cls.__name__,
201
- # module = cls.__module__,
202
- # methods = methods,
203
- # members = members))
204
-
205
- # self.writer.type_serializer[proxytype] = functional.constantly(ref)
206
- return proxytype
207
-
208
-
209
- def extend_type(self, cls):
210
-
211
- if cls in self.extended_types:
212
- return self.extended_types[cls]
213
-
214
- extended = super().extend_type(cls)
215
-
216
- self.extended_types[cls] = extended
217
-
218
- ref = self.writer.handle(ExtendedRef(name = cls.__name__,
219
- module = cls.__module__))
220
-
221
- # for binding?
222
- # self.writer(ref)
223
-
224
- self.writer.type_serializer[extended] = functional.constantly(ref)
225
-
226
- return extended
@@ -78,22 +78,6 @@ def on_stack_mismatch(last_matching, record, replay):
78
78
 
79
79
  class ReplayProxySystem(ProxySystem):
80
80
 
81
- # def stubtype(self, cls):
82
- # assert not issubclass(cls, Proxy)
83
-
84
- # return dynamic_proxytype(handler = self.ext_handler, cls = cls)
85
-
86
- def create_stub(self): return True
87
-
88
- # def stubtype_from_spec(self, spec):
89
- # print (f'FOOO!!! {spec}')
90
- # return stubtype_from_spec(
91
- # handler = self.ext_handler,
92
- # module = spec.module,
93
- # name = spec.name,
94
- # methods = spec.methods,
95
- # members = spec.members)
96
-
97
81
  @utils.striptraceback
98
82
  def next_result(self):
99
83
  while True:
@@ -113,6 +97,7 @@ class ReplayProxySystem(ProxySystem):
113
97
  return self.messages()
114
98
 
115
99
  elif next == 'ERROR':
100
+ # breakpoint()
116
101
  err_type = self.messages()
117
102
  err_value = self.messages()
118
103
  utils.raise_exception(err_type, err_value)
@@ -152,6 +137,66 @@ class ReplayProxySystem(ProxySystem):
152
137
  def basetype(self, cls):
153
138
  return self.stub_factory.create_stubtype(StubRef(cls))
154
139
 
140
+
141
+ def readnext(self):
142
+ with self.thread_state.select('disabled'):
143
+ try:
144
+ # obj = self.messages()
145
+ # print(f'read {obj}')
146
+ # return obj
147
+ return self.messages()
148
+ except Exception as error:
149
+ # print(f'Error reading stream: {error}')
150
+ traceback.print_exc()
151
+ os._exit(1)
152
+
153
+ def read_required(self, required):
154
+ obj = self.readnext()
155
+ if obj != required:
156
+ if self.last_matching_stack:
157
+ for line in self.last_matching_stack:
158
+ print(line)
159
+
160
+ print('---------------------------------')
161
+ print(f'Replay: {required}')
162
+ print('---------------------------------')
163
+ print(f'Record: {obj}')
164
+ print('---------------------------------')
165
+ for i in range(15):
166
+ print(self.readnext())
167
+
168
+ breakpoint()
169
+ os._exit(1)
170
+ raise Exception(f'Expected: {required} but got: {obj}')
171
+
172
+ self.last_matching_stack = utils.stacktrace()
173
+
174
+ def trace_writer(self, name, *args):
175
+ with self.thread_state.select('disabled'):
176
+ # read = self.messages_read
177
+
178
+ self.read_required('TRACE')
179
+ # self.read_required(read)
180
+ self.read_required(name)
181
+
182
+ if name == 'stacktrace':
183
+ record = self.readnext()
184
+ if args[0] == record:
185
+ self.last_matching_stack = args[0]
186
+ else:
187
+ on_stack_mismatch(
188
+ last_matching = self.last_matching_stack,
189
+ record = record,
190
+ replay = args[0])
191
+ os._exit(1)
192
+ else:
193
+ # print(f'Trace: {self.reader.messages_read} {name} {args}')
194
+ for arg in args:
195
+ self.read_required(arg)
196
+
197
+ def sync(self, function):
198
+ return utils.observer(on_call = functional.always(self.read_sync), function = function)
199
+
155
200
  def __init__(self,
156
201
  thread_state,
157
202
  immutable_types,
@@ -159,152 +204,29 @@ class ReplayProxySystem(ProxySystem):
159
204
  path,
160
205
  fork_path = []):
161
206
 
162
- # self.writer = writer
163
- # super().__init__(thread_state = thread_state)
164
- reader = stream.reader(path)
207
+ # self.messages_read = 0
208
+ self.reader = stream.reader(path)
165
209
 
166
210
  self.bindings = utils.id_dict()
167
211
  self.set_thread_id = utils.set_thread_id
168
212
  self.fork_path = fork_path
169
213
  deserialize = functional.walker(self.bindings.get_else_key)
170
214
 
171
- self.messages = functional.sequence(per_thread_messages(reader), deserialize)
172
-
173
- self.stub_factory = StubFactory(thread_state = thread_state, next_result = self.next_result)
174
-
175
- # messages = reader
176
-
177
- def readnext():
178
- with thread_state.select('disabled'):
179
- try:
180
- return self.messages()
181
- except Exception as error:
182
- # print(f'Error reading stream: {error}')
183
- traceback.print_exc()
184
-
185
- os._exit(1)
186
-
187
- # print(f'read: {obj}')
188
- # return obj
189
-
190
-
191
- # lookup = weakref.WeakKeyDictionary()
215
+ # def count(res):
216
+ # self.messages_read += 1
217
+ # return res
192
218
 
193
- # debug = debug_level(config)
194
-
195
- # int_refs = {}
196
- last_matching_stack = None
197
-
198
- def read_required(required):
199
- obj = readnext()
200
- if obj != required:
201
- if last_matching_stack:
202
- for line in last_matching_stack:
203
- print(line)
204
-
205
- print('---------------------------------')
206
- print(f'Replay: {required}')
207
- print('---------------------------------')
208
- print(f'Record: {obj}')
209
- print('---------------------------------')
210
- for i in range(5):
211
- print(readnext())
212
-
213
- utils.sigtrap(None)
214
- os._exit(1)
215
- raise Exception(f'Expected: {required} but got: {obj}')
216
-
217
- def trace_writer(name, *args):
218
- with thread_state.select('disabled'):
219
- read_required('TRACE')
220
- read_required(name)
221
-
222
- if name == 'stacktrace':
223
- record = readnext()
224
- if args[0] == record:
225
- nonlocal last_matching_stack
226
- last_matching_stack = args[0]
227
- else:
228
- on_stack_mismatch(
229
- last_matching= last_matching_stack,
230
- record = record,
231
- replay = args[0])
232
- os._exit(1)
233
- else:
234
- print(f'Trace: {name} {args}')
235
- for arg in args:
236
- read_required(arg)
237
-
238
- # self.tracer = Tracer(tracing_config, writer = trace_writer)
239
- # self.immutable_types = immutable_types
240
-
241
- self.reader = reader
242
-
243
- # def foo(cls):
244
- # print(cls)
245
- # assert isinstance(cls, type)
246
- # immutable_types.add(cls)
247
-
248
- # add_stubtype = functional.side_effect(foo)
249
- # add_stubtype = functional.side_effect(immutable_types.add)
250
-
251
- # reader.type_deserializer[ProxyRef] = functional.sequence(lambda ref: ref.resolve(), self.stubtype, add_stubtype)
252
-
253
- reader.type_deserializer[StubRef] = self.stub_factory
254
- # reader.type_deserializer[ProxySpec] = functional.sequence(self.stubtype_from_spec, add_stubtype)
219
+ self.messages = functional.sequence(per_thread_messages(self.reader),
220
+ deserialize)
255
221
 
256
- # on_ext_result = functional.if_then_else(
257
- # functional.is_instanceof(str), writer.handle('RESULT'), writer)
258
-
259
- # def int_proxytype(gateway):
260
- # return lambda cls: dynamic_int_proxytype(handler = gateway, cls = cls, bind = self.bind)
261
-
262
- # create_stubs = functional.walker(functional.when(is_stub_ref, lambda stub: stub.create()))
263
- # create_stubs = functional.walker(functional.when(is_stub_type, lambda cls: cls()))
222
+ self.stub_factory = StubFactory(thread_state = thread_state, next_result = self.next_result)
264
223
 
265
- # self.ext_apply = functional.repeatedly(functional.sequence(self.next_result, create_stubs))
266
- # self.ext_apply = functional.repeatedly(self.next_result)
267
-
268
- def read_sync(): read_required('SYNC')
224
+ self.last_matching_stack = None
269
225
 
270
- self.sync = lambda function: utils.observer(on_call = functional.always(read_sync), function = function)
226
+ self.reader.type_deserializer[StubRef] = self.stub_factory
227
+
228
+ self.read_sync = functional.always(lambda: self.read_required('SYNC'))
271
229
 
272
230
  super().__init__(thread_state = thread_state,
273
- tracer = Tracer(tracing_config, writer = trace_writer),
231
+ tracer = Tracer(tracing_config, writer = self.trace_writer),
274
232
  immutable_types = immutable_types)
275
-
276
- # super().__init__(
277
- # thread_state=thread_state,
278
- # immutable_types= immutable_types,
279
- # tracer=self.tracer,
280
- # ext_apply = ext_apply)
281
-
282
- # self.ext_handler, self.int_handler = gateway_pair(
283
- # thread_state,
284
- # self.tracer,
285
- # immutable_types = immutable_types,
286
- # ext_apply = ext_apply,
287
- # int_proxytype = int_proxytype,
288
- # ext_proxytype = functional.identity)
289
-
290
- # def extend_type(self, base):
291
-
292
- # # ok, how to provide __getattr__ style access,
293
-
294
- # extended = extending_proxytype(
295
- # cls = base,
296
- # thread_state = self.thread_state,
297
- # int_handler = self.int_handler,
298
- # ext_handler = self.ext_handler,
299
- # on_subclass_new = self.bind,
300
- # is_stub = True)
301
-
302
- # self.immutable_types.add(extended)
303
- # # proxytype = extending_proxytype(base)
304
-
305
- # # make_extensible(cls = extended,
306
- # # int_handler = self.int_handler,
307
- # # ext_handler = self.ext_handler,
308
- # # on_new = self.reader.supply)
309
-
310
- # return extended
@@ -17,19 +17,15 @@ class StubRef:
17
17
  blacklist = ['__class__', '__dict__', '__module__', '__doc__', '__new__']
18
18
 
19
19
  methods = []
20
- members = []
21
20
 
22
21
  for key,value in cls.__dict__.items():
23
22
  if key not in blacklist:
24
23
  if utils.is_method_descriptor(value):
25
24
  methods.append(key)
26
- elif not key.startswith("__retrace"):
27
- members.append(key)
28
25
 
29
26
  self.name = cls.__name__
30
27
  self.module = cls.__module__
31
28
  self.methods = methods
32
- self.members = members
33
29
 
34
30
  # def __init__(self, module, name, methods, members):
35
31
  # self.name = name
@@ -38,7 +34,7 @@ class StubRef:
38
34
  # self.members = members
39
35
 
40
36
  def __str__(self):
41
- return f'StubRef(module = {self.module}, name = {self.name}, methods = {self.methods}, members = {self.members})'
37
+ return f'StubRef(module = {self.module}, name = {self.name}, methods = {self.methods})'
42
38
 
43
39
  def resolve(module, name):
44
40
  try:
@@ -103,7 +99,7 @@ class StubFactory:
103
99
  next_result = self.thread_state.dispatch(disabled, external = self.next_result)
104
100
 
105
101
  return StubMemberDescriptor(name = name, next_result = next_result)
106
-
102
+
107
103
  def create_method(self, name):
108
104
 
109
105
  def disabled(*args, **kwargs):
@@ -133,8 +129,24 @@ class StubFactory:
133
129
  slots[method] = self.create_method(method)
134
130
  assert utils.is_method_descriptor(slots[method])
135
131
 
136
- for member in spec.members:
137
- slots[member] = self.create_member(member)
132
+ def getattr(instance, name):
133
+ if self.thread_state.value == 'external':
134
+ return self.next_result()
135
+ else:
136
+ print(f'Error trying to get attribute: {name}, when retrace mode: {self.thread_state.value} was not external')
137
+ utils.sigtrap(None)
138
+ os._exit(1)
139
+
140
+ def setattr(instance, name, value):
141
+ if self.thread_state.value == 'external':
142
+ return self.next_result()
143
+ else:
144
+ print(f'Error trying to set attribute: {name}, to: {value} when retrace mode: {self.thread_state.value} was not external')
145
+ utils.sigtrap(None)
146
+ os._exit(1)
147
+
148
+ slots['__getattr__'] = getattr
149
+ slots['__setattr__'] = setattr
138
150
 
139
151
  resolved = resolve(spec.module, spec.name)
140
152
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: retracesoftware_proxy
3
- Version: 0.1.7
3
+ Version: 0.1.9
4
4
  License: Apache-2.0
5
5
  Requires-Dist: retracesoftware_utils
6
6
  Requires-Dist: retracesoftware_functional
@@ -1,27 +1,27 @@
1
1
  retracesoftware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- retracesoftware/config.json,sha256=fzfxZF6ES2NuPO9u9fNX8xMZ5rKZStxAHovsVTSJYzs,8276
2
+ retracesoftware/config.json,sha256=c-bqr6SAuIGpnNRqZLPKW-0-VtG8VyGnqpQPhyc5CFY,8666
3
3
  retracesoftware/install/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  retracesoftware/install/config.py,sha256=EzE5ifQF2lo--hu2njI4T0FJ-zlnWDJV6i7x0DMkVTw,1364
5
5
  retracesoftware/install/edgecases.py,sha256=NR3lyvad9sRsyeDv_Ya8V4xMgPsMPOi9rMcnFOJGOEA,6330
6
6
  retracesoftware/install/globals.py,sha256=F8XvIoZQQ10gSRalk30dvdKllxlwxkaggYY6FogLDxY,510
7
7
  retracesoftware/install/install.py,sha256=HCD_ji8XCr96b5fNzNdL_8qcEp0Jf05Em7T6GA6u8HU,4969
8
- retracesoftware/install/patcher.py,sha256=5tRC8XmJW0_loqX1Nqad1rkG--LlX46YwgbbMTbgASc,17598
8
+ retracesoftware/install/patcher.py,sha256=VXYzE01SyDDw3wQ-spZRb5HEcH3MOlod56039zhpJIE,18888
9
9
  retracesoftware/install/predicate.py,sha256=tX7NQc0rGkyyHYO3mduYHcJHbw1wczT53m_Dpkzo6do,2679
10
10
  retracesoftware/install/record.py,sha256=tseF_jV4k4HLPTgBPJdjcahl4EQqagoiisMAdGNC52Q,3257
11
11
  retracesoftware/install/references.py,sha256=A-G651IDOfuo00MkbAdpbIQh_15ChvJ7uAVTSmE6zd4,1721
12
12
  retracesoftware/install/replay.py,sha256=VUiHvQK3mgAJEGmtE2TFs9kXzxdWtsjibEcGkhZVCVE,1830
13
- retracesoftware/install/tracer.py,sha256=Oqh8BhZVQVo1COfSGkFCipZGPB2Dv1b4DK3xBvloRew,4796
13
+ retracesoftware/install/tracer.py,sha256=cHEjiVxIp2iVTJEWndwSbMuiXVyGJQxJYZSGrfpSbCw,5723
14
14
  retracesoftware/install/typeutils.py,sha256=_a1PuwdCsYjG1Nkd77V-flqYtwbD4RkJVKn6Z-xABL4,1813
15
15
  retracesoftware/proxy/__init__.py,sha256=ZlDZIuUmKFsE9Tvfd2EKGabTepqv8nrbr5pQhCM3IKc,193
16
16
  retracesoftware/proxy/gateway.py,sha256=xESohWXkiNm4ZutU0RgWUwxjxcBWRQ4rQyxIGQXv_F4,1590
17
17
  retracesoftware/proxy/proxyfactory.py,sha256=qhOqDfMJnLDNkQs26JqDB431MwjjRhGQi8xupJ45asg,12272
18
- retracesoftware/proxy/proxysystem.py,sha256=W2v0Tj0tJeAt_bg9LljQm2iwWpjNIbqUTQ92WK22TF8,6861
19
- retracesoftware/proxy/proxytype.py,sha256=mcg3hBG0auYXv7Dez8SwrrG5dNlDl7nH_mdQUd9Iaj4,12488
20
- retracesoftware/proxy/record.py,sha256=ZsJV0o-Qy874VFObtsfkSF8u9gvyUSee0UPpf9Jq6Es,7734
21
- retracesoftware/proxy/replay.py,sha256=RVsezEZcy4bFdPQAAztfEHz6adm8t5lBDMhpnNAqeok,10510
22
- retracesoftware/proxy/stubfactory.py,sha256=UnRDQHgWv2xTYaMPZPXvsa7WBh10CyItc_hsQdtOhcM,4607
18
+ retracesoftware/proxy/proxysystem.py,sha256=Nf_yKa4gMvKA2RWEUBmyH9m46lbsAdyPzj5jVDh4cs8,7427
19
+ retracesoftware/proxy/proxytype.py,sha256=crq7idJP77Magtv58l_uJCAlTnD2aDTT-Uz14raTSIo,12767
20
+ retracesoftware/proxy/record.py,sha256=vtNsoTHP5gsBVJ6dTGHR7QXHGbKm0eONfGcXOb9fhFk,4696
21
+ retracesoftware/proxy/replay.py,sha256=m4Buxlix09aUJX9JYWG1z4jW8Yvbo2zBV353hsZE5qY,7670
22
+ retracesoftware/proxy/stubfactory.py,sha256=CnP0Sm0tZNwyFIQIPkk7w_soNBDcflNKwICsAoZxSD0,5128
23
23
  retracesoftware/proxy/thread.py,sha256=-SvnyVbANkmX2lLRpOvFtkpdpAoF6DhnnYdOOs7Q8vo,1379
24
- retracesoftware_proxy-0.1.7.dist-info/METADATA,sha256=Ug25Z8ULRbcvl7o9RQgSjcQzKC8HDqJhLQ3Z69wLHZc,202
25
- retracesoftware_proxy-0.1.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
26
- retracesoftware_proxy-0.1.7.dist-info/top_level.txt,sha256=hYHsR6txLidmqvjBMITpIHvmJJbmoCAgr76-IpZPRz8,16
27
- retracesoftware_proxy-0.1.7.dist-info/RECORD,,
24
+ retracesoftware_proxy-0.1.9.dist-info/METADATA,sha256=yiJDDJYQ4XQhjSaQq4PPZaW1dH7SHtn7m-Dfbk_CrUs,202
25
+ retracesoftware_proxy-0.1.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
26
+ retracesoftware_proxy-0.1.9.dist-info/top_level.txt,sha256=hYHsR6txLidmqvjBMITpIHvmJJbmoCAgr76-IpZPRz8,16
27
+ retracesoftware_proxy-0.1.9.dist-info/RECORD,,