retracesoftware-proxy 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,133 +1,221 @@
1
1
  import retracesoftware.functional as functional
2
- import retracesoftware_utils as utils
2
+ import retracesoftware.utils as utils
3
+ import retracesoftware.stream as stream
3
4
 
4
- from retracesoftware.proxy.proxytype import dynamic_proxytype, superdict, is_descriptor, extending_proxytype, dynamic_int_proxytype, make_extensible
5
- from retracesoftware.proxy.gateway import gateway_pair
5
+ from retracesoftware.proxy.proxytype import *
6
+ # from retracesoftware.proxy.gateway import gateway_pair
6
7
  from retracesoftware.proxy.proxysystem import ProxySystem
8
+ from retracesoftware.proxy.thread import write_thread_switch
9
+ from retracesoftware.install.tracer import Tracer
10
+ from retracesoftware.proxy.stubfactory import StubRef, ExtendedRef
7
11
 
8
12
  import sys
13
+ import os
14
+ import types
15
+ import gc
9
16
 
10
- class ExtendedProxy:
11
- __slots__ = []
17
+ class Placeholder:
18
+ __slots__ = ['id', '__weakref__']
12
19
 
13
- class ProxyRef:
14
- def __init__(self, module, name):
15
- self.module = module
16
- self.name = name
17
-
18
- def resolve(self):
19
- return getattr(sys.modules[self.module], self.name)
20
-
21
- class ProxySpec(ProxyRef):
22
- def __init__(self, module, name, methods, members):
23
- super().__init__(module, name)
24
- self.methods = methods
25
- self.members = members
26
-
27
- def __str__(self):
28
- return f'ProxySpec(module = {self.module}, name = {self.name}, methods = {self.methods}, members = {self.members})'
20
+ def __init__(self, id):
21
+ self.id = id
29
22
 
30
23
  def keys_where_value(pred, dict):
31
24
  for key,value in dict.items():
32
25
  if pred(value): yield key
33
26
 
27
+ types_lookup = {v:k for k,v in types.__dict__.items() if isinstance(v, type)}
28
+
29
+ def resolve(obj):
30
+ try:
31
+ return getattr(sys.modules[obj.__module__], obj.__name__)
32
+ except:
33
+ return None
34
+
34
35
  def resolveable(obj):
35
36
  try:
36
37
  return getattr(sys.modules[obj.__module__], obj.__name__) is obj
37
38
  except:
38
39
  return False
40
+
41
+ def resolveable_name(obj):
42
+ if obj in types_lookup:
43
+ return ('types', types_lookup[obj])
44
+ elif resolve(obj) is obj:
45
+ return (obj.__module__, obj.__name__)
46
+ else:
47
+ return None
48
+
49
+ # when
50
+ class RecordProxySystem(ProxySystem):
39
51
 
40
- class ExtProxytype:
52
+ def bind(self, obj):
53
+ self.bindings[obj] = self.writer.handle(Placeholder(self.next_placeholder_id))
54
+ self.writer(self.bindings[obj])
55
+ self.next_placeholder_id += 1
56
+
57
+ def before_fork(self):
58
+ self.writer.close()
59
+ super().before_fork()
60
+ # self.writer.path = self.dynamic_path
61
+
62
+ def after_fork_in_child(self):
63
+ new_path = self.new_child_path(self.writer.path)
64
+ new_path.parent.mkdir()
65
+ self.writer.path = new_path
66
+ super().after_fork_in_child()
67
+
68
+ def after_fork_in_parent(self):
69
+ super().after_fork_in_parent()
70
+ self.thread_state.value = self.saved_thread_state
71
+ self.writer.reopen()
72
+
73
+ def __init__(self, thread_state,
74
+ immutable_types,
75
+ tracing_config,
76
+ path):
77
+
78
+ self.fork_counter = 0
79
+
80
+ self.getpid = thread_state.wrap(
81
+ desired_state = 'disabled', function = os.getpid)
82
+
83
+ self.pid = self.getpid()
41
84
 
