retracesoftware-proxy 0.1.0__py3-none-any.whl → 0.1.1__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,20 +1,181 @@
1
1
  import retracesoftware.functional as functional
2
2
  import retracesoftware_utils as utils
3
-
4
- from retracesoftware.proxy.proxytype import extending_proxytype, make_extensible
3
+ import types
4
+ from retracesoftware.proxy.gateway import adapter_pair1
5
+ from types import SimpleNamespace
6
+ from retracesoftware.proxy.proxytype import ExtendingProxy
7
+
8
+ from retracesoftware.proxy.proxytype import extending_proxytype, make_extensible, dynamic_proxytype, dynamic_int_proxytype, instantiable_dynamic_proxytype
9
+
10
+ def proxy(proxytype):
11
+ def set_type(cls, obj):
12
+ obj.__class__ = cls
13
+ return obj
14
+
15
+ def can_set_type(cls, obj): return issubclass(cls, ExtendingProxy)
16
+
17
+ create = functional.if_then_else(can_set_type, set_type, utils.create_wrapped)
18
+
19
+ return functional.spread(
20
+ create,
21
+ functional.sequence(functional.typeof, proxytype),
22
+ None)
23
+
24
+ def maybe_proxy(proxytype):
25
+ return functional.if_then_else(
26
+ functional.isinstanceof(utils.Wrapped),
27
+ utils.unwrap,
28
+ proxy(functional.memoize_one_arg(proxytype)))
29
+
30
+ unproxy_execute = functional.mapargs(starting = 1,
31
+ transform = functional.walker(utils.try_unwrap),
32
+ function = functional.apply)
5
33
 
6
34
  class ProxySystem:
7
35
 
8
- def __init__(self, thread_state):
36
+ def wrap_int_to_ext(self, obj): return obj
37
+ def wrap_ext_to_int(self, obj): return obj
38
+
39
+ def on_int_call(self, func, *args, **kwargs):
40
+ pass
41
+
42
+ def on_ext_result(self, result):
43
+ pass
44
+
45
+ def on_ext_error(self, err_type, err_value, err_traceback):
46
+ pass
47
+
48
+ def ext_apply(self, func, *args, **kwargs):
49
+ return func(*args, **kwargs)
50
+
51
+ def int_apply(self, func, *args, **kwargs):
52
+ return func(*args, **kwargs)
53
+
54
+ def __init__(self, thread_state, immutable_types, tracer):
55
+
9
56
  self.thread_state = thread_state
