diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 2b26ebe..fb2df90 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -692,6 +692,11 @@ class ExecutionMagics(Magics): warn('For Windows, use double quotes to wrap a filename: %run "mypath\\myfile.py"') error(msg) return + except TypeError: + if fpath in sys.meta_path: + filename = "" + else: + raise if filename.lower().endswith(('.ipy', '.ipynb')): with preserve_keys(self.shell.user_ns, '__file__'): diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 5f58b11..e5ad820 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -1198,3 +1198,49 @@ def test_timeit_arguments(): # 3.7 optimize no-op statement like above out, and complain there is # nothing in the for loop. _ip.magic("timeit -n1 -r1 a=('#')") + + +TEST_MODULE = """ +print('Loaded my_tmp') +if __name__ == "__main__": + print('I just ran a script') +""" + + +def test_run_module_from_import_hook(): + "Test that a module can be loaded via an import hook" + with TemporaryDirectory() as tmpdir: + fullpath = os.path.join(tmpdir, 'my_tmp.py') + with open(fullpath, 'w') as f: + f.write(TEST_MODULE) + + class MyTempImporter(object): + def __init__(self): + pass + + def find_module(self, fullname, path=None): + if 'my_tmp' in fullname: + return self + return None + + def load_module(self, name): + import imp + return imp.load_source('my_tmp', fullpath) + + def get_code(self, fullname): + with open(fullpath, 'r') as f: + return compile(f.read(), 'foo', 'exec') + + def is_package(self, __): + return False + + sys.meta_path.insert(0, MyTempImporter()) + + with capture_output() as captured: + _ip.magic("run -m my_tmp") + _ip.run_cell("import my_tmp") + + output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n" + nt.assert_equal(output, captured.stdout) + + sys.meta_path.pop(0) diff --git a/IPython/utils/module_paths.py b/IPython/utils/module_paths.py index 0570c32..32ecab8 100644 --- a/IPython/utils/module_paths.py +++ b/IPython/utils/module_paths.py @@ -20,6 +20,7 @@ Utility functions for finding modules on sys.path. # Stdlib imports import importlib import os +import sys # Third-party imports @@ -61,6 +62,8 @@ def find_mod(module_name): loader = importlib.util.find_spec(module_name) module_path = loader.origin if module_path is None: + if loader.loader in sys.meta_path: + return loader.loader return None else: split_path = module_path.split(".")