retracesoftware-proxy 0.1.1__py3-none-any.whl → 0.1.3__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.
- retracesoftware/install/install.py +1 -7
- retracesoftware/install/patcher.py +22 -3
- retracesoftware/install/record.py +7 -0
- retracesoftware/install/references.py +2 -1
- retracesoftware/install/replay.py +1 -1
- retracesoftware/install/tracer.py +16 -14
- retracesoftware/proxy/gateway.py +3 -112
- retracesoftware/proxy/proxyfactory.py +194 -194
- retracesoftware/proxy/proxysystem.py +77 -61
- retracesoftware/proxy/proxytype.py +184 -103
- retracesoftware/proxy/record.py +85 -88
- retracesoftware/proxy/replay.py +55 -33
- retracesoftware/proxy/stubfactory.py +140 -0
- retracesoftware/proxy/thread.py +1 -1
- {retracesoftware_proxy-0.1.1.dist-info → retracesoftware_proxy-0.1.3.dist-info}/METADATA +1 -1
- retracesoftware_proxy-0.1.3.dist-info/RECORD +27 -0
- retracesoftware_proxy-0.1.1.dist-info/RECORD +0 -26
- {retracesoftware_proxy-0.1.1.dist-info → retracesoftware_proxy-0.1.3.dist-info}/WHEEL +0 -0
- {retracesoftware_proxy-0.1.1.dist-info → retracesoftware_proxy-0.1.3.dist-info}/top_level.txt +0 -0
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
import retracesoftware.functional as functional
|
|
2
2
|
import retracesoftware_utils as utils
|
|
3
3
|
import types
|
|
4
|
-
from retracesoftware.proxy.gateway import
|
|
4
|
+
from retracesoftware.proxy.gateway import adapter_pair
|
|
5
5
|
from types import SimpleNamespace
|
|
6
|
-
from retracesoftware.proxy.proxytype import
|
|
6
|
+
from retracesoftware.proxy.proxytype import *
|
|
7
|
+
from retracesoftware.proxy.stubfactory import Stub
|
|
8
|
+
import sys
|
|
9
|
+
import gc
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
class RetraceError(Exception):
|
|
12
|
+
pass
|
|
9
13
|
|
|
10
14
|
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
15
|
return functional.spread(
|
|
20
|
-
|
|
16
|
+
utils.create_wrapped,
|
|
21
17
|
functional.sequence(functional.typeof, proxytype),
|
|
22
18
|
None)
|
|
23
19
|
|
|
@@ -31,9 +27,23 @@ unproxy_execute = functional.mapargs(starting = 1,
|
|
|
31
27
|
transform = functional.walker(utils.try_unwrap),
|
|
32
28
|
function = functional.apply)
|
|
33
29
|
|
|
30
|
+
def resolve(obj):
|
|
31
|
+
try:
|
|
32
|
+
return getattr(sys.modules[obj.__module__], obj.__name__)
|
|
33
|
+
except:
|
|
34
|
+
return None
|
|
35
|
+
|
|
36
|
+
def is_function_type(cls):
|
|
37
|
+
return cls in [types.BuiltinFunctionType, types.FunctionType]
|
|
38
|
+
|
|
34
39
|
class ProxySystem:
|
|
35
40
|
|
|
36
|
-
def
|
|
41
|
+
def bind(self, obj): pass
|
|
42
|
+
|
|
43
|
+
def wrap_int_to_ext(self, obj):
|
|
44
|
+
return obj
|
|
45
|
+
# return functional.sequence(functional.side_effect(functional.repeatedly(gc.collect)), obj)
|
|
46
|
+
|
|
37
47
|
def wrap_ext_to_int(self, obj): return obj
|
|
38
48
|
|
|
39
49
|
def on_int_call(self, func, *args, **kwargs):
|
|
@@ -45,18 +55,13 @@ class ProxySystem:
|
|
|
45
55
|
def on_ext_error(self, err_type, err_value, err_traceback):
|
|
46
56
|
pass
|
|
47
57
|
|
|
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
58
|
def __init__(self, thread_state, immutable_types, tracer):
|
|
55
59
|
|
|
56
60
|
self.thread_state = thread_state
|
|
57
61
|
self.fork_counter = 0
|
|
58
62
|
self.tracer = tracer
|
|
59
63
|
self.immutable_types = immutable_types
|
|
64
|
+
self.on_proxytype = None
|
|
60
65
|
|
|
61
66
|
def is_immutable_type(cls):
|
|
62
67
|
return issubclass(cls, tuple(immutable_types))
|
|
@@ -67,53 +72,32 @@ class ProxySystem:
|
|
|
67
72
|
return functional.walker(functional.when_not(is_immutable, maybe_proxy(proxytype)))
|
|
68
73
|
|
|
69
74
|
int_spec = SimpleNamespace(
|
|
70
|
-
|
|
71
|
-
proxy = proxyfactory(self.int_proxytype),
|
|
75
|
+
apply = thread_state.wrap('internal', functional.apply),
|
|
76
|
+
proxy = proxyfactory(thread_state.wrap('disabled', self.int_proxytype)),
|
|
72
77
|
on_call = tracer('proxy.int.call', self.on_int_call),
|
|
73
78
|
on_result = tracer('proxy.int.result'),
|
|
74
79
|
on_error = tracer('proxy.int.error'),
|
|
75
|
-
apply = self.int_apply,
|
|
76
80
|
)
|
|
77
81
|
|
|
78
82
|
ext_spec = SimpleNamespace(
|
|
79
|
-
|
|
80
|
-
proxy = proxyfactory(self.
|
|
83
|
+
apply = thread_state.wrap('external', functional.apply),
|
|
84
|
+
proxy = proxyfactory(thread_state.wrap('disabled', self.dynamic_ext_proxytype)),
|
|
81
85
|
on_call = tracer('proxy.ext.call'),
|
|
82
86
|
on_result = self.on_ext_result,
|
|
83
87
|
on_error = self.on_ext_error,
|
|
84
|
-
apply = self.ext_apply
|
|
85
88
|
)
|
|
86
89
|
|
|
87
|
-
int2ext, ext2int =
|
|
88
|
-
|
|
89
|
-
# self.ext_handler = thread_state.dispatch(default, internal = internal, external = external)
|
|
90
|
+
int2ext, ext2int = adapter_pair(int_spec, ext_spec)
|
|
90
91
|
|
|
91
92
|
def gateway(name, internal = functional.apply, external = functional.apply):
|
|
92
93
|
default = tracer(name, unproxy_execute)
|
|
93
94
|
return thread_state.dispatch(default, internal = internal, external = external)
|
|
94
95
|
|
|
95
|
-
self.ext_handler =
|
|
96
|
-
self.int_handler =
|
|
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)
|
|
96
|
+
self.ext_handler = self.wrap_int_to_ext(int2ext)
|
|
97
|
+
self.int_handler = self.wrap_ext_to_int(ext2int)
|
|
116
98
|
|
|
99
|
+
self.ext_dispatch = gateway('proxy.int.disabled.event', internal = self.ext_handler)
|
|
100
|
+
self.int_dispatch = gateway('proxy.ext.disabled.event', external = self.int_handler)
|
|
117
101
|
|
|
118
102
|
def new_child_path(self, path):
|
|
119
103
|
return path.parent / f'fork-{self.fork_counter}' / path.name
|
|
@@ -134,48 +118,80 @@ class ProxySystem:
|
|
|
134
118
|
|
|
135
119
|
def int_proxytype(self, cls):
|
|
136
120
|
return dynamic_int_proxytype(
|
|
137
|
-
handler = self.
|
|
121
|
+
handler = self.int_dispatch,
|
|
138
122
|
cls = cls,
|
|
139
123
|
bind = self.bind)
|
|
140
124
|
|
|
125
|
+
def dynamic_ext_proxytype(self, cls):
|
|
126
|
+
|
|
127
|
+
proxytype = dynamic_proxytype(
|
|
128
|
+
handler = self.ext_dispatch,
|
|
129
|
+
cls = cls)
|
|
130
|
+
if self.on_proxytype:
|
|
131
|
+
self.on_proxytype(proxytype)
|
|
132
|
+
|
|
133
|
+
return proxytype
|
|
134
|
+
|
|
135
|
+
# resolved = resolve(cls)
|
|
136
|
+
# if isinstance(resolved, ExtendingProxy):
|
|
137
|
+
# return dynamic_from_extended(resolved)
|
|
138
|
+
# elif isinstance(resolved, DynamicProxy):
|
|
139
|
+
# return resolved
|
|
140
|
+
# else:
|
|
141
|
+
# return dynamic_proxytype(handler = self.ext_dispatch, cls = cls)
|
|
142
|
+
|
|
141
143
|
def ext_proxytype(self, cls):
|
|
142
144
|
assert isinstance(cls, type)
|
|
143
145
|
if utils.is_extendable(cls):
|
|
144
146
|
return self.extend_type(cls)
|
|
145
147
|
else:
|
|
146
148
|
return instantiable_dynamic_proxytype(
|
|
147
|
-
handler = self.
|
|
149
|
+
handler = self.ext_dispatch,
|
|
148
150
|
cls = cls,
|
|
149
151
|
thread_state = self.thread_state,
|
|
150
152
|
create_stub = self.create_stub())
|
|
151
153
|
|
|
152
|
-
def extend_type(self,
|
|
154
|
+
def extend_type(self, cls):
|
|
153
155
|
|
|
154
156
|
extended = extending_proxytype(
|
|
155
|
-
cls =
|
|
157
|
+
cls = cls,
|
|
158
|
+
base = Stub if self.create_stub() else cls,
|
|
156
159
|
thread_state = self.thread_state,
|
|
157
|
-
ext_handler = self.
|
|
158
|
-
int_handler = self.
|
|
159
|
-
on_subclass_new = self.bind
|
|
160
|
-
is_stub = self.create_stub())
|
|
160
|
+
ext_handler = self.ext_dispatch,
|
|
161
|
+
int_handler = self.int_dispatch,
|
|
162
|
+
on_subclass_new = self.bind)
|
|
161
163
|
|
|
162
164
|
self.immutable_types.add(extended)
|
|
163
165
|
|
|
164
166
|
return extended
|
|
165
167
|
|
|
168
|
+
def function_target(self, obj): return obj
|
|
169
|
+
|
|
170
|
+
def proxy_function(self, obj):
|
|
171
|
+
return utils.wrapped_function(handler = self.ext_handler, target = obj)
|
|
172
|
+
|
|
166
173
|
def __call__(self, obj):
|
|
167
174
|
assert not isinstance(obj, BaseException)
|
|
175
|
+
assert not isinstance(obj, Proxy)
|
|
168
176
|
assert not isinstance(obj, utils.wrapped_function)
|
|
169
177
|
|
|
170
178
|
if type(obj) == type:
|
|
179
|
+
if obj in self.immutable_types or issubclass(obj, tuple):
|
|
180
|
+
return obj
|
|
181
|
+
|
|
171
182
|
return self.ext_proxytype(obj)
|
|
172
183
|
|
|
173
|
-
elif type(obj)
|
|
174
|
-
return
|
|
184
|
+
elif type(obj) in self.immutable_types:
|
|
185
|
+
return obj
|
|
186
|
+
|
|
187
|
+
elif is_function_type(type(obj)):
|
|
188
|
+
|
|
189
|
+
return self.thread_state.dispatch(
|
|
190
|
+
obj,
|
|
191
|
+
internal = self.proxy_function(obj))
|
|
175
192
|
|
|
176
193
|
else:
|
|
177
|
-
proxytype = dynamic_proxytype(handler = self.
|
|
194
|
+
proxytype = dynamic_proxytype(handler = self.ext_dispatch, cls = type(obj))
|
|
178
195
|
|
|
179
196
|
return utils.create_wrapped(proxytype, obj)
|
|
180
197
|
# raise Exception(f'object {obj} was not proxied as its not a extensible type and is not callable')
|
|
181
|
-
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import retracesoftware.utils as utils
|
|
2
2
|
import retracesoftware.functional as functional
|
|
3
3
|
|
|
4
4
|
import types
|
|
5
5
|
|
|
6
|
+
from retracesoftware.proxy.stubfactory import StubMethodDescriptor
|
|
7
|
+
|
|
6
8
|
class Proxy:
|
|
7
9
|
__slots__ = []
|
|
8
10
|
|
|
@@ -18,6 +20,44 @@ class ExtendingProxy(Proxy):
|
|
|
18
20
|
class InternalProxy:
|
|
19
21
|
__slots__ = []
|
|
20
22
|
|
|
23
|
+
@functional.memoize_one_arg
|
|
24
|
+
def unproxy_type(cls):
|
|
25
|
+
if not issubclass(cls, Proxy):
|
|
26
|
+
return cls
|
|
27
|
+
|
|
28
|
+
# Prefer attribute on the class, not on the mappingproxy
|
|
29
|
+
target = getattr(cls, '__retrace_target_class__', None)
|
|
30
|
+
if target is not None:
|
|
31
|
+
return unproxy_type(target)
|
|
32
|
+
|
|
33
|
+
# Rebuild with unproxied bases, preserving metaclass and critical dunder attrs
|
|
34
|
+
new_bases = tuple(map(unproxy_type, cls.__bases__))
|
|
35
|
+
|
|
36
|
+
# Copy attrs, but omit implementation-managed ones
|
|
37
|
+
attrs = {}
|
|
38
|
+
classcell = None
|
|
39
|
+
for k, v in cls.__dict__.items():
|
|
40
|
+
if k in ('__dict__', '__weakref__'):
|
|
41
|
+
continue
|
|
42
|
+
if k == '__classcell__':
|
|
43
|
+
# must be passed through at class creation for zero-arg super()
|
|
44
|
+
classcell = v
|
|
45
|
+
continue
|
|
46
|
+
attrs[k] = v
|
|
47
|
+
|
|
48
|
+
# Ensure module/doc are kept (in case they weren't in __dict__)
|
|
49
|
+
attrs.setdefault('__module__', cls.__module__)
|
|
50
|
+
attrs.setdefault('__doc__', cls.__doc__)
|
|
51
|
+
|
|
52
|
+
# Use types.new_class if you want full class-creation protocol
|
|
53
|
+
def exec_body(ns):
|
|
54
|
+
ns.update(attrs)
|
|
55
|
+
if classcell is not None:
|
|
56
|
+
ns['__classcell__'] = classcell
|
|
57
|
+
|
|
58
|
+
return types.new_class(cls.__name__, new_bases, {'metaclass': type(cls)}, exec_body)
|
|
59
|
+
|
|
60
|
+
|
|
21
61
|
def superdict(cls):
|
|
22
62
|
result = {}
|
|
23
63
|
for cls in list(reversed(cls.__mro__))[1:]:
|
|
@@ -27,7 +67,9 @@ def superdict(cls):
|
|
|
27
67
|
|
|
28
68
|
def is_method_descriptor(obj):
|
|
29
69
|
return isinstance(obj, types.FunctionType) or \
|
|
30
|
-
(isinstance(obj, (types.WrapperDescriptorType,
|
|
70
|
+
(isinstance(obj, (types.WrapperDescriptorType,
|
|
71
|
+
types.MethodDescriptorType,
|
|
72
|
+
StubMethodDescriptor)) and obj.__objclass__ != object)
|
|
31
73
|
|
|
32
74
|
def proxy_method_descriptors(cls, handler):
|
|
33
75
|
for name, target in cls.__dict__.items():
|
|
@@ -86,7 +128,7 @@ def dynamic_stubtype(handler, cls):
|
|
|
86
128
|
|
|
87
129
|
assert not issubclass(cls, BaseException)
|
|
88
130
|
|
|
89
|
-
blacklist = ['__getattribute__', '__hash__', '__del__', '
|
|
131
|
+
blacklist = ['__getattribute__', '__hash__', '__del__', '__call__']
|
|
90
132
|
|
|
91
133
|
to_proxy = [m for m in methods(cls) if m not in blacklist]
|
|
92
134
|
|
|
@@ -102,26 +144,82 @@ def dynamic_stubtype(handler, cls):
|
|
|
102
144
|
spec['__call__'] = handler
|
|
103
145
|
|
|
104
146
|
spec['__retrace_target_class__'] = cls
|
|
105
|
-
spec['__class__'] = property(functional.repeatedly(cls))
|
|
106
147
|
|
|
107
|
-
|
|
148
|
+
target_type = functional.sequence(utils.unwrap, functional.typeof)
|
|
149
|
+
spec['__class__'] = property(target_type)
|
|
150
|
+
|
|
151
|
+
spec['__module__'] = cls.__module__
|
|
152
|
+
spec['__qualname__'] = cls.__name__
|
|
153
|
+
|
|
154
|
+
# name = f'retrace.proxied.{cls.__module__}.{cls.__name__}'
|
|
155
|
+
|
|
156
|
+
return type(cls.__name__, (Stub, DynamicProxy), spec)
|
|
157
|
+
|
|
158
|
+
class DescriptorProxy:
|
|
159
|
+
__slots__ = ['target', 'handler']
|
|
160
|
+
|
|
161
|
+
def __init__(self, handler, target):
|
|
162
|
+
self.handler = handler
|
|
163
|
+
self.target = target
|
|
164
|
+
|
|
165
|
+
def __get__(self, obj, cls):
|
|
166
|
+
return self.handler(self.target.__get__, obj, cls)
|
|
167
|
+
|
|
168
|
+
def __set__(self, obj, value):
|
|
169
|
+
return self.handler(self.target.__set__, obj, value)
|
|
170
|
+
|
|
171
|
+
def __delete__(self, obj):
|
|
172
|
+
return self.handler(self.target.__delete__, obj)
|
|
173
|
+
|
|
174
|
+
class ExtendingDescriptorProxy:
|
|
175
|
+
|
|
176
|
+
__slots__ = ['handler', 'proxytype', 'name']
|
|
177
|
+
|
|
178
|
+
def __init__(self, proxytype, handler, name):
|
|
179
|
+
self.proxytype = proxytype
|
|
180
|
+
self.handler = handler
|
|
181
|
+
self.name = name
|
|
182
|
+
|
|
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
|
+
|
|
188
|
+
def __set__(self, instance, value):
|
|
189
|
+
setter = functional.partial(setattr, super(self.proxytype, instance))
|
|
190
|
+
return self.handler(setter, self.name, value)
|
|
191
|
+
|
|
192
|
+
def __delete__(self, instance):
|
|
193
|
+
deleter = functional.partial(delattr, super(self.proxytype, instance))
|
|
194
|
+
return self.handler(deleter, self.name)
|
|
108
195
|
|
|
109
|
-
return type(name, (Stub, DynamicProxy), spec)
|
|
110
196
|
|
|
111
197
|
def dynamic_proxytype(handler, cls):
|
|
112
198
|
|
|
199
|
+
assert not issubclass(cls, Proxy)
|
|
113
200
|
assert not issubclass(cls, BaseException)
|
|
114
201
|
|
|
115
202
|
blacklist = ['__getattribute__', '__hash__', '__del__', '__call__']
|
|
116
203
|
|
|
117
|
-
|
|
204
|
+
spec = {}
|
|
118
205
|
|
|
119
|
-
|
|
206
|
+
for name in superdict(cls).keys():
|
|
207
|
+
if name not in blacklist:
|
|
208
|
+
value = getattr(cls, name)
|
|
209
|
+
if is_descriptor(value):
|
|
210
|
+
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)
|
|
214
|
+
|
|
215
|
+
# to_proxy = [m for m in methods(cls) if m not in blacklist]
|
|
216
|
+
|
|
217
|
+
# def wrap(target): return utils.wrapped_function(handler = handler, target = target)
|
|
120
218
|
|
|
121
|
-
spec = { name: wrap(getattr(cls, name)) for name in to_proxy }
|
|
219
|
+
# spec = { name: wrap(getattr(cls, name)) for name in to_proxy }
|
|
122
220
|
|
|
123
|
-
spec['__getattr__'] = wrap(getattr)
|
|
124
|
-
spec['__setattr__'] = wrap(setattr)
|
|
221
|
+
# spec['__getattr__'] = wrap(getattr)
|
|
222
|
+
# spec['__setattr__'] = wrap(setattr)
|
|
125
223
|
|
|
126
224
|
if utils.yields_callable_instances(cls):
|
|
127
225
|
spec['__call__'] = handler
|
|
@@ -135,6 +233,25 @@ def dynamic_proxytype(handler, cls):
|
|
|
135
233
|
|
|
136
234
|
return type(name, (utils.Wrapped, DynamicProxy), spec)
|
|
137
235
|
|
|
236
|
+
def dynamic_from_extended(cls):
|
|
237
|
+
|
|
238
|
+
base = cls.__base__
|
|
239
|
+
|
|
240
|
+
name = f'retrace.proxied.{base.__module__}.{base.__name__}'
|
|
241
|
+
|
|
242
|
+
spec = dict(cls.__dict__)
|
|
243
|
+
|
|
244
|
+
spec['__retrace_target_class__'] = base
|
|
245
|
+
|
|
246
|
+
del spec['__init_subclass__']
|
|
247
|
+
# del spec['__new__']
|
|
248
|
+
|
|
249
|
+
target_type = functional.sequence(utils.unwrap, functional.typeof)
|
|
250
|
+
spec['__class__'] = property(target_type)
|
|
251
|
+
|
|
252
|
+
return type(name, (utils.Wrapped, DynamicProxy), spec)
|
|
253
|
+
|
|
254
|
+
|
|
138
255
|
def instantiable_dynamic_proxytype(handler, cls, thread_state, create_stub = False):
|
|
139
256
|
|
|
140
257
|
proxytype = dynamic_proxytype(handler = handler, cls = cls)
|
|
@@ -145,8 +262,6 @@ def instantiable_dynamic_proxytype(handler, cls, thread_state, create_stub = Fal
|
|
|
145
262
|
return instance
|
|
146
263
|
|
|
147
264
|
def __new__(proxytype, *args, **kwargs):
|
|
148
|
-
print(f'instantiable_dynamic_proxytype: {cls}')
|
|
149
|
-
|
|
150
265
|
instance = utils.create_stub_object(cls) if create_stub else cls(*args, **kwargs)
|
|
151
266
|
return utils.create_wrapped(proxytype, instance)
|
|
152
267
|
|
|
@@ -159,40 +274,58 @@ def dynamic_int_proxytype(handler, cls, bind):
|
|
|
159
274
|
proxytype.__new__ = functional.sequence(proxytype.__new__, functional.side_effect(bind))
|
|
160
275
|
return proxytype
|
|
161
276
|
|
|
162
|
-
class DescriptorProxy:
|
|
163
277
|
|
|
164
|
-
|
|
278
|
+
blacklist = ['__getattribute__', '__hash__', '__del__', '__dict__']
|
|
165
279
|
|
|
166
|
-
|
|
167
|
-
self.proxytype = proxytype
|
|
168
|
-
self.handler = handler
|
|
169
|
-
self.name = name
|
|
280
|
+
# if the type can be patched, thats better, all new instances must be of correct type
|
|
170
281
|
|
|
171
|
-
|
|
172
|
-
inst = owner if instance is None else instance
|
|
173
|
-
getter = functional.partial(getattr, super(self.proxytype, inst))
|
|
174
|
-
return self.handler(getter, self.name)
|
|
282
|
+
# def make_extensible(thread_state, proxy_method_descriptor, cls):
|
|
175
283
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
284
|
+
# @functional.memoize_one_arg
|
|
285
|
+
# def proxy_subclass(subclass):
|
|
286
|
+
# if '__retrace_target_type__' in subclass.__dict__:
|
|
287
|
+
# return subclass
|
|
288
|
+
|
|
289
|
+
# attrs = {k: proxy_method_descriptor(v) for k, v in subclass.__dict__.items() if is_method_descriptor(v) }
|
|
179
290
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
291
|
+
# # Ensure module/doc are kept (in case they weren't in __dict__)
|
|
292
|
+
# attrs.setdefault('__module__', subclass.__module__)
|
|
293
|
+
# attrs.setdefault('__doc__', subclass.__doc__)
|
|
294
|
+
# attrs['__retrace_target_type__'] = subclass
|
|
183
295
|
|
|
296
|
+
# return type(subclass.__name__, (subclass,), attrs)
|
|
184
297
|
|
|
185
|
-
|
|
298
|
+
# orig__new__ = cls.__new__
|
|
186
299
|
|
|
187
|
-
#
|
|
300
|
+
# def proxied__new__(subclass, *args, **kwargs):
|
|
301
|
+
# nonlocal orig__new__
|
|
302
|
+
# return orig__new__(proxy_subclass(subclass), *args, **kwargs)
|
|
303
|
+
|
|
304
|
+
# def unproxied__new__(subclass, *args, **kwargs):
|
|
305
|
+
# return unproxy_type(subclass)(*args, **kwargs)
|
|
306
|
+
|
|
307
|
+
# # Dispatch which constructor to use based on your thread_state policy
|
|
308
|
+
# cls.__new__ = thread_state.dispatch(unproxied__new__, internal = proxied__new__)
|
|
309
|
+
|
|
310
|
+
def create_unproxied_type(cls):
|
|
311
|
+
def unproxy_type(cls):
|
|
312
|
+
return cls.__dict__.get('__retrace_unproxied__', cls)
|
|
188
313
|
|
|
189
|
-
|
|
314
|
+
bases = tuple(map(unproxy_type, cls.__bases__))
|
|
315
|
+
slots = dict(cls.__dict__)
|
|
316
|
+
del slots['__init_subclass__']
|
|
317
|
+
return type(cls.__name__, tuple(bases), slots)
|
|
190
318
|
|
|
319
|
+
def extending_proxytype(cls, base, thread_state, ext_handler, int_handler, on_subclass_new):
|
|
320
|
+
|
|
321
|
+
# assert cls is base
|
|
191
322
|
assert not issubclass(cls, BaseException)
|
|
323
|
+
assert not issubclass(cls, ExtendingProxy)
|
|
192
324
|
|
|
193
325
|
def init_subclass(subclass, **kwargs):
|
|
194
326
|
print(f'In init_subclass: {subclass} {kwargs}')
|
|
195
|
-
|
|
327
|
+
unproxied = create_unproxied_type(subclass)
|
|
328
|
+
subclass.__retrace_unproxied__ = unproxied
|
|
196
329
|
|
|
197
330
|
proxy_method_descriptors(cls = subclass, handler = int_handler)
|
|
198
331
|
|
|
@@ -200,7 +333,12 @@ def extending_proxytype(cls, thread_state, ext_handler, int_handler, on_subclass
|
|
|
200
333
|
subclass.__new__ = functional.sequence(subclass.__new__, functional.side_effect(on_subclass_new))
|
|
201
334
|
subclass.__bases__ = subclass.__bases__ + (InternalProxy,)
|
|
202
335
|
|
|
203
|
-
|
|
336
|
+
assert not issubclass(subclass.__retrace_unproxied__, ExtendingProxy)
|
|
337
|
+
|
|
338
|
+
slots = { "__slots__": (),
|
|
339
|
+
"__retrace_unproxied__": cls,
|
|
340
|
+
"__module__": cls.__module__,
|
|
341
|
+
"__init_subclass__": init_subclass }
|
|
204
342
|
|
|
205
343
|
def wrap(target): return utils.wrapped_function(handler = ext_handler, target = target)
|
|
206
344
|
|
|
@@ -213,79 +351,22 @@ def extending_proxytype(cls, thread_state, ext_handler, int_handler, on_subclass
|
|
|
213
351
|
elif is_descriptor(value):
|
|
214
352
|
descriptors.append(name)
|
|
215
353
|
|
|
216
|
-
|
|
354
|
+
slots['__retrace_unproxied__'] = cls
|
|
217
355
|
|
|
218
|
-
extended = type(
|
|
356
|
+
extended = type(cls.__name__, (base, ExtendingProxy), slots)
|
|
219
357
|
|
|
220
358
|
for name in descriptors:
|
|
221
|
-
proxy =
|
|
359
|
+
proxy = ExtendingDescriptorProxy(handler = ext_handler, name = name, proxytype = extended)
|
|
222
360
|
setattr(extended, name, proxy)
|
|
361
|
+
|
|
362
|
+
def unproxied__new__(subclass, *args, **kwargs):
|
|
363
|
+
return subclass.__retrace_unproxied__(*args, **kwargs)
|
|
364
|
+
|
|
365
|
+
extended.__new__ = thread_state.dispatch(unproxied__new__, internal = base.__new__)
|
|
223
366
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
# utils.sigtrap(None)
|
|
229
|
-
return instance
|
|
230
|
-
|
|
231
|
-
extended.__new__ = thread_state.dispatch(cls.__new__, internal = __new__, external = __new__)
|
|
232
|
-
|
|
233
|
-
# extended.__retrace_unproxied__ = cls
|
|
367
|
+
assert not issubclass(extended.__retrace_unproxied__, ExtendingProxy)
|
|
368
|
+
assert extended.__dict__['__retrace_unproxied__'] is extended.__retrace_unproxied__
|
|
369
|
+
print(f'FOO: {extended} {id(extended)} {id(extended.__retrace_unproxied__)}')
|
|
370
|
+
# breakpoint()
|
|
234
371
|
|
|
235
372
|
return extended
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
def stubtype(cls, result, thread_state, handler):
|
|
239
|
-
|
|
240
|
-
name = f'retrace.stub.{cls.__module__}.{cls.__name__}'
|
|
241
|
-
|
|
242
|
-
slots = {}
|
|
243
|
-
|
|
244
|
-
def wrap(name):
|
|
245
|
-
return utils.wrapped_function(
|
|
246
|
-
handler = handler,
|
|
247
|
-
target = StubMethodDescriptor(name = name, result = result))
|
|
248
|
-
|
|
249
|
-
for name,value in superdict(cls).items():
|
|
250
|
-
if name not in blacklist:
|
|
251
|
-
if is_method_descriptor(value):
|
|
252
|
-
slots[name] = wrap(name)
|
|
253
|
-
elif is_descriptor(value):
|
|
254
|
-
slots[name] = DescriptorStub(handler = handler, name = name)
|
|
255
|
-
|
|
256
|
-
def disabled__new__(subcls, *args, **kwargs):
|
|
257
|
-
instance = cls.__new__(subcls.__retrace_unproxied__, *args, **kwargs)
|
|
258
|
-
instance.__init__(*args, **kwargs)
|
|
259
|
-
return instance
|
|
260
|
-
|
|
261
|
-
stub = type(name, (Stub,), slots)
|
|
262
|
-
|
|
263
|
-
stub.__new__ = thread_state.dispatch(disabled__new__, internal = stub.__new__, external = stub.__new__)
|
|
264
|
-
|
|
265
|
-
stub.__retrace_unproxied__ = cls
|
|
266
|
-
|
|
267
|
-
return stub
|
|
268
|
-
|
|
269
|
-
def create_unproxied_type(cls):
|
|
270
|
-
name = f'{cls.__module__}.{cls.__name__}'
|
|
271
|
-
|
|
272
|
-
def unproxy_type(cls):
|
|
273
|
-
return cls.__retrace_unproxied__ if issubclass(cls, ExtendingProxy) else cls
|
|
274
|
-
|
|
275
|
-
return type(name, tuple(map(unproxy_type, cls.__bases__)), dict(cls.__dict__))
|
|
276
|
-
|
|
277
|
-
def make_extensible(cls, handler, on_new):
|
|
278
|
-
|
|
279
|
-
cls.__retrace_unproxied__ = cls.__base__
|
|
280
|
-
|
|
281
|
-
def init_subclass(*args, **kwargs):
|
|
282
|
-
print(f'In init_subclass: {args} {kwargs}')
|
|
283
|
-
# subclass.__retrace_unproxied__ = create_unproxied_type(subclass)
|
|
284
|
-
|
|
285
|
-
# proxy_method_descriptors(cls = subclass, handler = handler)
|
|
286
|
-
|
|
287
|
-
# if not issubclass(subclass, InternalProxy):
|
|
288
|
-
# cls.__new__ = functional.compose(cls.__new__, functional.side_effect(on_new))
|
|
289
|
-
# cls.__bases__ = cls.__bases__ + (InternalProxy,)
|
|
290
|
-
|
|
291
|
-
cls.__init_subclass__ = init_subclass
|