##// END OF EJS Templates
allow type of already existing class instances to be updated
Niclas -
Show More
@@ -115,6 +115,7 b' import sys'
115 import traceback
115 import traceback
116 import types
116 import types
117 import weakref
117 import weakref
118 import inspect
118 from importlib import import_module
119 from importlib import import_module
119 from importlib.util import source_from_cache
120 from importlib.util import source_from_cache
120 from imp import reload
121 from imp import reload
@@ -267,6 +268,54 b' def update_function(old, new):'
267 pass
268 pass
268
269
269
270
271 def update_instances(old, new, objects=None):
272 """Iterate through objects recursively, searching for instances of old and
273 replace their __class__ reference with new. If no objects are given, start
274 with the current ipython workspace.
275 """
276 if not objects:
277 # find ipython workspace stack frame
278 frame = next(frame_nfo.frame for frame_nfo in inspect.stack()
279 if 'trigger' in frame_nfo.function)
280 # build generator for non-private variable values from workspace
281 shell = frame.f_locals['self'].shell
282 user_ns = shell.user_ns
283 user_ns_hidden = shell.user_ns_hidden
284 nonmatching = object()
285 objects = ( value for key, value in user_ns.items()
286 if not key.startswith('_')
287 and (value is not user_ns_hidden.get(key, nonmatching))
288 and not inspect.ismodule(value))
289
290 # use dict values if objects is a dict but don't touch private variables
291 if hasattr(objects, 'items'):
292 objects = (value for key, value in objects.items()
293 if not str(key).startswith('_')
294 and not inspect.ismodule(value) )
295
296 # try if objects is iterable
297 try:
298 for obj in objects:
299
300 # update, if object is instance of old_class (but no subclasses)
301 if type(obj) is old:
302 obj.__class__ = new
303
304
305 # if object is instance of other class, look for nested instances
306 if hasattr(obj, '__dict__') and not (inspect.isfunction(obj)
307 or inspect.ismethod(obj)):
308 update_instances(old, new, obj.__dict__)
309
310 # if object is a container, search it
311 if hasattr(obj, 'items') or (hasattr(obj, '__contains__')
312 and not isinstance(obj, str)):
313 update_instances(old, new, obj)
314
315 except TypeError:
316 pass
317
318
270 def update_class(old, new):
319 def update_class(old, new):
271 """Replace stuff in the __dict__ of a class, and upgrade
320 """Replace stuff in the __dict__ of a class, and upgrade
272 method code objects, and add new methods, if any"""
321 method code objects, and add new methods, if any"""
@@ -300,6 +349,9 b' def update_class(old, new):'
300 except (AttributeError, TypeError):
349 except (AttributeError, TypeError):
301 pass # skip non-writable attributes
350 pass # skip non-writable attributes
302
351
352 # update all instances of class
353 update_instances(old, new)
354
303
355
304 def update_property(old, new):
356 def update_property(old, new):
305 """Replace get/set/del functions of a property"""
357 """Replace get/set/del functions of a property"""
General Comments 0
You need to be logged in to leave comments. Login now