From 8a8884b399cf3f5b761313bf0d446ba204f2c810 2012-01-18 22:51:46 From: Thomas Kluyver Date: 2012-01-18 22:51:46 Subject: [PATCH] Make autoreload extension work on Python 3. Some changes for Python 3 in general, and some changes for the .pyc repository directories introduced in Python 3.2 (PEP 3147) Closes gh-846 --- diff --git a/IPython/extensions/autoreload.py b/IPython/extensions/autoreload.py index 2080bc4..cdb9164 100644 --- a/IPython/extensions/autoreload.py +++ b/IPython/extensions/autoreload.py @@ -108,6 +108,9 @@ try: except NameError: from imp import reload +from IPython.utils import pyfile +from IPython.utils.py3compat import PY3 + def _get_compiled_ext(): """Official way to get the extension of compiled files (.pyc or .pyo)""" for ext, mode, typ in imp.get_suffixes(): @@ -198,11 +201,14 @@ class ModuleReloader(object): if ext.lower() == '.py': ext = PY_COMPILED_EXT - pyc_filename = path + PY_COMPILED_EXT + pyc_filename = pyfile.cache_from_source(filename) py_filename = filename else: pyc_filename = filename - py_filename = filename[:-1] + try: + py_filename = pyfile.source_from_cache(filename) + except ValueError: + continue if ext != PY_COMPILED_EXT: continue @@ -229,10 +235,16 @@ class ModuleReloader(object): # superreload #------------------------------------------------------------------------------ +if PY3: + func_attrs = ['__code__', '__defaults__', '__doc__', + '__closure__', '__globals__', '__dict__'] +else: + func_attrs = ['func_code', 'func_defaults', 'func_doc', + 'func_closure', 'func_globals', 'func_dict'] + def update_function(old, new): """Upgrade the code object of a function""" - for name in ['func_code', 'func_defaults', 'func_doc', - 'func_closure', 'func_globals', 'func_dict']: + for name in func_attrs: try: setattr(old, name, getattr(new, name)) except (AttributeError, TypeError): @@ -271,18 +283,26 @@ def isinstance2(a, b, typ): return isinstance(a, typ) and isinstance(b, typ) UPDATE_RULES = [ - (lambda a, b: isinstance2(a, b, types.ClassType), - update_class), - (lambda a, b: isinstance2(a, b, types.TypeType), + (lambda a, b: isinstance2(a, b, type), update_class), (lambda a, b: isinstance2(a, b, types.FunctionType), update_function), (lambda a, b: isinstance2(a, b, property), update_property), - (lambda a, b: isinstance2(a, b, types.MethodType), - lambda a, b: update_function(a.im_func, b.im_func)), ] +if PY3: + UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.MethodType), + lambda a, b: update_function(a.__func__, b.__func__)), + ]) +else: + UPDATE_RULES.extend([(lambda a, b: isinstance2(a, b, types.ClassType), + update_class), + (lambda a, b: isinstance2(a, b, types.MethodType), + lambda a, b: update_function(a.im_func, b.im_func)), + ]) + + def update_generic(a, b): for type_check, update in UPDATE_RULES: if type_check(a, b): @@ -317,7 +337,7 @@ def superreload(module, reload=reload, old_objects={}): except TypeError: # weakref doesn't work for all types; # create strong references for 'important' cases - if isinstance(obj, types.ClassType): + if not PY3 and isinstance(obj, types.ClassType): old_objects.setdefault(key, []).append(StrongRef(obj)) # reload module diff --git a/IPython/extensions/tests/test_autoreload.py b/IPython/extensions/tests/test_autoreload.py index 2227a06..d8604fa 100644 --- a/IPython/extensions/tests/test_autoreload.py +++ b/IPython/extensions/tests/test_autoreload.py @@ -294,12 +294,8 @@ x = -99 self.shell.run_code("pass") # trigger reload nt.assert_equal(mod.x, -99) - # The autoreload extension needs to be updated for Python 3.2, as .pyc files - # are stored in a different location. See gh-846. - @knownfailureif(sys.version_info >= (3,2)) def test_smoketest_aimport(self): self._check_smoketest(use_aimport=True) - @knownfailureif(sys.version_info >= (3,2)) def test_smoketest_autoreload(self): self._check_smoketest(use_aimport=False)