retracesoftware-proxy 0.1.5__py3-none-any.whl → 0.2.4__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.
Files changed (35) hide show
  1. retracesoftware/__main__.py +285 -0
  2. retracesoftware/autoenable.py +53 -0
  3. retracesoftware/config.json +19 -233
  4. retracesoftware/config.yaml +0 -0
  5. retracesoftware/install/config.py +6 -0
  6. retracesoftware/install/edgecases.py +23 -1
  7. retracesoftware/install/patcher.py +98 -513
  8. retracesoftware/install/patchfindspec.py +117 -0
  9. retracesoftware/install/phases.py +338 -0
  10. retracesoftware/install/record.py +111 -40
  11. retracesoftware/install/replace.py +28 -0
  12. retracesoftware/install/replay.py +59 -11
  13. retracesoftware/install/tracer.py +171 -33
  14. retracesoftware/install/typeutils.py +20 -0
  15. retracesoftware/modules.toml +384 -0
  16. retracesoftware/preload.txt +216 -0
  17. retracesoftware/proxy/__init__.py +1 -1
  18. retracesoftware/proxy/globalref.py +31 -0
  19. retracesoftware/proxy/messagestream.py +204 -0
  20. retracesoftware/proxy/proxysystem.py +328 -71
  21. retracesoftware/proxy/proxytype.py +90 -38
  22. retracesoftware/proxy/record.py +109 -119
  23. retracesoftware/proxy/replay.py +94 -188
  24. retracesoftware/proxy/serializer.py +28 -0
  25. retracesoftware/proxy/startthread.py +40 -0
  26. retracesoftware/proxy/stubfactory.py +82 -27
  27. retracesoftware/proxy/thread.py +64 -4
  28. retracesoftware/replay.py +104 -0
  29. retracesoftware/run.py +378 -0
  30. retracesoftware/stackdifference.py +133 -0
  31. {retracesoftware_proxy-0.1.5.dist-info → retracesoftware_proxy-0.2.4.dist-info}/METADATA +2 -1
  32. retracesoftware_proxy-0.2.4.dist-info/RECORD +42 -0
  33. retracesoftware_proxy-0.1.5.dist-info/RECORD +0 -27
  34. {retracesoftware_proxy-0.1.5.dist-info → retracesoftware_proxy-0.2.4.dist-info}/WHEEL +0 -0
  35. {retracesoftware_proxy-0.1.5.dist-info → retracesoftware_proxy-0.2.4.dist-info}/top_level.txt +0 -0
@@ -3,14 +3,11 @@ import retracesoftware.functional as functional
3
3
 
4
4
  import types
5
5
 
6
- from retracesoftware.proxy.stubfactory import StubMethodDescriptor
6
+ from retracesoftware.proxy.stubfactory import StubMethodDescriptor, Stub
7
7
 
8
8
  class Proxy:
9
9
  __slots__ = []
10
10
 
11
- class Stub(Proxy):
12
- __slots__ = []
13
-
14
11
  class DynamicProxy(Proxy):
15
12
  __slots__ = []
16
13
 
@@ -163,7 +160,11 @@ class DescriptorProxy:
163
160
  self.target = target
164
161
 
165
162
  def __get__(self, obj, cls):
166
- return self.handler(self.target.__get__, obj, cls)
163
+ try:
164
+ return self.handler(self.target.__get__, obj, cls)
165
+ except:
166
+ print(f'error calling __get__')
167
+ raise
167
168
 
168
169
  def __set__(self, obj, value):
169
170
  return self.handler(self.target.__set__, obj, value)
@@ -171,46 +172,75 @@ class DescriptorProxy:
171
172
  def __delete__(self, obj):
172
173
  return self.handler(self.target.__delete__, obj)
173
174
 
174
- class ExtendingDescriptorProxy:
175
+ # class ExtendingDescriptorProxy:
175
176
 
176
- __slots__ = ['handler', 'proxytype', 'name']
177
+ # __slots__ = ['handler', 'proxytype', 'name']
177
178
 
178
- def __init__(self, proxytype, handler, name):
179
- self.proxytype = proxytype
180
- self.handler = handler
181
- self.name = name
179
+ # def __init__(self, proxytype, handler, name):
180
+ # self.proxytype = proxytype
181
+ # self.handler = handler
182
+ # self.name = name
182
183
 
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)
184
+ # def __get__(self, instance, owner):
185
+ # inst = owner if instance is None else instance
186
+ # getter = functional.partial(getattr, super(self.proxytype, inst))
187
+ # return self.handler(getter, self.name)
187
188
 
