Show More
@@ -115,7 +115,7 b' import sys' | |||
|
115 | 115 | import traceback |
|
116 | 116 | import types |
|
117 | 117 | import weakref |
|
118 |
import |
|
|
118 | import gc | |
|
119 | 119 | from importlib import import_module |
|
120 | 120 | from importlib.util import source_from_cache |
|
121 | 121 | from imp import reload |
@@ -268,56 +268,16 b' def update_function(old, new):' | |||
|
268 | 268 | pass |
|
269 | 269 | |
|
270 | 270 | |
|
271 |
def update_instances(old, new |
|
|
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 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)) | |
|
271 | def update_instances(old, new): | |
|
272 | """Use garbage collector to find all instances that refer to the old | |
|
273 | class definition and update their __class__ to point to the new class | |
|
274 | definition""" | |
|
291 | 275 | |
|
292 | # use dict values if objects is a dict but don't touch private variables | |
|
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) ) | |
|
276 | refs = gc.get_referrers(old) | |
|
297 | 277 | |
|
298 | # try if objects is iterable | |
|
299 | try: | |
|
300 | for obj in (obj for obj in objects if id(obj) not in visited): | |
|
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 | |
|
278 | for ref in refs: | |
|
279 | if type(ref) is old: | |
|
280 | ref.__class__ = new | |
|
321 | 281 | |
|
322 | 282 | |
|
323 | 283 | def update_class(old, new): |
General Comments 0
You need to be logged in to leave comments.
Login now