42
- def __init__(self, gateway, extended_types, writer):
43
- self.gateway = gateway
44
- self.writer = writer
45
- self.extended_types = extended_types
85
+ self.writer = stream.writer(path)
86
+
87
+ w = self.writer.handle('TRACE')
88
+ def trace_writer(*args):
89
+ print(f'Trace: {args}')
90
+ w(*args)
46
91
 
47
- def __call__(self, cls):
48
- assert isinstance(cls, type)
92
+ self.extended_types = {}
93
+ self.bindings = utils.id_dict()
94
+ self.next_placeholder_id = 0
49
95
 
50
- if cls in self.extended_types:
51
- return functional.side_effect(lambda obj: utils.set_type(obj, self.extended_types[cls]))
52
- else:
53
- if resolveable(cls):
54
- ref = self.writer.handle(ProxyRef(name = cls.__name__, module = cls.__module__))
55
- else:
56
- blacklist = ['__getattribute__']
57
- descriptors = {k: v for k,v in superdict(cls).items() if k not in blacklist and is_descriptor(v) }
58
-
59
- methods = [k for k, v in descriptors.items() if utils.is_method_descriptor(v)]
60
- members = [k for k, v in descriptors.items() if not utils.is_method_descriptor(v)]
61
-
62
- ref = self.writer.handle(ProxySpec(name = cls.__name__,
63
- module = cls.__module__,
64
- methods = methods,
65
- members = members))
96
+ serialize = functional.walker(self.bindings.get_else_key)
97
+
98
+ thread_switch_monitor = \
99
+ utils.thread_switch_monitor(
100
+ functional.repeatedly(functional.sequence(utils.thread_id, self.writer)))
101
+
102
+ self.sync = lambda function: functional.firstof(thread_switch_monitor, functional.always(self.writer.handle('SYNC')), function)
66
103
 
67
- proxytype = dynamic_proxytype(handler = self.gateway, cls = cls)
104
+ error = self.writer.handle('ERROR')
68
105
 
69
- self.writer.type_serializer[proxytype] = functional.constantly(ref)
70
- return proxytype
106
+ def write_error(cls, val, traceback):
107
+ error(cls, val)
71
108
 
109
+ self.set_thread_id = functional.partial(utils.set_thread_id, self.writer)
72
110
 
73
- # when
74
- class RecordProxySystem(ProxySystem):
75
-
76
- def __init__(self, thread_state, immutable_types, tracer, writer):
77
- super().__init__(thread_state = thread_state)
111
+ def watch(f): return functional.either(thread_switch_monitor, f)
78
112
 
79
- self.immutable_types = immutable_types
113
+ tracer = Tracer(tracing_config, writer = trace_writer)
80
114
 
81
- self.extended_types = {}
82
- self.writer = writer
83
- self.bind = writer.placeholder
115
+ self.wrap_int_to_ext = watch
116
+
117
+ self.on_int_call = functional.mapargs(transform = serialize, function = self.writer.handle('CALL'))
118
+
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_error = write_error
84
125
 
85
- # on_ext_result = writer.handle('RESULT')
86
- on_ext_result = functional.if_then_else(
87
- functional.isinstanceof(str), writer.handle('RESULT'), writer)
126
+ self.ext_apply = self.int_apply = functional.apply
88
127
 
89
- def int_proxytype(gateway):
90
- return lambda cls: dynamic_int_proxytype(handler = gateway, cls = cls, bind = self.bind)
128
+ super().__init__(thread_state = thread_state, tracer = tracer, immutable_types = immutable_types)
129
+
130
+ def dynamic_ext_proxytype(self, cls):
91
131
 
92
- def ext_proxytype(gateway):
93
- return ExtProxytype(gateway = gateway, writer = writer, extended_types = self.extended_types)
94
-
95
- error = writer.handle('ERROR')
132
+ proxytype = super().dynamic_ext_proxytype(cls)
96
133
 
97
- def write_error(cls, val, traceback):
98
- error(cls, val)
134
+ blacklist = ['__class__', '__dict__', '__module__', '__doc__']
99
135
 