57
+ self.fork_counter = 0
58
+ self.tracer = tracer
59
+ self.immutable_types = immutable_types
60
+
61
+ def is_immutable_type(cls):
62
+ return issubclass(cls, tuple(immutable_types))
63
+
64
+ is_immutable = functional.sequence(functional.typeof, functional.memoize_one_arg(is_immutable_type))
65
+
66
+ def proxyfactory(proxytype):
67
+ return functional.walker(functional.when_not(is_immutable, maybe_proxy(proxytype)))
68
+
69
+ int_spec = SimpleNamespace(
70
+ proxytype = self.int_proxytype,
71
+ proxy = proxyfactory(self.int_proxytype),
72
+ on_call = tracer('proxy.int.call', self.on_int_call),
73
+ on_result = tracer('proxy.int.result'),
74
+ on_error = tracer('proxy.int.error'),
75
+ apply = self.int_apply,
76
+ )
77
+
78
+ ext_spec = SimpleNamespace(
79
+ proxytype = self.ext_proxytype,
80
+ proxy = proxyfactory(self.ext_proxytype),
81
+ on_call = tracer('proxy.ext.call'),
82
+ on_result = self.on_ext_result,
83
+ on_error = self.on_ext_error,
84
+ apply = self.ext_apply
85
+ )
86
+
87
+ int2ext, ext2int = adapter_pair1(int_spec, ext_spec)
88
+
89
+ # self.ext_handler = thread_state.dispatch(default, internal = internal, external = external)
90
+
91
+ def gateway(name, internal = functional.apply, external = functional.apply):
92
+ default = tracer(name, unproxy_execute)
93
+ return thread_state.dispatch(default, internal = internal, external = external)
94
+
95
+ self.ext_handler = gateway('proxy.int.disabled.event', internal = self.wrap_int_to_ext(int2ext))
96
+ self.int_handler = gateway('proxy.ext.disabled.event', external = self.wrap_ext_to_int(ext2int))
97
+
98
+ # return (gateway('proxy.int.disabled.event', internal = wrap_int_to_ext(int_to_ext)),
99
+ # gateway('proxy.ext.disabled.event',
100
+ # external = tracer('proxy.ext_to_int.wrap', ext_to_int)))
101
+
102
+ # # def adapter_pair1(int, ext):
103
+
104
+
105
+ # self.ext_handler, self.int_handler = gateway_pair(
106
+ # thread_state,
107
+ # self.tracer,
108
+ # immutable_types = immutable_types,
109
+ # wrap_int_to_ext = wrap_int_to_ext,
110
+ # int_proxytype = self.int_proxytype,
111
+ # ext_proxytype = self.ext_proxytype,
112
+ # ext_apply = ext_apply,
113
+ # on_int_call = on_int_call,
114
+ # on_ext_result = on_ext_result,
115
+ # on_ext_error = on_ext_error)
116
+
117
+
118
+ def new_child_path(self, path):
119
+ return path.parent / f'fork-{self.fork_counter}' / path.name
120
+
121
+ def before_fork(self):
122
+ self.saved_thread_state = self.thread_state.value
123
+ self.thread_state.value = 'disabled'
124
+
125
+ def after_fork_in_child(self):
126
+ self.thread_state.value = self.saved_thread_state
127
+ self.fork_counter = 0
128
+
129
+ def after_fork_in_parent(self):
130
+ self.thread_state.value = self.saved_thread_state
131
+ self.fork_counter += 1
132
+
133
+ def create_stub(self): return False
134
+
135
+ def int_proxytype(self, cls):
136
+ return dynamic_int_proxytype(
137
+ handler = self.int_handler,
138
+ cls = cls,
139
+ bind = self.bind)
140
+
141
+ def ext_proxytype(self, cls):
142
+ assert isinstance(cls, type)
143
+ if utils.is_extendable(cls):
144
+ return self.extend_type(cls)
145
+ else:
146
+ return instantiable_dynamic_proxytype(
147
+ handler = self.ext_handler,
148
+ cls = cls,
149
+ thread_state = self.thread_state,
150
+ create_stub = self.create_stub())
151
+
152
+ def extend_type(self, base):
153
+
154
+ extended = extending_proxytype(
155
+ cls = base,
156
+ thread_state = self.thread_state,
157
+ ext_handler = self.ext_handler,
158
+ int_handler = self.int_handler,
159
+ on_subclass_new = self.bind,
160
+ is_stub = self.create_stub())
161
+
162
+ self.immutable_types.add(extended)
163
+
164
+ return extended
10
165
 
11
166
  def __call__(self, obj):
12
167
  assert not isinstance(obj, BaseException)
13
-
14
- if type(obj) == type and utils.is_extendable(obj):
15
- return self.extend_type(obj)
16
- elif callable(obj):
168
+ assert not isinstance(obj, utils.wrapped_function)
169
+
170
+ if type(obj) == type:
171
+ return self.ext_proxytype(obj)
172
+
173
+ elif type(obj) == types.BuiltinFunctionType:
17
174
  return utils.wrapped_function(handler = self.ext_handler, target = obj)
175
+
18
176
  else:
19
- raise Exception(f'object {obj} was not proxied as its not a extensible type and is not callable')
177
+ proxytype = dynamic_proxytype(handler = self.ext_handler, cls = type(obj))
178
+
179
+ return utils.create_wrapped(proxytype, obj)
180
+ # raise Exception(f'object {obj} was not proxied as its not a extensible type and is not callable')
20
181
 
@@ -112,7 +112,7 @@ def dynamic_proxytype(handler, cls):
112
112
 
113
113
  assert not issubclass(cls, BaseException)
114
114
 
115
- blacklist = ['__getattribute__', '__hash__', '__del__', '__init__', '__call__']
115
+ blacklist = ['__getattribute__', '__hash__', '__del__', '__call__']
116
116
 
117
117
  to_proxy = [m for m in methods(cls) if m not in blacklist]
118
118
 
@@ -128,13 +128,32 @@ def dynamic_proxytype(handler, cls):
128
128
 
129
129
  spec['__retrace_target_class__'] = cls
130
130
 
131
- target_type = functional.compose(utils.unwrap, functional.typeof)
131
+ target_type = functional.sequence(utils.unwrap, functional.typeof)
132
132
  spec['__class__'] = property(target_type)
133
-
133
+
134
134
  name = f'retrace.proxied.{cls.__module__}.{cls.__name__}'