188
- def __set__(self, instance, value):
189
- setter = functional.partial(setattr, super(self.proxytype, instance))
190
- return self.handler(setter, self.name, value)
189
+ # def __set__(self, instance, value):
190
+ # breakpoint()
191
+ # setter = functional.partial(setattr, super(self.proxytype, instance))
192
+ # return self.handler(setter, self.name, value)
191
193
 
192
- def __delete__(self, instance):
193
- deleter = functional.partial(delattr, super(self.proxytype, instance))
194
- return self.handler(deleter, self.name)
194
+ # def __delete__(self, instance):
195
+ # deleter = functional.partial(delattr, super(self.proxytype, instance))
196
+ # return self.handler(deleter, self.name)
195
197
 
196
198
 
197
199
  def dynamic_proxytype(handler, cls):
198
200
 
201
+ if cls.__module__.startswith('retracesoftware'):
202
+ print(cls)
203
+ utils.sigtrap('HERE5')
204
+
205
+ assert not cls.__module__.startswith('retracesoftware')
206
+
207
+ # print(f'In dynamic_proxytype: {cls}')
208
+
199
209
  assert not issubclass(cls, Proxy)
200
210
  assert not issubclass(cls, BaseException)
201
211
 
202
- blacklist = ['__getattribute__', '__hash__', '__del__', '__call__']
212
+ blacklist = ['__getattribute__', '__hash__', '__del__', '__call__', '__new__']
203
213
 
204
214
  spec = {}
205
215
 
216
+ def wrap(func): return utils.wrapped_function(handler = handler, target = func)
217
+
206
218
  for name in superdict(cls).keys():
207
219
  if name not in blacklist:
208
220
  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)
221
+
222
+ if issubclass(type(value), utils.dispatch):
223
+ value = utils.dispatch.table(value)['disabled']
224
+
225
+ # if is_descriptor(value):
226
+ if utils.is_method_descriptor(value):
227
+ spec[name] = wrap(value)
228
+
229
+ # try:
230
+ # value = getattr(cls, name)
231
+
232
+ # assert type(value) is not utils.dispatch
233
+
234
+ # if is_descriptor(value):
235
+ # if utils.is_method_descriptor(value):
236
+ # spec[name] = wrap(value)
237
+ # except Exception as error:
238
+ # print(f'FOO! {cls} {name} {error}')
239
+ # breakpoint()
240
+ # raise
241
+
242
+ # else:
243
+ # spec[name] = DescriptorProxy(handler = handler, target = value)
214
244
 
215
245
  # to_proxy = [m for m in methods(cls) if m not in blacklist]
216
246
 
@@ -218,26 +248,39 @@ def dynamic_proxytype(handler, cls):
218
248
 
219
249
  # spec = { name: wrap(getattr(cls, name)) for name in to_proxy }
220
250
 
221
- # spec['__getattr__'] = wrap(getattr)
222
- # spec['__setattr__'] = wrap(setattr)
251
+ # def foo(obj, name, default = None):
252
+ # print(f'dynamic_proxytype.__getattr__: {type(obj).__mro__} {name}')
253
+ # utils.sigtrap(obj)
254
+ # return getattr(obj, name, default)
255
+
256
+ # spec['__getattr__'] = wrap(foo)
257
+ spec['__getattr__'] = wrap(getattr)
258
+ spec['__setattr__'] = wrap(setattr)
223
259
 
224
260
  if utils.yields_callable_instances(cls):
225
261
  spec['__call__'] = handler
226
262
 
227
263
  spec['__retrace_target_class__'] = cls
228
264
 
229
- target_type = functional.sequence(utils.unwrap, functional.typeof)
230
- spec['__class__'] = property(target_type)
231
-
232
- name = f'retrace.proxied.{cls.__module__}.{cls.__name__}'
265
+ # target_type = functional.sequence(utils.unwrap, functional.typeof)
233
266
 