100
- self.ext_handler, self.int_handler = gateway_pair(
101
- thread_state,
102
- tracer,
103
- immutable_types = immutable_types,
104
- int_proxytype = int_proxytype,
105
- ext_proxytype = ext_proxytype,
106
- on_int_call = writer.handle('CALL'),
107
- on_ext_result = functional.side_effect(on_ext_result),
108
- on_ext_error = write_error)
109
-
110
- def extend_type(self, base):
111
-
112
- if base in self.extended_types:
113
- return self.extended_types[base]
114
-
115
- # self.tracer.log('proxy.ext.new.extended', f'{base.__module__}.{base.__name__}')
116
-
117
- extended = extending_proxytype(
118
- cls = base,
119
- thread_state = self.thread_state,
120
- ext_handler = self.ext_handler,
121
- int_handler = self.int_handler,
122
- on_subclass_new = self.bind,
123
- is_stub = False)
136
+ methods = []
137
+ members = []
138
+
139
+ for key,value in proxytype.__dict__.items():
140
+ if key not in blacklist:
141
+ if utils.is_method_descriptor(value):
142
+ methods.append(key)
143
+ elif not key.startswith("__retrace"):
144
+ members.append(key)
145
+
146
+ ref = self.writer.handle(StubRef(
147
+ name = cls.__name__,
148
+ module = cls.__module__,
149
+ methods = methods,
150
+ members = members))
124
151
 
125
- ref = self.writer.handle(ProxyRef(name = base.__name__, module = base.__module__,))
126
- self.writer.type_serializer[extended] = functional.constantly(ref)
152
+ # list(proxytype.__dict__.keys())
153
+
154
+ # if resolveable_name(cls):
155
+ # module, name = resolveable_name(cls)
156
+ # ref = self.writer.handle(StubRef(type = 'dynamic', name = name, module = module))
157
+ # else:
158
+ # blacklist = ['__getattribute__']
159
+ # descriptors = {k: v for k,v in superdict(cls).items() if k not in blacklist and is_descriptor(v) }
160
+
161
+ # methods = [k for k, v in descriptors.items() if utils.is_method_descriptor(v)]
162
+ # members = [k for k, v in descriptors.items() if not utils.is_method_descriptor(v)]
163
+
164
+ # ref = self.writer.handle(ProxySpec(name = cls.__name__,
165
+ # module = cls.__module__,
166
+ # methods = methods,
167
+ # members = members))
168
+
169
+ self.writer.type_serializer[proxytype] = functional.constantly(ref)
170
+
171
+ return proxytype
172
+
173
+ def ext_proxytype(self, cls):
174
+ assert isinstance(cls, type), f"record.proxytype requires a type but was passed: {cls}"
175
+
176
+ # resolved = resolve(cls)
177
+
178
+ proxytype = super().ext_proxytype(cls)
179
+
180
+ assert resolve(cls) is cls
181
+
182
+ # ref = self.writer.handle(StubRef(name = cls.__name__,
183
+ # module = cls.__module__))
184
+
185
+ # if resolveable_name(cls):
186
+ # module, name = resolveable_name(cls)
187
+ # ref = self.writer.handle(StubRef(name = cls.__name__, module = cls.__module__))
188
+ # else:
189
+ # blacklist = ['__getattribute__']
190
+ # descriptors = {k: v for k,v in superdict(cls).items() if k not in blacklist and is_descriptor(v) }
191
+
192
+ # methods = [k for k, v in descriptors.items() if utils.is_method_descriptor(v)]
193
+ # members = [k for k, v in descriptors.items() if not utils.is_method_descriptor(v)]
194
+
195
+ # ref = self.writer.handle(ProxySpec(name = cls.__name__,
196
+ # module = cls.__module__,
197
+ # methods = methods,
198
+ # members = members))
199
+
200
+ # self.writer.type_serializer[proxytype] = functional.constantly(ref)
201
+ return proxytype
202
+
203
+
204
+ def extend_type(self, cls):
205
+
206
+ if cls in self.extended_types:
207
+ return self.extended_types[cls]
208
+
209
+ extended = super().extend_type(cls)
127
210
 
128
- # make_extensible(cls = extended, handler = self.int_handler, on_new = self.writer.placeholder)
211
+ self.extended_types[cls] = extended
129
212
 
