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,8 +1,10 @@
1
- import retracesoftware_utils as utils
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, types.MethodDescriptorType)) and obj.__objclass__ != object)
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__', '__init__', '__call__']
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,86 +144,203 @@ 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
- name = f'retrace.proxied.{cls.__module__}.{cls.__name__}'
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
+ print(f'Creating dynamic_proxytype from {cls} {cls.__dict__}')
200
+
201
+ assert not issubclass(cls, Proxy)
113
202
  assert not issubclass(cls, BaseException)
114
203
 
115
- blacklist = ['__getattribute__', '__hash__', '__del__', '__init__', '__call__']
204
+ blacklist = ['__getattribute__', '__hash__', '__del__', '__call__']
116
205
 
117
- to_proxy = [m for m in methods(cls) if m not in blacklist]
206
+ spec = {}
207
+
208
+ for name in superdict(cls).keys():
209
+ if name not in blacklist:
210
+ value = getattr(cls, name)
211
+ if is_descriptor(value):
212
+ print(f'Adding: {name} {value} {type(value).__mro__}')
118
213
 
119
- def wrap(target): return utils.wrapped_function(handler = handler, target = target)
214
+ if utils.is_method_descriptor(value):
215
+ print(f'Adding method descriptor: {name} {value}')
216
+ spec[name] = utils.wrapped_function(handler = handler, target = value)
217
+ else:
218
+ spec[name] = DescriptorProxy(handler = handler, target = value)
219
+
220
+ # to_proxy = [m for m in methods(cls) if m not in blacklist]
221
+
222
+ # def wrap(target): return utils.wrapped_function(handler = handler, target = target)
120
223
 
121
- spec = { name: wrap(getattr(cls, name)) for name in to_proxy }
224
+ # spec = { name: wrap(getattr(cls, name)) for name in to_proxy }
122
225
 
123
- spec['__getattr__'] = wrap(getattr)
124
- spec['__setattr__'] = wrap(setattr)
226
+ # spec['__getattr__'] = wrap(getattr)
227
+ # spec['__setattr__'] = wrap(setattr)
125
228
 
126
229
  if utils.yields_callable_instances(cls):
127
230
  spec['__call__'] = handler
128
231
 
129
232
  spec['__retrace_target_class__'] = cls
130
233
 
131
- target_type = functional.compose(utils.unwrap, functional.typeof)
234
+ target_type = functional.sequence(utils.unwrap, functional.typeof)
132
235
  spec['__class__'] = property(target_type)
133
-
236
+
134
237
  name = f'retrace.proxied.{cls.__module__}.{cls.__name__}'
135
238
 
136
239
  return type(name, (utils.Wrapped, DynamicProxy), spec)
137
240
 
241
+ def dynamic_from_extended(cls):
242
+
243
+ base = cls.__base__
244
+
245
+ name = f'retrace.proxied.{base.__module__}.{base.__name__}'
246
+
247
+ spec = dict(cls.__dict__)
248
+
249
+ spec['__retrace_target_class__'] = base
250
+
251
+ del spec['__init_subclass__']
252
+ # del spec['__new__']
253
+
254
+ target_type = functional.sequence(utils.unwrap, functional.typeof)
255
+ spec['__class__'] = property(target_type)
256
+
257
+ print(f'dynamic_from_extended {spec}')
258
+
259
+ return type(name, (utils.Wrapped, DynamicProxy), spec)
260
+
261
+
262
+ def instantiable_dynamic_proxytype(handler, cls, thread_state, create_stub = False):
263
+
264
+ proxytype = dynamic_proxytype(handler = handler, cls = cls)
265
+
266
+ def create_original(proxytype, *args, **kwargs):
267
+ instance = cls(*args, **kwargs)
268
+ instance.__init__(*args, **kwargs)
269
+ return instance
270
+
271
+ def __new__(proxytype, *args, **kwargs):
272
+ print(f'instantiable_dynamic_proxytype: {cls}')
273
+
274
+ instance = utils.create_stub_object(cls) if create_stub else cls(*args, **kwargs)
275
+ return utils.create_wrapped(proxytype, instance)
276
+
277
+ proxytype.__new__ = thread_state.dispatch(create_original, internal = __new__)
278
+
279
+ return proxytype
280
+
138
281
  def dynamic_int_proxytype(handler, cls, bind):
139
282
  proxytype = dynamic_proxytype(handler = handler, cls = cls)
140
283
  proxytype.__new__ = functional.sequence(proxytype.__new__, functional.side_effect(bind))
141
284
  return proxytype
142
285
 
143
- class DescriptorProxy:
144
286
 
145
- __slots__ = ['handler', 'proxytype', 'name']
287
+ blacklist = ['__getattribute__', '__hash__', '__del__', '__dict__']
146
288
 