234
- return type(name, (utils.Wrapped, DynamicProxy), spec)
267
+ target_type = cls.__retrace_target_type__ if issubclass(cls, Stub) else cls
268
+ # functional.repeatedly(resolved)
269
+
270
+ # spec['__class__'] = property(target_type)
271
+ spec['__class__'] = property(functional.constantly(target_type))
272
+
273
+ spec['__name__'] = cls.__name__
274
+ spec['__module__'] = cls.__module__
275
+ # name = f'retrace.proxied.{cls.__module__}.{cls.__name__}'
276
+
277
+ return type(cls.__name__, (utils.Wrapped, DynamicProxy), spec)
235
278
 
236
279
  def dynamic_from_extended(cls):
237
280
 
238
281
  base = cls.__base__
239
282
 
240
- name = f'retrace.proxied.{base.__module__}.{base.__name__}'
283
+ name = f'retrace.proxied1.{base.__module__}.{base.__name__}'
241
284
 
242
285
  spec = dict(cls.__dict__)
243
286
 
@@ -272,6 +315,7 @@ def instantiable_dynamic_proxytype(handler, cls, thread_state, create_stub = Fal
272
315
  def dynamic_int_proxytype(handler, cls, bind):
273
316
  proxytype = dynamic_proxytype(handler = handler, cls = cls)
274
317
  proxytype.__new__ = functional.sequence(proxytype.__new__, functional.side_effect(bind))
318
+ proxytype.__retrace_source__ = 'internal'
275
319
  return proxytype
276
320
 
277
321
 
@@ -313,6 +357,11 @@ def create_unproxied_type(cls):
313
357
 
314
358
  bases = tuple(map(unproxy_type, cls.__bases__))
315
359
  slots = dict(cls.__dict__)
360
+
361
+ if '__slots__' in slots:
362
+ for slot in slots['__slots__']:
363
+ slots.pop(slot)
364
+
316
365
  # del slots['__init_subclass__']
317
366
  return type(cls.__name__, tuple(bases), slots)
318
367
 
@@ -323,7 +372,7 @@ def extending_proxytype(cls, base, thread_state, ext_handler, int_handler, on_su
323
372
  assert not issubclass(cls, ExtendingProxy)
324
373
 
325
374
  def init_subclass(subclass, **kwargs):
326
- print(f'In init_subclass: {subclass} {kwargs}')
375
+ # print(f'In init_subclass: {subclass} {subclass.__mro__} {kwargs}')
327
376
  unproxied = create_unproxied_type(subclass)
328
377
  subclass.__retrace_unproxied__ = unproxied
329
378
 
@@ -347,7 +396,7 @@ def extending_proxytype(cls, base, thread_state, ext_handler, int_handler, on_su
347
396
  for name,value in superdict(cls).items():
348
397
  if name not in blacklist:
349
398
  if is_method_descriptor(value):
350
- slots[name] = wrap(getattr(cls, name))
399
+ slots[name] = wrap(getattr(base, name))
351
400
  elif is_descriptor(value):
352
401
  descriptors.append(name)
353
402
 
@@ -356,12 +405,15 @@ def extending_proxytype(cls, base, thread_state, ext_handler, int_handler, on_su
356
405
  extended = type(cls.__name__, (base, ExtendingProxy), slots)
357
406
 
358
407
  for name in descriptors:
359
- proxy = ExtendingDescriptorProxy(handler = ext_handler, name = name, proxytype = extended)
408
+ # proxy = ExtendingDescriptorProxy(handler = ext_handler, name = name, proxytype = extended)
409
+ proxy = DescriptorProxy(handler = ext_handler, target = getattr(cls, name))
360
410
  setattr(extended, name, proxy)
361
411
 
362
412
  def unproxied__new__(subclass, *args, **kwargs):
363
413
  return subclass.__retrace_unproxied__(*args, **kwargs)
364
414
 
415
+ assert callable(base.__new__)
416
+
365
417
  extended.__new__ = thread_state.dispatch(unproxied__new__, internal = base.__new__)
366
418
 
367
419
  assert not issubclass(extended.__retrace_unproxied__, ExtendingProxy)
@@ -5,20 +5,22 @@ import retracesoftware.stream as stream
5
5
  from retracesoftware.proxy.proxytype import *
6
6
  # from retracesoftware.proxy.gateway import gateway_pair
7
7
  from retracesoftware.proxy.proxysystem import ProxySystem
8
- from retracesoftware.proxy.thread import write_thread_switch
8
+ from retracesoftware.proxy.thread import write_thread_switch, ThreadSwitch, thread_id
9
9
  from retracesoftware.install.tracer import Tracer
10
+ from retracesoftware.install.patchfindspec import patch_find_spec
10
11
  from retracesoftware.proxy.stubfactory import StubRef, ExtendedRef
12
+ from retracesoftware.proxy.globalref import GlobalRef
11
13
 
12
14
  import sys
13
15
  import os
14
16
  import types
15
17
  import gc
16
18
 
17
- class Placeholder:
18
- __slots__ = ['id', '__weakref__']
19
+ # class Placeholder:
20
+ # __slots__ = ['id', '__weakref__']
19
21
 
20
- def __init__(self, id):
21
- self.id = id
22
+ # def __init__(self, id):
23
+ # self.id = id
22
24
 
23
25
  def keys_where_value(pred, dict):
24
26
  for key,value in dict.items():
@@ -49,13 +51,14 @@ def resolveable_name(obj):
49
51
  # when
50
52
  class RecordProxySystem(ProxySystem):
51
53
 
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
54
+ # def bind(self, obj):
55
+ # self.bindings[obj] = self.writer.handle(Placeholder(self.next_placeholder_id))
56
+ # self.writer(self.bindings[obj])
57
+ # self.next_placeholder_id += 1
56
58
 
57
59
  def before_fork(self):
58
- self.writer.close()
60
+ self.writer.keep_open = False
61
+ # self.writer.close()
59
62
  super().before_fork()
60
63
  # self.writer.path = self.dynamic_path
61
64
 
@@ -63,159 +66,146 @@ class RecordProxySystem(ProxySystem):
63
66
  new_path = self.new_child_path(self.writer.path)
64
67
  new_path.parent.mkdir()
65
68
  self.writer.path = new_path
69
+ self.writer.keep_open = True
66
70
  super().after_fork_in_child()
67
71
 
68
72
  def after_fork_in_parent(self):
69
73
  super().after_fork_in_parent()
70
74
  self.thread_state.value = self.saved_thread_state
71
- self.writer.reopen()
75
+ self.writer.keep_open = True
76
+ # self.writer.reopen()
77
+
78
+ def set_thread_id(self, id):
79
+ utils.set_thread_id(self.writer.handle(ThreadSwitch(id)))
80
+ # utils.set_thread_id(id)
81
+
82
+ # def is_entry_frame(self, frame):
83
+ # if super().is_entry_frame(frame):
84
+ # self.write_main_path(frame.function.__code__.co_filename)
85
+ # return True
86
+ # return False
87
+
88
+ def create_from_external(self, obj):
89
+ # class of obj is bound
90
+ # can now write type(obj)
91
+
92
+ self.bind(obj)
93
+
94
+ breakpoint()
95
+
96
+ def patch_type(self, cls):
72
97
 
73
- def __init__(self, thread_state,
98
+ patched = super().patch_type(cls)
99
+
100
+ self.writer.type_serializer[patched] = functional.side_effect(self.writer.ext_bind)
101
+
102
+ return patched
103
+
104
+ def exclude_from_stacktrace(self, func):
105
+ self.writer.exclude_from_stacktrace(func)
106
+
107
+ def on_gc_event(self, phase, info):
108
+ if phase == 'start':
109
+ self.writer.stacktraces = False
110
+ self.on_start_collect(info['generation'])
111
+
112
+ elif phase == 'stop':
113
+ self.on_end_collect()
114
+ self.writer.stacktraces = self.stacktraces
115
+
116
+ def __init__(self, thread_state,
117
+ writer,
74
118
  immutable_types,
75
119
  tracing_config,
76
- path):
120
+ maybe_collect,
121
+ traceargs):
77
122
 
78
123
  self.fork_counter = 0
79
-
124
+ # self.write_main_path = write_main_path
125
+
80
126
  self.getpid = thread_state.wrap(
81
127
  desired_state = 'disabled', function = os.getpid)
82
128
 
83
129
  self.pid = self.getpid()
84
130
 
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)
131
+ self.writer = writer
132
+
133
+ self.stacktraces = self.writer.stacktraces
134
+
135
+ if self.stacktraces:
136
+ def set(status):
137
+ self.writer.stacktraces = status
138
+
139
+ self.wrap_weakref_callback = functional.sequence(
140
+ self.wrap_weakref_callback,
141
+ lambda callback:
142
+ utils.observer(
143
+ on_call = functional.lazy(set, False),
144
+ on_result = functional.lazy(set, True),
145
+ on_error = functional.lazy(set, True),
146
+ function = callback))
147
+
148
+ self.exclude_from_stacktrace(RecordProxySystem.patch_type)
149
+ self.exclude_from_stacktrace(patch_find_spec.__call__)
91
150
 
92
151
  self.extended_types = {}
93
- self.bindings = utils.id_dict()
94
- self.next_placeholder_id = 0
95
152
 
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)))
153
+ sync_handle = self.writer.handle('SYNC')
101
154
 
