retracesoftware-proxy 0.1.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.
@@ -0,0 +1,100 @@
1
+ import retracesoftware.functional as functional
2
+ import retracesoftware_utils as utils
3
+
4
+ # from retracesoftware.proxy.proxytype import ExtendingProxy
5
+
6
+ unproxy_execute = functional.mapargs(starting = 1,
7
+ transform = functional.walker(utils.try_unwrap),
8
+ function = functional.apply)
9
+
10
+ def adapter(proxy_input,
11
+ proxy_output,
12
+ function,
13
+ on_call = None,
14
+ on_result = None,
15
+ on_error = None):
16
+
17
+ # function = functional.apply
18
+
19
+ if on_call: function = functional.observer(on_call = on_call, function = function)
20
+
21
+ function = functional.mapargs(starting = 1, transform = proxy_input, function = function)
22
+
23
+ function = functional.compose(function, proxy_output)
24
+
25
+ if on_result or on_error:
26
+ function = functional.observer(on_result = on_result, on_error = on_error, function = function)
27
+
28
+ return function
29
+
30
+ def adapter_pair(proxy_int,
31
+ proxy_ext,
32
+ int_apply,
33
+ ext_apply,
34
+ tracer,
35
+ on_int_call,
36
+ on_ext_result,
37
+ on_ext_error):
38
+ return (
39
+ adapter(
40
+ function = ext_apply,
41
+ proxy_input = proxy_int,
42
+ proxy_output = proxy_ext,
43
+ on_call = tracer('proxy.ext.call'),
44
+ on_result = on_ext_result,
45
+ on_error = on_ext_error),
46
+ # on_result = tracer('proxy.ext.result', on_ext_result),
47
+ # on_error = tracer('proxy.ext.error', on_ext_error)),
48
+ adapter(
49
+ function = int_apply,
50
+ proxy_input = proxy_ext,
51
+ proxy_output = proxy_int,
52
+ on_call = tracer('proxy.int.call', on_int_call),
53
+ on_result = tracer('proxy.int.result'),
54
+ on_error = tracer('proxy.int.error')))
55
+
56
+ def proxy(proxytype):
57
+ return functional.selfapply(functional.compose(functional.typeof, proxytype))
58
+
59
+ def maybe_proxy(proxytype):
60
+ return functional.if_then_else(
61
+ functional.isinstanceof(utils.Wrapped),
62
+ utils.unwrap,
63
+ proxy(functional.memoize_one_arg(proxytype)))
64
+
65
+ def gateway_pair(thread_state,
66
+ tracer,
67
+ immutable_types,
68
+ int_proxytype,
69
+ ext_proxytype,
70
+ int_apply = functional.apply,
71
+ ext_apply = functional.apply,
72
+ on_int_call = None,
73
+ on_ext_result = None,
74
+ on_ext_error = None):
75
+
76
+ def is_immutable_type(cls):
77
+ return issubclass(cls, tuple(immutable_types))
78
+
79
+ is_immutable = functional.sequence(functional.typeof, functional.memoize_one_arg(is_immutable_type))
80
+
81
+ def create_proxier(proxytype):
82
+ return functional.walker(functional.when_not(is_immutable, maybe_proxy(proxytype)))
83
+
84
+ int_to_ext_dispatch = thread_state.dispatch(tracer('proxy.int.disabled.event', unproxy_execute))
85
+ ext_to_int_dispatch = thread_state.dispatch(tracer('proxy.ext.disabled.event', unproxy_execute))
86
+
87
+ int_to_ext, ext_to_int = adapter_pair(
88
+ proxy_int = create_proxier(int_proxytype(ext_to_int_dispatch)),
89
+ proxy_ext = create_proxier(ext_proxytype(int_to_ext_dispatch)),
90
+ int_apply = thread_state.wrap(desired_state = 'internal', function = int_apply),
91
+ ext_apply = thread_state.wrap(desired_state = 'external', function = ext_apply),
92
+ tracer = tracer,
93
+ on_int_call = on_int_call,
94
+ on_ext_result = on_ext_result,
95
+ on_ext_error = on_ext_error)
96
+
97
+ thread_state.set_dispatch(int_to_ext_dispatch, external = functional.apply, internal = tracer('proxy.int_to_ext.stack', int_to_ext))
98
+ thread_state.set_dispatch(ext_to_int_dispatch, internal = functional.apply, external = tracer('proxy.ext_to_int.wrap', ext_to_int))
99
+
100
+ return (int_to_ext_dispatch, ext_to_int_dispatch)
@@ -0,0 +1,357 @@
1
+ from retracesoftware_utils import counter
2
+ from retracesoftware_functional import *
3
+
4
+ import types
5
+ import pickle
6
+ import gc
7
+ import os
8
+ import functools
9
+ import inspect
10
+
11
+ def is_function_type(cls):
12
+ return issubclass(cls, types.BuiltinFunctionType) or issubclass(cls, types.FunctionType)
13
+
14
+ def superdict(cls):
15
+ result = {}
16
+ for cls in list(reversed(cls.__mro__))[1:]:
17
+ result.update(cls.__dict__)
18
+
19
+ return result
20
+
21
+ def is_method_descriptor(obj):
22
+ return isinstance(obj, types.FunctionType) or \
23
+ (isinstance(obj, (types.WrapperDescriptorType, types.MethodDescriptorType)) and obj.__objclass__ != object)
24
+
25
+ def blacklist_for(self, cls):
26
+ return ['__getattribute__', '__hash__', '__del__', '__init__', '__call__']
27
+
28
+ def is_descriptor(obj):
29
+ return hasattr(obj, '__get__') or hasattr(obj, '__set__') or hasattr(obj, '__delete__')
30
+
31
+ def methods(cls):
32
+ for name,value in superdict(cls).items():
33
+ if is_descriptor(value) and is_method_descriptor(value):
34
+ yield name
35
+
36
+ def patch_spec(cls, blacklist):
37
+ return {
38
+ 'name': f'retrace.proxied.{cls.__module__}.{cls.__name__}',
39
+ 'methods': [m for m in methods(cls) if m not in blacklist],
40
+ 'callable': yeilds_callable_instances(cls),
41
+ 'weakrefs': yeilds_weakly_referenceable_instances(cls)
42
+ }
43
+
44
+ def proxytype_from_spec(target_for, spec):
45
+ proxytype = create_wrapping_proxy_type(
46
+ name = spec['name'],
47
+ callable = spec['callable'],
48
+ weakrefs = spec['weakrefs'])
49
+
50
+ def add_method_descriptor(name, target):
51
+ setattr(proxytype, name, proxytype.method_descriptor(name = name, target = target))
52
+
53
+ for method in spec['methods']:
54
+ add_method_descriptor(name = method, target = target_for(method))
55
+
56
+ # add_method_descriptor(name = '__getattr__', target = object.__getattribute__)
57
+ add_method_descriptor(name = '__getattr__', target = getattr)
58
+ add_method_descriptor(name = '__setattr__', target = setattr)
59
+
60
+ return proxytype
61
+
62
+ def stubtype_from_spec(spec):
63
+ proxytype = create_stub_proxy_type(
64
+ name = spec['name'],
65
+ callable = spec['callable'],
66
+ weakrefs = spec['weakrefs'])
67
+
68
+ def add_method_descriptor(name):
69
+ setattr(proxytype, name, proxytype.method_descriptor(name))
70
+
71
+ for method in spec['methods']:
72
+ add_method_descriptor(method)
73
+
74
+ add_method_descriptor('__getattr__')
75
+ add_method_descriptor('__setattr__')
76
+
77
+ return proxytype
78
+
79
+ def wrap_method_descriptors(wrapper, prefix, base):
80
+ slots = {"__slots__": () }
81
+
82
+ extended = type(f'{prefix}.{base.__module__}.{base.__name__}', (base,), {"__slots__": () })
83
+
84
+ blacklist = ['__getattribute__', '__hash__', '__del__']
85
+
86
+ for name,value in superdict(base).items():
87
+ if name not in blacklist:
88
+ if is_method_descriptor(value):
89
+ setattr(extended, name, wrapper(value))
90
+
91
+ return extended
92
+
93
+ def sync_type(sync, base):
94
+ return wrap_method_descriptors(
95
+ wrapper = lambda desc: intercept(on_call = sync, function = desc),
96
+ prefix = 'retrace.synced',
97
+ base = base)
98
+
99
+ class GCHook:
100
+ def __init__(self, thread_state):
101
+ self.thread_state = thread_state
102
+
103
+ def __call__(self, phase, info):
104
+ if phase == 'start':
105
+ self.saved_state = self.thread_state.value
106
+ self.thread_state.value = 'disabled'
107
+
108
+ elif phase == 'stop':
109
+ self.thread_state.value = self.saved_state
110
+
111
+ class ProxyFactory:
112
+
113
+ def ext_proxy_factory(self):
114
+ return wrapping_proxy_factory(proxytype = self.proxytype, create_reference = compose(type, Reference), handler = self.ext_handler)
115
+
116
+ def int_proxy_factory(self):
117
+ return wrapping_proxy_factory(proxytype = self.proxytype, create_reference = Reference, handler = self.int_handler)
118
+
119
+ def ext_call_handler(self):
120
+ return self.int_handler.call_handler
121
+
122
+ def int_call_handler(self):
123
+ return self.ext_handler.call_handler
124
+
125
+ def before_fork(self):
126
+ pass
127
+ # self.state_before_fork = self.thread_state.value
128
+ # self.thread_state.value = 'disabled'
129
+
130
+ def after_fork_in_child(self):
131
+ self.fork_counter = 0
132
+
133
+ def after_fork_in_parent(self):
134
+ self.fork_counter += 1
135
+ # self.thread_state.value = self.state_before_fork
136
+
137
+ def gc_start(self):
138
+ self.before_gc = self.thread_state.value
139
+ self.thread_state.value = 'external'
140
+
141
+ def gc_end(self):
142
+ self.thread_state.value = self.before_gc
143
+ del self.before_gc
144
+
145
+ def gc_hook(self, phase, info):
146
+
147
+ if phase == 'start':
148
+ self.gc_start()
149
+
150
+ elif phase == 'stop':
151
+ self.gc_end()
152
+
153
+ def __init__(self, thread_state, on_new_proxytype, sync,
154
+ debug, checkpoint, verbose,
155
+ ext_proxy, ext_handler, int_proxy, int_handler):
156
+
157
+ assert ext_proxy
158
+
159
+ self.ext_proxy = ext_proxy
160
+ self.ext_handler = ext_handler
161
+ self.int_proxy = int_proxy
162
+ self.int_handler = int_handler
163
+
164
+ def normalize(obj):
165
+ if isinstance(obj, RootProxy):
166
+ return str(obj)
167
+ elif isinstance(obj, MethodDescriptor):
168
+ return f'{obj.__objclass__.__module__}.{obj.__objclass__.__name__}.{obj.__name__}'
169
+ elif isinstance(obj, Proxy):
170
+ return 'Proxy'
171
+ else:
172
+ return obj
173
+
174
+ self.normalize = walker(normalize)
175
+
176
+ self.checkpoint_ext_call = mapargs(transform = self.normalize,
177
+ function = self.checkpoint_ext_call)
178
+
179
+ # self.checkpoint_ext_call = self.arg_serializer(self.checkpoint_ext_call)
180
+
181
+ self.thread_state = thread_state
182
+ self.debug = debug
183
+ self.fork_counter = 0
184
+ self.verbose = verbose
185
+
186
+ self.on_new_proxytype = on_new_proxytype
187
+ self._sync = sync
188
+ self.thread_counter = self.sync_function(counter(1))
189
+
190
+ # immutable_types = self.disable_for(immutable_types)
191
+
192
+ gc.callbacks.append(self.gc_hook)
193
+
194
+ def before():
195
+ print("In before!!!!")
196
+ with self.thread_state.select('disabled'):
197
+ self.before_fork()
198
+
199
+ os.register_at_fork(
200
+ # before = self.thread_state.wrap('disabled', self.before_fork),
201
+ before = before,
202
+ after_in_parent = self.thread_state.wrap('disabled', self.after_fork_in_parent),
203
+ after_in_child = self.thread_state.wrap('disabled', self.after_fork_in_child))
204
+
205
+ self.tracing = None
206
+
207
+ if debug > 3:
208
+
209
+ # def checkpoint(obj):
210
+ # print(f'in checkpoint: {obj}')
211
+ # self.checkpoint(obj)
212
+
213
+ FrameTracer.install(self.thread_state.dispatch(_proxy.noop, internal = checkpoint))
214
+
215
+ # import threading
216
+ # tracer = FrameTracer(
217
+ # pred = self.thread_state.predicate('internal'),
218
+ # checkpoint = checkpoint)
219
+
220
+ # sys.settrace(tracer)
221
+ # threading.settrace(tracer)
222
+ # self.trace = lambda event, **kwargs: checkpoint({'type': 'trace', 'event': event} | kwargs)
223
+ # self.enable_tracing()
224
+
225
+ def sync_type(self, base):
226
+ return sync_type(sync = self.sync, base = base)
227
+
228
+ def sync_function(self, function):
229
+ return intercept(on_call = self._sync, function = function)
230
+
231
+ def checkpoint(self, obj):
232
+ pass
233
+
234
+ def log(self, message):
235
+ if self.verbose:
236
+ print(message)
237
+
238
+ self.checkpoint({'type': 'log', 'message': message})
239
+
240
+ @property
241
+ def disable(self):
242
+ return self.thread_state.select('disabled')
243
+
244
+ def with_state(self, state, function):
245
+ return self.thread_state.wrap(desired_state = state, function = function)
246
+
247
+ def disable_for(self, function):
248
+ return self.thread_state.wrap(desired_state = 'disabled', function = function)
249
+
250
+ def __call__(self, module, name, obj):
251
+
252
+ if type(obj) == type:
253
+ try:
254
+ return self.extend_type(obj)
255
+ except:
256
+ pass
257
+
258
+ self.checkpoint({'type': 'proxy', 'module': module, 'name': name})
259
+
260
+ if is_function_type(type(obj)) or type(obj) == type:
261
+ proxied = RootProxy(module = module, name = name, handler = self.ext_handler, target = obj)
262
+
263
+ try:
264
+ # print(f"signature: {inspect.signature(obj)} for {obj}")
265
+ proxied.__signature__ = inspect.signature(obj)
266
+ except:
267
+ pass
268
+
269
+ return proxied
270
+ else:
271
+ return self.ext_proxy(obj)
272
+
273
+ # return self.ext_proxy(obj)
274
+
275
+ def start_new_thread(self, start_new_thread, function, *args):
276
+ # synchronized, replay shoudl yeild correct number
277
+ thread_id = self.thread_counter()
278
+
279
+ def threadrunner(*args, **kwargs):
280
+ self.set_thread_number(thread_id)
281
+ with self.thread_state.select('internal'):
282
+ if self.tracing:
283
+ FrameTracer.install(self.thread_state.dispatch(noop, internal = self.checkpoint))
284
+
285
+ return function(*args, **kwargs)
286
+
287
+ return start_new_thread(threadrunner, *args)
288
+
289
+ def wrap_start_new_thread(self, start_new_thread):
290
+ wrapped = functools.partial(self.start_new_thread, start_new_thread)
291
+ return self.thread_state.dispatch(start_new_thread, internal = wrapped)
292
+
293
+ def checkpoint_ext_call(self, func, *args, **kwargs):
294
+ self.checkpoint({'type':
295
+ 'external.call',
296
+ 'function': str(func)})
297
+
298
+ def extend_type(self, base):
299
+
300
+ assert not issubclass(base, BaseException)
301
+
302
+ self.checkpoint({'type': 'log', 'message': f'extending type: {base}'})
303
+
304
+ def custom_init_subclass(cls, **kwargs):
305
+ for name, target in cls.__dict__.items():
306
+ if is_method_descriptor(target):
307
+ proxied = cls.method_descriptor(handler = self.int_handler,
308
+ call_handler = self.thread_state.predicate('external'),
309
+ name = name,
310
+ target = target)
311
+ setattr(cls, name, proxied)
312
+
313
+ def __new__(cls, *args, **kwargs):
314
+ instance = base.__new__(cls, *args, **kwargs)
315
+ self.on_new(instance)
316
+ return instance
317
+
318
+ slots = {
319
+ "__slots__": (),
320
+ '__new__': __new__,
321
+ "__init_subclass__": classmethod(custom_init_subclass)
322
+ }
323
+
324
+ extended = type(f'retrace.extended.{base.__module__}.{base.__name__}', (base, _proxy.ExtendedProxy), slots)
325
+
326
+ blacklist = ['__getattribute__', '__hash__', '__del__']
327
+
328
+ for name,value in superdict(base).items():
329
+ if name not in blacklist:
330
+ if is_method_descriptor(value):
331
+ proxied = extended.method_descriptor(
332
+ handler = self.ext_handler,
333
+ name = name,
334
+ target = getattr(base, name))
335
+
336
+ setattr(extended, name, proxied)
337
+ elif is_descriptor(value):
338
+ setattr(extended, name, self.ext_proxy(value))
339
+
340
+ def __del__(obj):
341
+ try:
342
+ self.on_del(Reference(obj))
343
+ # self.external.handler.on_del(_proxy.Reference(obj))
344
+ except:
345
+ pass
346
+
347
+ try:
348
+ base.__del__(obj)
349
+ except:
350
+ pass
351
+
352
+ extended.__del__ = __del__
353
+
354
+ if self.on_new_proxytype:
355
+ self.on_new_proxytype(base.__module__, base.__name__, extended)
356
+
357
+ return extended
@@ -0,0 +1,20 @@
1
+ import retracesoftware.functional as functional
2
+ import retracesoftware_utils as utils
3
+
4
+ from retracesoftware.proxy.proxytype import extending_proxytype, make_extensible
5
+
6
+ class ProxySystem:
7
+
8
+ def __init__(self, thread_state):
9
+ self.thread_state = thread_state
10
+
11
+ def __call__(self, obj):
12
+ 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):
17
+ return utils.wrapped_function(handler = self.ext_handler, target = obj)
18
+ else:
19
+ raise Exception(f'object {obj} was not proxied as its not a extensible type and is not callable')
20
+