135
135
 
136
136
  return type(name, (utils.Wrapped, DynamicProxy), spec)
137
137
 
138
+ def instantiable_dynamic_proxytype(handler, cls, thread_state, create_stub = False):
139
+
140
+ proxytype = dynamic_proxytype(handler = handler, cls = cls)
141
+
142
+ def create_original(proxytype, *args, **kwargs):
143
+ instance = cls(*args, **kwargs)
144
+ instance.__init__(*args, **kwargs)
145
+ return instance
146
+
147
+ def __new__(proxytype, *args, **kwargs):
148
+ print(f'instantiable_dynamic_proxytype: {cls}')
149
+
150
+ instance = utils.create_stub_object(cls) if create_stub else cls(*args, **kwargs)
151
+ return utils.create_wrapped(proxytype, instance)
152
+
153
+ proxytype.__new__ = thread_state.dispatch(create_original, internal = __new__)
154
+
155
+ return proxytype
156
+
138
157
  def dynamic_int_proxytype(handler, cls, bind):
139
158
  proxytype = dynamic_proxytype(handler = handler, cls = cls)
140
159
  proxytype.__new__ = functional.sequence(proxytype.__new__, functional.side_effect(bind))
@@ -163,7 +182,7 @@ class DescriptorProxy:
163
182
  return self.handler(deleter, self.name)
164
183
 
165
184
 
166
- blacklist = ['__getattribute__', '__hash__', '__del__']
185
+ blacklist = ['__getattribute__', '__hash__', '__del__', '__dict__']
167
186
 
168
187
  # if the type can be patched, thats better, all new instances must be of correct type
169
188
 