147
- def __init__(self, proxytype, handler, name):
148
- self.proxytype = proxytype
149
- self.handler = handler
150
- self.name = name
289
+ # if the type can be patched, thats better, all new instances must be of correct type
151
290
 
152
- def __get__(self, instance, owner):
153
- inst = owner if instance is None else instance
154
- getter = functional.partial(getattr, super(self.proxytype, inst))
155
- return self.handler(getter, self.name)
291
+ # def make_extensible(thread_state, proxy_method_descriptor, cls):
156
292
 
157
- def __set__(self, instance, value):
158
- setter = functional.partial(setattr, super(self.proxytype, instance))
159
- return self.handler(setter, self.name, value)
293
+ # @functional.memoize_one_arg
294
+ # def proxy_subclass(subclass):
295
+ # if '__retrace_target_type__' in subclass.__dict__:
296
+ # return subclass
297
+
298
+ # attrs = {k: proxy_method_descriptor(v) for k, v in subclass.__dict__.items() if is_method_descriptor(v) }
160
299
 
161
- def __delete__(self, instance):
162
- deleter = functional.partial(delattr, super(self.proxytype, instance))
163
- return self.handler(deleter, self.name)
300
+ # # Ensure module/doc are kept (in case they weren't in __dict__)
301
+ # attrs.setdefault('__module__', subclass.__module__)
302
+ # attrs.setdefault('__doc__', subclass.__doc__)
303
+ # attrs['__retrace_target_type__'] = subclass
164
304
 
305
+ # return type(subclass.__name__, (subclass,), attrs)
165
306
 
166
- blacklist = ['__getattribute__', '__hash__', '__del__']
307
+ # orig__new__ = cls.__new__
167
308
 
168
- # if the type can be patched, thats better, all new instances must be of correct type
309
+ # def proxied__new__(subclass, *args, **kwargs):
310
+ # nonlocal orig__new__
311
+ # return orig__new__(proxy_subclass(subclass), *args, **kwargs)
312
+
313
+ # def unproxied__new__(subclass, *args, **kwargs):
314
+ # return unproxy_type(subclass)(*args, **kwargs)
315
+
316
+ # # Dispatch which constructor to use based on your thread_state policy
317
+ # cls.__new__ = thread_state.dispatch(unproxied__new__, internal = proxied__new__)
318
+
319
+ def create_unproxied_type(cls):
169
320
 
170
- def extending_proxytype(cls, thread_state, ext_handler, int_handler, on_subclass_new, is_stub = False):
321
+ def unproxy_type(cls):
322
+ return cls.__dict__.get('__retrace_unproxied__', cls)
323
+
324
+ return type(cls.__name__, tuple(map(unproxy_type, cls.__bases__)), dict(cls.__dict__))
325
+
326
+ def extending_proxytype(cls, base, thread_state, ext_handler, int_handler, on_subclass_new):
171
327
 
172
328
  assert not issubclass(cls, BaseException)
173
329
 
174
330
  def init_subclass(subclass, **kwargs):
175
- print(f'In init_subclass: {subclass} {kwargs}')
176
- # subclass.__retrace_unproxied__ = create_unproxied_type(subclass)
331
+ # print(f'In init_subclass: {subclass} {kwargs}')
332
+ subclass.__retrace_unproxied__ = create_unproxied_type(subclass)
177
333
 
178
334
  proxy_method_descriptors(cls = subclass, handler = int_handler)
179
335
 
180
336
  if not issubclass(subclass, InternalProxy):
181
- subclass.__new__ = functional.compose(subclass.__new__, functional.side_effect(on_subclass_new))
337
+ subclass.__new__ = functional.sequence(subclass.__new__, functional.side_effect(on_subclass_new))
182
338
  subclass.__bases__ = subclass.__bases__ + (InternalProxy,)
183
339
 
184
- slots = { "__slots__": (), "__init_subclass__": init_subclass }
340
+ slots = { "__slots__": (),
341
+ "__retrace_unproxied__": cls,
342
+ "__module__": cls.__module__,
343
+ "__init_subclass__": init_subclass }
185
344
 
186
345
  def wrap(target): return utils.wrapped_function(handler = ext_handler, target = target)
187
346
 