130
- self.immutable_types.add(extended)
131
- self.extended_types[base] = extended
213
+ ref = self.writer.handle(ExtendedRef(name = cls.__name__,
214
+ module = cls.__module__))
215
+
216
+ # for binding?
217
+ # self.writer(ref)
218
+
219
+ self.writer.type_serializer[extended] = functional.constantly(ref)
132
220
 
133
221
  return extended
@@ -1,43 +1,55 @@
1
1
  import retracesoftware.functional as functional
2
2
  import retracesoftware_utils as utils
3
+ import retracesoftware.stream as stream
3
4
 
4
- from retracesoftware.proxy.proxytype import dynamic_proxytype, dynamic_int_proxytype, extending_proxytype, make_extensible, dynamic_stubtype, stubtype_from_spec, Stub
5
- from retracesoftware.proxy.gateway import gateway_pair
6
-
7
- from retracesoftware.proxy.record import ProxyRef, ProxySpec
8
- from retracesoftware.proxy.proxysystem import ProxySystem
5
+ from retracesoftware.install.tracer import Tracer
6
+ from retracesoftware.proxy.thread import per_thread_messages
7
+ from retracesoftware.proxy.proxytype import *
8
+ # from retracesoftware.proxy.gateway import gateway_pair
9
+ from retracesoftware.proxy.record import StubRef, Placeholder
10
+ from retracesoftware.proxy.proxysystem import ProxySystem, RetraceError
11
+ from retracesoftware.proxy.stubfactory import StubFactory, StubFunction
9
12
 
10
13
  import os
11
-
14
+ import weakref
15
+ import traceback
12
16
  # we can have a dummy method descriptor, its has a __name__ and when called, returns the next element
13
17
 
14
18
  # for types, we can patch the __new__ method
15
19
  # do it from C and immutable types can be patched too
16
20
  # patch the tp_new pointer?
17
21
 
22
+ class ReplayError(RetraceError):
23
+ pass
24
+
18
25
  class ReplayProxySystem(ProxySystem):
19
26
 
20
27
  def stubtype(self, cls):
28
+ print(f'In stubtype, class: {cls}')
29
+ assert not issubclass(cls, Proxy)
30
+
21
31
  return dynamic_proxytype(handler = self.ext_handler, cls = cls)
22
32
 
23
- def stubtype_from_spec(self, spec):
24
- print (f'FOOO!!! {spec}')
25
- return stubtype_from_spec(
26
- handler = self.ext_handler,
27
- module = spec.module,
28
- name = spec.name,
29
- methods = spec.methods,
30
- members = spec.members)
33
+ def create_stub(self): return True
34
+
35
+ # def stubtype_from_spec(self, spec):
36
+ # print (f'FOOO!!! {spec}')
37
+ # return stubtype_from_spec(
38
+ # handler = self.ext_handler,
39
+ # module = spec.module,
40
+ # name = spec.name,
41
+ # methods = spec.methods,
42
+ # members = spec.members)
31
43
 
32
44
  @utils.striptraceback
33
45
  def next_result(self):
34
46
  while True:
35
- next = self.reader()
47
+ next = self.messages()
36
48
 
37
49
  if next == 'CALL':
38
- func = self.reader()
39
- args = self.reader()
40
- kwargs = self.reader()
50
+ func = self.messages()
51
+ args = self.messages()
52
+ kwargs = self.messages()
41
53
 
42
54
  try:
43
55
  func(*args, **kwargs)
@@ -45,66 +57,178 @@ class ReplayProxySystem(ProxySystem):
45
57
  pass
46
58
 
47
59
  elif next == 'RESULT':
48
- return self.reader()
60
+ return self.messages()
49
61
  elif next == 'ERROR':
50
- err_type = self.reader()
51
- err_value = self.reader()
62
+ err_type = self.messages()
63
+ err_value = self.messages()
52
64
  utils.raise_exception(err_type, err_value)
53
65
  else:
54
- assert not isinstance(next, str)
66
+ if type(next) is str: print('FOOBAR!!!!')
67
+ assert type(next) is not str
55
68
  return next
56
69
 