@@ -178,7 +197,7 @@ def extending_proxytype(cls, thread_state, ext_handler, int_handler, on_subclass
178
197
  proxy_method_descriptors(cls = subclass, handler = int_handler)
179
198
 
180
199
  if not issubclass(subclass, InternalProxy):
181
- subclass.__new__ = functional.compose(subclass.__new__, functional.side_effect(on_subclass_new))
200
+ subclass.__new__ = functional.sequence(subclass.__new__, functional.side_effect(on_subclass_new))
182
201
  subclass.__bases__ = subclass.__bases__ + (InternalProxy,)
183
202
 
184
203
  slots = { "__slots__": (), "__init_subclass__": init_subclass }
@@ -202,14 +221,6 @@ def extending_proxytype(cls, thread_state, ext_handler, int_handler, on_subclass
202
221
  proxy = DescriptorProxy(handler = ext_handler, name = name, proxytype = extended)
203
222
  setattr(extended, name, proxy)
204
223
 
205
- # def disabled__new__(subcls, *args, **kwargs):
206
- # print('IN Diabled new!!!')
207
-
208
- # instance = cls.__new__(subcls.__retrace_unproxied__, *args, **kwargs)
209
- # instance.__init__(*args, **kwargs)
210
- # return instance
211
-
212
- # __new__ = functional.compose(cls.__new__, functional.side_effect(on_new))
213
224
  if is_stub:
214
225
  def __new__(cls, *args, **kwargs):
215
226
  instance = utils.create_stub_object(cls)
@@ -1,11 +1,21 @@
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, superdict, is_descriptor, extending_proxytype, dynamic_int_proxytype, make_extensible
5
- from retracesoftware.proxy.gateway import gateway_pair
5
+ from retracesoftware.proxy.proxytype import dynamic_proxytype, superdict, is_descriptor, extending_proxytype, dynamic_int_proxytype, make_extensible, Proxy
6
+ # from retracesoftware.proxy.gateway import gateway_pair
6
7
  from retracesoftware.proxy.proxysystem import ProxySystem
7
-
8
+ from retracesoftware.proxy.thread import write_thread_switch
9
+ from retracesoftware.install.tracer import Tracer
8
10
  import sys
11
+ import os
12
+ import types
13
+
14
+ class Placeholder:
15
+ __slots__ = ['id', '__weakref__']
16
+
17
+ def __init__(self, id):
18
+ self.id = id
9
19
 
10
20
  class ExtendedProxy:
11
21
  __slots__ = []
@@ -31,103 +41,184 @@ def keys_where_value(pred, dict):
31
41
  for key,value in dict.items():
32
42
  if pred(value): yield key
33
43
 
44
+ types_lookup = {v:k for k,v in types.__dict__.items() if isinstance(v, type)}
45
+
46
+ def resolve(obj):
47
+ try:
48
+ return getattr(sys.modules[obj.__module__], obj.__name__)
49
+ except:
50
+ return None
51
+
34
52
  def resolveable(obj):
35
53
  try:
36
54
  return getattr(sys.modules[obj.__module__], obj.__name__) is obj
37
55
  except:
38
56
  return False
57
+
58
+ def resolveable_name(obj):
59
+ if obj in types_lookup:
60
+ return ('types', types_lookup[obj])
61
+ elif resolve(obj) is obj:
62
+ return (obj.__module__, obj.__name__)
63
+ else:
64
+ return None
65
+
66
+ # when
67
+ class RecordProxySystem(ProxySystem):
39
68
 
40
- class ExtProxytype:
69
+ def bind(self, obj):
70
+ self.bindings[obj] = self.writer.handle(Placeholder(self.next_placeholder_id))
71
+ self.writer(self.bindings[obj])
72
+ self.next_placeholder_id += 1
73
+
74
+ def before_fork(self):
75
+ self.writer.close()
76
+ super().before_fork()
77
+ # self.writer.path = self.dynamic_path
78
+
79
+ def after_fork_in_child(self):
80
+ new_path = self.new_child_path(self.writer.path)
81
+ new_path.parent.mkdir()
82
+ self.writer.path = new_path
83
+ super().after_fork_in_child()
84
+
85
+ def after_fork_in_parent(self):
86
+ super().after_fork_in_parent()
87
+ self.thread_state.value = self.saved_thread_state
88
+ self.writer.reopen()
89
+
90
+ def __init__(self, thread_state,
91
+ immutable_types,
92
+ tracing_config,
93
+ path):
94
+
95
+ self.fork_counter = 0
41
96
 
42
- def __init__(self, gateway, extended_types, writer):
43
- self.gateway = gateway
44
- self.writer = writer
45
- self.extended_types = extended_types
97
+ self.getpid = thread_state.wrap(
98
+ desired_state = 'disabled', function = os.getpid)
99
+
100
+ self.pid = self.getpid()
46
101
 
47
- def __call__(self, cls):
48
- assert isinstance(cls, type)
102
+ self.writer = stream.writer(path)
103
+
104
+ w = self.writer.handle('TRACE')
105
+ def trace_writer(*args):
106
+ print(f'Trace: {args}')
107
+ w(*args)
49
108
 
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))
109
+ self.extended_types = {}
110
+ self.bindings = utils.id_dict()
111
+ self.next_placeholder_id = 0
112
+
113
+ serialize = functional.walker(self.bindings.get_else_key)
114
+
115
+ thread_switch_monitor = \
116
+ utils.thread_switch_monitor(
117
+ functional.repeatedly(functional.sequence(utils.thread_id, self.writer)))
118
+
119
+ # self.sync = lambda function: functional.observer(on_call = functional.always(writer.handle('SYNC')), function = function)
120
+ self.sync = lambda function: functional.firstof(thread_switch_monitor, functional.always(self.writer.handle('SYNC')), function)
121
+
122
+ # trace_handle = writer.handle('TRACE')
123
+ # tracer = Tracer(tracing_config, writer = trace_handle)
124
+
125
+ # on_ext_result = writer.handle('RESULT')
126
+ # on_ext_result = functional.if_then_else(
127
+ # functional.isinstanceof(str), self.writer.handle('RESULT'), functional.sequence(serialize, self.writer))
128
+
129
+ # on_int_call = functional.mapargs(transform = serialize, function = self.writer.handle('CALL'))
66
130
 
67
- proxytype = dynamic_proxytype(handler = self.gateway, cls = cls)
131
+ error = self.writer.handle('ERROR')
68
132
 
69
- self.writer.type_serializer[proxytype] = functional.constantly(ref)
70
- return proxytype
133
+ def write_error(cls, val, traceback):
134
+ error(cls, val)
71
135
 
136
+ self.set_thread_id = functional.partial(utils.set_thread_id, self.writer)
72
137
 
73
- # when
74
- class RecordProxySystem(ProxySystem):
75
-
76
- def __init__(self, thread_state, immutable_types, tracer, writer):
77
- super().__init__(thread_state = thread_state)
138
+ def watch(f): return functional.either(thread_switch_monitor, f)
78
139
 
79
- self.immutable_types = immutable_types
140
+ tracer = Tracer(tracing_config, writer = trace_writer)
80
141
 