102
- self.sync = lambda function: functional.firstof(thread_switch_monitor, functional.always(self.writer.handle('SYNC')), function)
103
-
155
+ self.on_ext_call = functional.lazy(utils.runall(maybe_collect, sync_handle) if maybe_collect else sync_handle)
156
+
157
+ write_sync = thread_state.dispatch(utils.noop, internal = functional.lazy(sync_handle))
158
+
159
+ self.sync = lambda function: \
160
+ utils.observer(on_call = write_sync, function = function)
104
161
  error = self.writer.handle('ERROR')
105
162
 
106
163
  def write_error(cls, val, traceback):
164
+ assert isinstance(val, BaseException)
107
165
  error(cls, val)
108
166
 
109
- self.set_thread_id = functional.partial(utils.set_thread_id, self.writer)
110
-
111
- def watch(f): return functional.either(thread_switch_monitor, f)
112
-
113
167
  tracer = Tracer(tracing_config, writer = self.writer.handle('TRACE'))
114
168
 
115
- self.wrap_int_to_ext = watch
169
+ self.writer.exclude_from_stacktrace(write_error)
170
+ # self.writer.exclude_from_stacktrace(Tracer.write_call)
116
171
 
117
- self.on_int_call = functional.mapargs(transform = serialize, function = self.writer.handle('CALL'))
172
+ self.on_int_call = self.writer.handle('CALL')
118
173
 