57
- def __init__(self, thread_state, immutable_types, tracer, reader):
70
+ def bind(self, obj):
71
+ read = self.messages()
72
+
73
+ assert isinstance(read, Placeholder)
74
+
75
+ self.bindings[read] = obj
76
+
77
+ # def dynamic_path(self):
78
+ # if self.getpid() != self.pid:
79
+ # self.pid = self.getpid()
80
+ # # ok we are in child, calculate new path
81
+ # self.path = self.path / f'fork-{self.fork_counter}'
82
+ # self.fork_counter = 0
83
+
84
+ # return self.path
85
+
86
+ def after_fork_in_child(self):
87
+ self.reader.path = self.new_child_path(self.reader.path)
88
+ super().after_fork_in_child()
89
+
90
+ # def dynamic_ext_proxytype(self, cls):
91
+ # raise Exception('dynamic_ext_proxytype should not be called in replay')
92
+
93
+ def proxy_function(self, obj):
94
+ func = functional.repeatedly(self.next_result)
95
+ func.__name__ = obj.__name__
96
+
97
+ return super().proxy_function(func)
98
+
99
+ def __init__(self,
100
+ thread_state,
101
+ immutable_types,
102
+ tracing_config,
103
+ path,
104
+ fork_path = []):
105
+
58
106
  # self.writer = writer
59
- super().__init__(thread_state = thread_state)
60
- self.immutable_types = immutable_types
107
+ # super().__init__(thread_state = thread_state)
108
+ reader = stream.reader(path)
109
+
110
+ self.bindings = utils.id_dict()
111
+ self.set_thread_id = utils.set_thread_id
112
+ self.fork_path = fork_path
113
+ deserialize = functional.walker(self.bindings.get_else_key)
114
+
115
+ self.messages = functional.sequence(per_thread_messages(reader), deserialize)
116
+
117
+ self.stub_factory = StubFactory(thread_state = thread_state, next_result = self.next_result)
118
+
119
+ # messages = reader
120
+
121
+ def readnext():
122
+ with thread_state.select('disabled'):
123
+ try:
124
+ return self.messages()
125
+ except Exception as error:
126
+ # print(f'Error reading stream: {error}')
127
+ traceback.print_exc()
128
+
129
+ os._exit(1)
130
+
131
+ # print(f'read: {obj}')
132
+ # return obj
133
+
134
+
135
+ # lookup = weakref.WeakKeyDictionary()
136
+
137
+ # debug = debug_level(config)
138
+
139
+ # int_refs = {}
140
+
141
+ def read_required(required):
142
+ obj = readnext()
143
+ if obj != required:
144
+ print(f'Replay: {required} Record: {obj}')
145
+ for i in range(5):
146
+ print(readnext())
147
+
148
+ utils.sigtrap(None)
149
+ os._exit(1)
150
+ raise Exception(f'Expected: {required} but got: {obj}')
151
+
152
+ def trace_writer(name, *args):
153
+ with thread_state.select('disabled'):
154
+ print(f'Trace: {name} {args}')
155
+
156
+ read_required('TRACE')
157
+ read_required(name)
158
+
159
+ for arg in args:
160
+ read_required(arg)
161
+
162
+ # self.tracer = Tracer(tracing_config, writer = trace_writer)
163
+ # self.immutable_types = immutable_types
164
+
61
165
  self.reader = reader
62
- self.bind = self.reader.supply
63
166
 
64
- add_stubtype = functional.side_effect(immutable_types.add)
167
+ # def foo(cls):
168
+ # print(cls)
169
+ # assert isinstance(cls, type)
170
+ # immutable_types.add(cls)
171
+
172
+ # add_stubtype = functional.side_effect(foo)
173
+ # add_stubtype = functional.side_effect(immutable_types.add)
174
+
175
+ # reader.type_deserializer[ProxyRef] = functional.sequence(lambda ref: ref.resolve(), self.stubtype, add_stubtype)
65
176
 