81
- self.extended_types = {}
82
- self.writer = writer
83
- self.bind = writer.placeholder
142
+ # def wrap_int_to_ext(self, obj): return obj
143
+ # def wrap_ext_to_int(self, obj): return obj
144
+
145
+ # def on_int_call(self, func, *args, **kwargs):
146
+ # pass
84
147
 
85
- # on_ext_result = writer.handle('RESULT')
86
- on_ext_result = functional.if_then_else(
87
- functional.isinstanceof(str), writer.handle('RESULT'), writer)
148
+ # def on_ext_result(self, result):
149
+ # pass
150
+
151
+ # def on_ext_error(self, err_type, err_value, err_tarceback):
152
+ # pass
88
153
 
89
- def int_proxytype(gateway):
90
- return lambda cls: dynamic_int_proxytype(handler = gateway, cls = cls, bind = self.bind)
154
+ # def ext_apply(self, func, *args, **kwargs):
155
+ # return func(*args, **kwargs)
91
156
 
92
- def ext_proxytype(gateway):
93
- return ExtProxytype(gateway = gateway, writer = writer, extended_types = self.extended_types)
94
-
95
- error = writer.handle('ERROR')
157
+ # def int_apply(self, func, *args, **kwargs):
158
+ # return func(*args, **kwargs)
96
159
 
97
- def write_error(cls, val, traceback):
98
- error(cls, val)
160
+ self.wrap_int_to_ext = watch
161
+
162
+ self.on_int_call = functional.mapargs(transform = serialize, function = self.writer.handle('CALL'))
163
+
164
+ self.on_ext_result = functional.if_then_else(
165
+ functional.isinstanceof(str),
166
+ self.writer.handle('RESULT'),
167
+ functional.sequence(serialize, self.writer))
168
+
169
+ self.on_ext_error = write_error
99
170
 
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)
171
+ self.ext_apply = self.int_apply = functional.apply
172
+
173
+ super().__init__(thread_state = thread_state, tracer = tracer, immutable_types = immutable_types)
174
+ # wrap_int_to_ext = watch,
175
+ # on_int_call = on_int_call,
176
+ # on_ext_result = on_ext_result,
177
+ # on_ext_error = write_error)
178
+
179
+ # self.ext_handler, self.int_handler = gateway_pair(
180
+ # thread_state,
181
+ # self.tracer,
182
+ # immutable_types = immutable_types,
183
+ # wrap_int_to_ext = watch,
184
+ # int_proxytype = self.int_proxytype,
185
+ # ext_proxytype = self.proxytype,
186
+ # on_int_call = on_int_call,
187
+ # on_ext_result = on_ext_result,
188
+ # on_ext_error = write_error)
189
+
190
+ def ext_proxytype(self, cls):
191
+ assert isinstance(cls, type), f"record.proxytype requires a type but was passed: {cls}"
192
+
193
+ # resolved = resolve(cls)
194
+
195
+ proxytype = super().ext_proxytype(cls)
196
+
197
+ if resolveable_name(cls):
198
+ module, name = resolveable_name(cls)
199
+ ref = self.writer.handle(ProxyRef(name = name, module = module))
200
+ else:
201
+ blacklist = ['__getattribute__']
202
+ descriptors = {k: v for k,v in superdict(cls).items() if k not in blacklist and is_descriptor(v) }
203
+
204
+ methods = [k for k, v in descriptors.items() if utils.is_method_descriptor(v)]
205
+ members = [k for k, v in descriptors.items() if not utils.is_method_descriptor(v)]
206
+
207
+ ref = self.writer.handle(ProxySpec(name = cls.__name__,
208
+ module = cls.__module__,
209
+ methods = methods,
210
+ members = members))
211
+
212
+ self.writer.type_serializer[proxytype] = functional.constantly(ref)
213
+ return proxytype
109
214
 
110
215
  def extend_type(self, base):
111
216
 
112
217
  if base in self.extended_types:
113
218
  return self.extended_types[base]
114
219
 
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)
124
-
125
- ref = self.writer.handle(ProxyRef(name = base.__name__, module = base.__module__,))
126
- self.writer.type_serializer[extended] = functional.constantly(ref)
220
+ extended = super().extend_type(base)
127
221
 
128
- # make_extensible(cls = extended, handler = self.int_handler, on_new = self.writer.placeholder)
129
-
130
- self.immutable_types.add(extended)
131
222
  self.extended_types[base] = extended
132
223
 
133
224
  return extended