119
- self.on_ext_result = functional.if_then_else(
120
- functional.isinstanceof(str),
121
- self.writer.handle('RESULT'),
122
- functional.sequence(serialize, self.writer))
174
+ # write_new_ref = self.writer.handle('RESULT')
175
+
176
+ self.on_ext_result = self.writer.handle('RESULT')
123
177
 
124
178
  self.on_ext_error = write_error
125
179
 
126
- self.ext_apply = self.int_apply = functional.apply
180
+ self.writer.type_serializer[types.ModuleType] = GlobalRef
127
181
 
128
- super().__init__(thread_state = thread_state, tracer = tracer, immutable_types = immutable_types)
182
+ self.bind = self.writer.bind
129
183
 
130
- def dynamic_ext_proxytype(self, cls):
131
-
132
- proxytype = super().dynamic_ext_proxytype(cls)
184
+ self.create_from_external = self.writer.ext_bind
133
185
 
134
- blacklist = ['__class__', '__dict__', '__module__', '__doc__']
186
+ self.write_trace = self.writer.handle('TRACER')
135
187
 
136
- methods = []
137
- members = []
188
+ self.checkpoint = self.writer.handle('CHECKPOINT')
138
189
 
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)
190
+ self.on_weakref_callback_start = functional.lazy(self.writer.handle('ON_WEAKREF_CALLBACK_START'))
191
+ self.on_weakref_callback_end = functional.lazy(self.writer.handle('ON_WEAKREF_CALLBACK_END'))
145
192
 
146
- ref = self.writer.handle(StubRef(
147
- name = cls.__name__,
148
- module = cls.__module__,
149
- methods = methods,
150
- members = members))
151
-
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)
193
+ self.on_start_collect = self.writer.handle('ON_START_COLLECT')
194
+ self.on_end_collect = self.writer.handle('ON_END_COLLECT')
170
195
 
171
- return proxytype
196
+ super().__init__(thread_state = thread_state,
197
+ tracer = tracer,
198
+ traceargs = traceargs,
199
+ immutable_types = immutable_types)
172
200
 
173
201
  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
-
202
+
178
203
  proxytype = super().ext_proxytype(cls)
179
204
 
180
- assert resolve(cls) is cls
205
+ ref = self.writer.handle(StubRef(proxytype))
181
206
 
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)]
207
+ self.writer.type_serializer[proxytype] = functional.constantly(ref)
194
208
 
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
209
  return proxytype
202
210
 
203
211
 
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)
210
-
211
- self.extended_types[cls] = extended
212
-
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)
220
-
221
- return extended