@@ -194,87 +353,67 @@ def extending_proxytype(cls, thread_state, ext_handler, int_handler, on_subclass
194
353
  elif is_descriptor(value):
195
354
  descriptors.append(name)
196
355
 
197
- name = f'retrace.extended.{cls.__module__}.{cls.__name__}'
198
-
199
- extended = type(name, (cls, ExtendingProxy), slots)
356
+ extended = type(cls.__name__, (base, ExtendingProxy), slots)
200
357
 
201
358
  for name in descriptors:
202
- proxy = DescriptorProxy(handler = ext_handler, name = name, proxytype = extended)
359
+ proxy = ExtendingDescriptorProxy(handler = ext_handler, name = name, proxytype = extended)
203
360
  setattr(extended, name, proxy)
204
-
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
- if is_stub:
214
- def __new__(cls, *args, **kwargs):
215
- instance = utils.create_stub_object(cls)
216
- # print(instance is None)
217
- # utils.sigtrap(None)
218
- return instance
219
-
220
- extended.__new__ = thread_state.dispatch(cls.__new__, internal = __new__, external = __new__)
221
-
222
- # extended.__retrace_unproxied__ = cls
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
367
  return extended
225
368
 
226
369
 
227
- def stubtype(cls, result, thread_state, handler):
370
+ # def stubtype(cls, result, thread_state, handler):
228
371
 
229
- name = f'retrace.stub.{cls.__module__}.{cls.__name__}'
372
+ # name = f'retrace.stub.{cls.__module__}.{cls.__name__}'
230
373
 
231
- slots = {}
374
+ # slots = {}
232
375
 
233
- def wrap(name):
234
- return utils.wrapped_function(
235
- handler = handler,
236
- target = StubMethodDescriptor(name = name, result = result))
376
+ # def wrap(name):
377
+ # return utils.wrapped_function(
378
+ # handler = handler,
379
+ # target = StubMethodDescriptor(name = name, result = result))
237
380
 
238
- for name,value in superdict(cls).items():
239
- if name not in blacklist:
240
- if is_method_descriptor(value):
241
- slots[name] = wrap(name)
242
- elif is_descriptor(value):
243
- slots[name] = DescriptorStub(handler = handler, name = name)
381
+ # for name,value in superdict(cls).items():
382
+ # if name not in blacklist:
383
+ # if is_method_descriptor(value):
384
+ # slots[name] = wrap(name)
385
+ # elif is_descriptor(value):
386
+ # slots[name] = DescriptorStub(handler = handler, name = name)
244
387
 
245
- def disabled__new__(subcls, *args, **kwargs):
246
- instance = cls.__new__(subcls.__retrace_unproxied__, *args, **kwargs)
247
- instance.__init__(*args, **kwargs)
248
- return instance
388
+ # def disabled__new__(subcls, *args, **kwargs):
389
+ # instance = cls.__new__(subcls.__retrace_unproxied__, *args, **kwargs)
390
+ # instance.__init__(*args, **kwargs)
391
+ # return instance
249
392
 
250
- stub = type(name, (Stub,), slots)
393
+ # stub = type(name, (Stub,), slots)
251
394
 
252
- stub.__new__ = thread_state.dispatch(disabled__new__, internal = stub.__new__, external = stub.__new__)
395
+ # stub.__new__ = thread_state.dispatch(disabled__new__, internal = stub.__new__, external = stub.__new__)
253
396
 
254
- stub.__retrace_unproxied__ = cls
397
+ # stub.__retrace_unproxied__ = cls
398
+
399
+ # return stub
255
400
 
256
- return stub
257
401
 
258
- def create_unproxied_type(cls):
259
- name = f'{cls.__module__}.{cls.__name__}'
260
402
 
261
- def unproxy_type(cls):
262
- return cls.__retrace_unproxied__ if issubclass(cls, ExtendingProxy) else cls
263
403
 
264
- return type(name, tuple(map(unproxy_type, cls.__bases__)), dict(cls.__dict__))
265
404
 
266
- def make_extensible(cls, handler, on_new):
405
+ # def make_extensible(cls, handler, on_new):
267
406
 
268
- cls.__retrace_unproxied__ = cls.__base__
407
+ # cls.__retrace_unproxied__ = cls.__base__
269
408
 
270
- def init_subclass(*args, **kwargs):
271
- print(f'In init_subclass: {args} {kwargs}')
272
- # subclass.__retrace_unproxied__ = create_unproxied_type(subclass)
409
+ # def init_subclass(*args, **kwargs):
410
+ # print(f'In init_subclass: {args} {kwargs}')
411
+ # # subclass.__retrace_unproxied__ = create_unproxied_type(subclass)
273
412
 
274
- # proxy_method_descriptors(cls = subclass, handler = handler)
413
+ # # proxy_method_descriptors(cls = subclass, handler = handler)
275
414
 
276
- # if not issubclass(subclass, InternalProxy):
277
- # cls.__new__ = functional.compose(cls.__new__, functional.side_effect(on_new))
278
- # cls.__bases__ = cls.__bases__ + (InternalProxy,)
415
+ # # if not issubclass(subclass, InternalProxy):
416
+ # # cls.__new__ = functional.compose(cls.__new__, functional.side_effect(on_new))
417
+ # # cls.__bases__ = cls.__bases__ + (InternalProxy,)
279
418
 
280
- cls.__init_subclass__ = init_subclass
419
+ # cls.__init_subclass__ = init_subclass