##// END OF EJS Templates
Merge branch 'main' into main
Merge branch 'main' into main

File last commit:

r27159:30e5a5d3
r27905:5c9ddef8 merge
Show More
deepreload.py
310 lines | 9.2 KiB | text/x-python | PythonLexer
Ville M. Vainio
crlf -> lf
r1032 # -*- coding: utf-8 -*-
"""
Thomas Kluyver
Update docstring for deepreload module
r15811 Provides a reload() function that acts recursively.
Fernando Perez
Fixes to testing....
r1376
Thomas Kluyver
Update docstring for deepreload module
r15811 Python's normal :func:`python:reload` function only reloads the module that it's
passed. The :func:`reload` function in this module also reloads everything
imported from that module, which is useful when you're changing files deep
inside a package.
Terry Davis
Remove python 2 references from docstrings, where appropriate.
r25450 To use this as your default reload function, type this::
Bernardo B. Marques
remove all trailling spaces
r4872
Thomas Kluyver
Update docstring for deepreload module
r15811 import builtins
from IPython.lib import deepreload
builtins.reload = deepreload.reload
Brian Granger
More work addressing review comments for Fernando's branch....
r2499
Thomas Kluyver
Update docstring for deepreload module
r15811 A reference to the original :func:`python:reload` is stored in this module as
:data:`original_reload`, so you can restore it later.
Bernardo B. Marques
remove all trailling spaces
r4872
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 This code is almost entirely based on knee.py, which is a Python
re-implementation of hierarchical module import.
Fernando Perez
Remove svn-style $Id marks from docstrings and Release imports....
r1853 """
Ville M. Vainio
crlf -> lf
r1032 #*****************************************************************************
# Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#*****************************************************************************
Thomas Kluyver
Remove uses of compatibility builtin_mod and builtin_mod_name
r23129 import builtins as builtin_mod
Thomas Kluyver
Fix deepreload on Python 3....
r6548 from contextlib import contextmanager
Nikita Kniazev
Port `deepreload` to `importlib`...
r27044 import importlib
Ville M. Vainio
crlf -> lf
r1032 import sys
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 from types import ModuleType
from warnings import warn
Matthias Bussonnier
Avoid reloading builtin `types` module....
r23391 import types
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531
Thomas Kluyver
Fix imports of builtins module
r13351 original_import = builtin_mod.__import__
Thomas Kluyver
Fix deepreload on Python 3....
r6548
@contextmanager
def replace_import_hook(new_import):
Thomas Kluyver
Fix imports of builtins module
r13351 saved_import = builtin_mod.__import__
builtin_mod.__import__ = new_import
Thomas Kluyver
Fix deepreload on Python 3....
r6548 try:
yield
finally:
Thomas Kluyver
Fix imports of builtins module
r13351 builtin_mod.__import__ = saved_import
Thomas Kluyver
Fix deepreload on Python 3....
r6548
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 def get_parent(globals, level):
"""
parent, name = get_parent(globals, level)
Return the package that an import is being performed in. If globals comes
from the module foo.bar.bat (not itself a package), this returns the
sys.modules entry for foo.bar. If globals is from a package's __init__.py,
the package's entry in sys.modules is returned.
If globals doesn't come from a package or a module in a package, or a
corresponding entry is not found in sys.modules, None is returned.
"""
orig_level = level
Ville M. Vainio
crlf -> lf
r1032
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 if not level or not isinstance(globals, dict):
return None, ''
pkgname = globals.get('__package__', None)
if pkgname is not None:
# __package__ is set, so use it
if not hasattr(pkgname, 'rindex'):
raise ValueError('__package__ set to non-string')
if len(pkgname) == 0:
if level > 0:
raise ValueError('Attempted relative import in non-package')
return None, ''
name = pkgname
Ville M. Vainio
crlf -> lf
r1032 else:
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 # __package__ not set, so figure it out and set it
if '__name__' not in globals:
return None, ''
modname = globals['__name__']
if '__path__' in globals:
# __path__ is set, so modname is already the package name
globals['__package__'] = name = modname
else:
# Normal module, so work out the package name if any
lastdot = modname.rfind('.')
Rémy Léone
Simplify comparison
r21780 if lastdot < 0 < level:
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 raise ValueError("Attempted relative import in non-package")
if lastdot < 0:
globals['__package__'] = None
return None, ''
globals['__package__'] = name = modname[:lastdot]
dot = len(name)
Thomas Kluyver
Fix references to xrange
r13356 for x in range(level, 1, -1):
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 try:
dot = name.rindex('.', 0, dot)
Ram Rachum
Fix exception causes all over the codebase
r25833 except ValueError as e:
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 raise ValueError("attempted relative import beyond top-level "
Ram Rachum
Fix exception causes all over the codebase
r25833 "package") from e
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 name = name[:dot]
try:
parent = sys.modules[name]
Ram Rachum
Fix exception causes all over the codebase
r25833 except BaseException as e:
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 if orig_level < 1:
warn("Parent module '%.200s' not found while handling absolute "
"import" % name)
parent = None
else:
raise SystemError("Parent module '%.200s' not loaded, cannot "
Ram Rachum
Fix exception causes all over the codebase
r25833 "perform relative import" % name) from e
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531
# We expect, but can't guarantee, if parent != None, that:
# - parent.__name__ == name
# - parent.__dict__ is globals
# If this is violated... Who cares?
return parent, name
def load_next(mod, altmod, name, buf):
"""
mod, name, buf = load_next(mod, altmod, name, buf)
altmod is either None or same as mod
"""
if len(name) == 0:
# completely empty module name should only happen in
# 'from . import' (or '__import__("")')
return mod, None, buf
dot = name.find('.')
if dot == 0:
raise ValueError('Empty module name')
if dot < 0:
subname = name
next = None
Ville M. Vainio
crlf -> lf
r1032 else:
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 subname = name[:dot]
next = name[dot+1:]
Ville M. Vainio
crlf -> lf
r1032
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 if buf != '':
buf += '.'
buf += subname
result = import_submodule(mod, subname, buf)
if result is None and mod != altmod:
result = import_submodule(altmod, subname, subname)
if result is not None:
buf = subname
if result is None:
raise ImportError("No module named %.200s" % name)
return result, next, buf
Ville M. Vainio
crlf -> lf
r1032
Matthias Bussonnier
Avoid reloading builtin `types` module....
r23391
Ville M. Vainio
crlf -> lf
r1032 # Need to keep track of what we've already reloaded to prevent cyclic evil
found_now = {}
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 def import_submodule(mod, subname, fullname):
"""m = import_submodule(mod, subname, fullname)"""
# Require:
# if mod == None: subname == fullname
# else: mod.__name__ + "." + subname == fullname
Ville M. Vainio
crlf -> lf
r1032 global found_now
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 if fullname in found_now and fullname in sys.modules:
m = sys.modules[fullname]
else:
Thomas Kluyver
Convert print statements to print function calls...
r13348 print('Reloading', fullname)
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 found_now[fullname] = 1
oldm = sys.modules.get(fullname, None)
try:
Nikita Kniazev
Port `deepreload` to `importlib`...
r27044 if oldm is not None:
m = importlib.reload(oldm)
else:
m = importlib.import_module(subname, mod)
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 except:
# load_module probably removed name from modules because of
# the error. Put back the original module object.
if oldm:
sys.modules[fullname] = oldm
raise
add_submodule(mod, m, fullname, subname)
return m
def add_submodule(mod, submod, fullname, subname):
"""mod.{subname} = submod"""
if mod is None:
return #Nothing to do here.
if submod is None:
submod = sys.modules[fullname]
Bernardo B. Marques
remove all trailling spaces
r4872
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 setattr(mod, subname, submod)
return
def ensure_fromlist(mod, fromlist, buf, recursive):
"""Handle 'from module import a, b, c' imports."""
if not hasattr(mod, '__path__'):
return
for item in fromlist:
if not hasattr(item, 'rindex'):
raise TypeError("Item in ``from list'' not a string")
if item == '*':
if recursive:
continue # avoid endless recursion
try:
all = mod.__all__
except AttributeError:
pass
else:
ret = ensure_fromlist(mod, all, buf, 1)
if not ret:
return 0
elif not hasattr(mod, item):
import_submodule(mod, item, buf + '.' + item)
Bradley M. Froehle
Keep original function names.
r6532 def deep_import_hook(name, globals=None, locals=None, fromlist=None, level=-1):
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 """Replacement for __import__()"""
parent, buf = get_parent(globals, level)
head, name, buf = load_next(parent, None if level < 0 else parent, name, buf)
tail = head
while name:
tail, name, buf = load_next(tail, tail, name, buf)
# If tail is None, both get_parent and load_next found
# an empty module name: someone called __import__("") or
# doctored faulty bytecode
if tail is None:
raise ValueError('Empty module name')
if not fromlist:
return head
Bernardo B. Marques
remove all trailling spaces
r4872
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 ensure_fromlist(tail, fromlist, buf, 0)
return tail
modules_reloading = {}
Bradley M. Froehle
Keep original function names.
r6532 def deep_reload_hook(m):
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 """Replacement for reload()."""
Min ho Kim
Fixed typos
r25167 # Hardcode this one as it would raise a NotImplementedError from the
Matthias Bussonnier
Avoid reloading builtin `types` module....
r23391 # bowels of Python and screw up the import machinery after.
luzpaz
Misc. typo fixes...
r24084 # unlike other imports the `exclude` list already in place is not enough.
Matthias Bussonnier
Avoid reloading builtin `types` module....
r23391
if m is types:
return m
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 if not isinstance(m, ModuleType):
raise TypeError("reload() argument must be module")
name = m.__name__
if name not in sys.modules:
raise ImportError("reload(): module %.200s not in sys.modules" % name)
global modules_reloading
Ville M. Vainio
crlf -> lf
r1032 try:
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 return modules_reloading[name]
except:
modules_reloading[name] = m
try:
Nikita Kniazev
Port `deepreload` to `importlib`...
r27044 newm = importlib.reload(m)
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 except:
sys.modules[name] = m
raise
finally:
Nikita Kniazev
Port `deepreload` to `importlib`...
r27044 modules_reloading.clear()
Bradley M. Froehle
Update deepreload to use a rewritten knee.py. Fixes dreload(numpy)....
r6531 return newm
Ville M. Vainio
crlf -> lf
r1032
# Save the original hooks
Nikita Kniazev
Port `deepreload` to `importlib`...
r27044 original_reload = importlib.reload
Ville M. Vainio
crlf -> lf
r1032
# Replacement for reload()
Nikita Kniazev
deepreload: Use `sys.builtin_module_names` to exclude builtins
r27159 def reload(
module,
exclude=(
*sys.builtin_module_names,
"sys",
"os.path",
"builtins",
"__main__",
"numpy",
"numpy._globals",
),
):
Ville M. Vainio
crlf -> lf
r1032 """Recursively reload all modules used in the given module. Optionally
takes a list of modules to exclude from reloading. The default exclude
Nikita Kniazev
deepreload: Use `sys.builtin_module_names` to exclude builtins
r27159 list contains modules listed in sys.builtin_module_names with additional
sys, os.path, builtins and __main__, to prevent, e.g., resetting
Ville M. Vainio
crlf -> lf
r1032 display, exception, and io hooks.
"""
global found_now
for i in exclude:
found_now[i] = 1
try:
Thomas Kluyver
Fix deepreload on Python 3....
r6548 with replace_import_hook(deep_import_hook):
Abhinav Upadhyay
Return value directly from the try block and avoid a variable...
r12882 return deep_reload_hook(module)
Ville M. Vainio
crlf -> lf
r1032 finally:
found_now = {}