##// END OF EJS Templates
switching to gc.get_referrers() allows for a very simple and (hopefully) efficient update of old class instances
Niclas -
Show More
@@ -115,7 +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 import gc
119 from importlib import import_module
119 from importlib import import_module
120 from importlib.util import source_from_cache
120 from importlib.util import source_from_cache
121 from imp import reload
121 from imp import reload
@@ -268,56 +268,16 b' def update_function(old, new):'
268 pass
268 pass
269
269
270
270
271 def update_instances(old, new, objects=None, visited={}):
271 def update_instances(old, new):
272 """Iterate through objects recursively, searching for instances of old and
272 """Use garbage collector to find all instances that refer to the old
273 replace their __class__ reference with new. If no objects are given, start
273 class definition and update their __class__ to point to the new class
274 with the current ipython workspace.
274 definition"""
275 """
276 if objects is None:
277 # make sure visited is cleaned when not called recursively
278 visited = {}
279 # find ipython workspace stack frame
280 frame = next(frame_nfo.frame for frame_nfo in inspect.stack()
281 if 'trigger' in frame_nfo.function)
282 # build generator for non-private variable values from workspace
283 shell = frame.f_locals['self'].shell
284 user_ns = shell.user_ns
285 user_ns_hidden = shell.user_ns_hidden
286 nonmatching = object()
287 objects = ( value for key, value in user_ns.items()
288 if not key.startswith('_')
289 and (value is not user_ns_hidden.get(key, nonmatching))
290 and not inspect.ismodule(value))
291
275
292 # use dict values if objects is a dict but don't touch private variables
276 refs = gc.get_referrers(old)
293 if hasattr(objects, 'items'):
294 objects = (value for key, value in objects.items()
295 if not str(key).startswith('_')
296 and not inspect.ismodule(value) )
297
277
298 # try if objects is iterable
278 for ref in refs:
299 try:
279 if type(ref) is old:
300 for obj in (obj for obj in objects if id(obj) not in visited):
280 ref.__class__ = new
301 # add current object to visited to avoid revisiting
302 visited.update({id(obj):obj})
303
304 # update, if object is instance of old_class (but no subclasses)
305 if type(obj) is old:
306 obj.__class__ = new
307
308
309 # if object is instance of other class, look for nested instances
310 if hasattr(obj, '__dict__') and not (inspect.isfunction(obj)
311 or inspect.ismethod(obj)):
312 update_instances(old, new, obj.__dict__, visited)
313
314 # if object is a container, search it
315 if hasattr(obj, 'items') or (hasattr(obj, '__contains__')
316 and not isinstance(obj, str)):
317 update_instances(old, new, obj, visited)
318
319 except TypeError:
320 pass
321
281
322
282
323 def update_class(old, new):
283 def update_class(old, new):
General Comments 0
You need to be logged in to leave comments. Login now