66
- reader.type_deserializer[ProxyRef] = functional.sequence(lambda ref: ref.resolve(), self.stubtype, add_stubtype)
67
- reader.type_deserializer[ProxySpec] = functional.sequence(self.stubtype_from_spec, add_stubtype)
177
+ reader.type_deserializer[StubRef] = self.stub_factory
178
+ # reader.type_deserializer[ProxySpec] = functional.sequence(self.stubtype_from_spec, add_stubtype)
68
179
 
69
180
  # on_ext_result = functional.if_then_else(
70
181
  # functional.is_instanceof(str), writer.handle('RESULT'), writer)
71
182
 
72
- def int_proxytype(gateway):
73
- return lambda cls: dynamic_int_proxytype(handler = gateway, cls = cls, bind = self.bind)
183
+ # def int_proxytype(gateway):
184
+ # return lambda cls: dynamic_int_proxytype(handler = gateway, cls = cls, bind = self.bind)
74
185
 
75
- def is_stub_type(obj):
76
- return functional.typeof(obj) is type and issubclass(obj, Stub)
186
+ # create_stubs = functional.walker(functional.when(is_stub_ref, lambda stub: stub.create()))
187
+ # create_stubs = functional.walker(functional.when(is_stub_type, lambda cls: cls()))
77
188
 
78
- create_stubs = functional.walker(functional.when(is_stub_type, lambda cls: cls()))
189
+ # self.ext_apply = functional.repeatedly(functional.sequence(self.next_result, create_stubs))
190
+ # self.ext_apply = functional.repeatedly(self.next_result)
191
+
192
+ def read_sync(): read_required('SYNC')
79
193
 
80
- ext_apply = functional.repeatedly(functional.sequence(self.next_result, create_stubs))
81
-
82
- self.ext_handler, self.int_handler = gateway_pair(
83
- thread_state,
84
- tracer,
85
- immutable_types = immutable_types,
86
- ext_apply = ext_apply,
87
- int_proxytype = int_proxytype,
88
- ext_proxytype = functional.identity)
89
-
90
- def extend_type(self, base):
194
+ self.sync = lambda function: utils.observer(on_call = functional.always(read_sync), function = function)
195
+
196
+ super().__init__(thread_state = thread_state,
197
+ tracer = Tracer(tracing_config, writer = trace_writer),
198
+ immutable_types = immutable_types)
199
+
200
+ # super().__init__(
201
+ # thread_state=thread_state,
202
+ # immutable_types= immutable_types,
203
+ # tracer=self.tracer,
204
+ # ext_apply = ext_apply)
205
+
206
+ # self.ext_handler, self.int_handler = gateway_pair(
207
+ # thread_state,
208
+ # self.tracer,
209
+ # immutable_types = immutable_types,
210
+ # ext_apply = ext_apply,
211
+ # int_proxytype = int_proxytype,
212
+ # ext_proxytype = functional.identity)
213
+
214
+ # def extend_type(self, base):
91
215
 
92
- # ok, how to provide __getattr__ style access,
216
+ # # ok, how to provide __getattr__ style access,
93
217
 
94
- extended = extending_proxytype(
95
- cls = base,
96
- thread_state = self.thread_state,
97
- int_handler = self.int_handler,
98
- ext_handler = self.ext_handler,
99
- on_subclass_new = self.bind,
100
- is_stub = True)
218
+ # extended = extending_proxytype(
219
+ # cls = base,
220
+ # thread_state = self.thread_state,
221
+ # int_handler = self.int_handler,
222
+ # ext_handler = self.ext_handler,
223
+ # on_subclass_new = self.bind,
224
+ # is_stub = True)
101
225
 
102
- self.immutable_types.add(extended)
103
- # proxytype = extending_proxytype(base)
226
+ # self.immutable_types.add(extended)
227
+ # # proxytype = extending_proxytype(base)
104
228
 
105
- # make_extensible(cls = extended,
106
- # int_handler = self.int_handler,
107
- # ext_handler = self.ext_handler,
108
- # on_new = self.reader.supply)
229
+ # # make_extensible(cls = extended,
230
+ # # int_handler = self.int_handler,
231
+ # # ext_handler = self.ext_handler,
232
+ # # on_new = self.reader.supply)
109
233
 
110
- return extended
234
+ # return extended