diff --git a/IPython/core/magic.py b/IPython/core/magic.py index aff945f..ba8bf82 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -55,6 +55,7 @@ from IPython.lib.pylabtools import mpl_runner from IPython.testing.skipdoctest import skip_doctest from IPython.utils import py3compat from IPython.utils.io import file_read, nlprint +from IPython.utils.module_paths import find_mod from IPython.utils.path import get_py_filename, unquote_filename from IPython.utils.process import arg_split, abbrev_cwd from IPython.utils.terminal import set_term_title @@ -92,85 +93,6 @@ def needs_local_scope(func): func.needs_local_scope = True return func -def find_module(name, path=None): - """imp.find_module variant that only return path of module. - - The `imp.find_module` returns a filehandle that we are not interested in. - Also we ignore any bytecode files that `imp.find_module` finds. - - Parameters - ---------- - name : str - name of module to locate - path : list of str - list of paths to search for `name`. If path=None then search sys.path - - Returns - ------- - filename : str - Return full path of module or None if module is missing or does not have - .py or .pyw extension - """ - if name is None: - return None - try: - file, filename, _ = imp.find_module(name, path) - except ImportError: - return None - if file is None: - return filename - else: - file.close() - if os.path.splitext(filename)[1] in [".py", "pyc"]: - return filename - else: - return None - -def get_init(dirname): - """Get __init__ file path for module directory - - Parameters - ---------- - dirname : str - Find the __init__ file in directory `dirname` - - Returns - ------- - init_path : str - Path to __init__ file - """ - fbase = os.path.join(dirname, "__init__") - for ext in [".py", ".pyw"]: - fname = fbase + ext - if os.path.isfile(fname): - return fname - - -def find_mod(module_name): - """Find module `module_name` on sys.path - - Return the path to module `module_name`. If `module_name` refers to - a module directory then return path to __init__ file. Return full - path of module or None if module is missing or does not have .py or .pyw - extension. We are not interested in running bytecode. - - Parameters - ---------- - module_name : str - - Returns - ------- - modulepath : str - Path to module `module_name`. - """ - parts = module_name.split(".") - basepath = find_module(parts[0]) - for submodname in parts[1:]: - basepath = find_module(submodname, [basepath]) - if basepath and os.path.isdir(basepath): - basepath = get_init(basepath) - return basepath - # Used for exception handling in magic_edit class MacroToEdit(ValueError): pass diff --git a/IPython/utils/module_paths.py b/IPython/utils/module_paths.py new file mode 100644 index 0000000..bcdc790 --- /dev/null +++ b/IPython/utils/module_paths.py @@ -0,0 +1,125 @@ +"""Utility functions for finding modules + +Utility functions for finding modules on sys.path. + +`find_mod` finds named module on sys.path. + +`get_init` helper function that finds __init__ file in a directory. + +`find_module` variant of imp.find_module in std_lib that only returns +path to module and not an open file object as well. + + + +""" +#----------------------------------------------------------------------------- +# Copyright (c) 2011, the IPython Development Team. +# +# Distributed under the terms of the Modified BSD License. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- +from __future__ import print_function + +# Stdlib imports +import imp +import os + +# Third-party imports + +# Our own imports + + +#----------------------------------------------------------------------------- +# Globals and constants +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Local utilities +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Classes and functions +#----------------------------------------------------------------------------- +def find_module(name, path=None): + """imp.find_module variant that only return path of module. + + The `imp.find_module` returns a filehandle that we are not interested in. + Also we ignore any bytecode files that `imp.find_module` finds. + + Parameters + ---------- + name : str + name of module to locate + path : list of str + list of paths to search for `name`. If path=None then search sys.path + + Returns + ------- + filename : str + Return full path of module or None if module is missing or does not have + .py or .pyw extension + """ + if name is None: + return None + try: + file, filename, _ = imp.find_module(name, path) + except ImportError: + return None + if file is None: + return filename + else: + file.close() + if os.path.splitext(filename)[1] in [".py", "pyc"]: + return filename + else: + return None + +def get_init(dirname): + """Get __init__ file path for module directory + + Parameters + ---------- + dirname : str + Find the __init__ file in directory `dirname` + + Returns + ------- + init_path : str + Path to __init__ file + """ + fbase = os.path.join(dirname, "__init__") + for ext in [".py", ".pyw"]: + fname = fbase + ext + if os.path.isfile(fname): + return fname + + +def find_mod(module_name): + """Find module `module_name` on sys.path + + Return the path to module `module_name`. If `module_name` refers to + a module directory then return path to __init__ file. Return full + path of module or None if module is missing or does not have .py or .pyw + extension. We are not interested in running bytecode. + + Parameters + ---------- + module_name : str + + Returns + ------- + modulepath : str + Path to module `module_name`. + """ + parts = module_name.split(".") + basepath = find_module(parts[0]) + for submodname in parts[1:]: + basepath = find_module(submodname, [basepath]) + if basepath and os.path.isdir(basepath): + basepath = get_init(basepath) + return basepath diff --git a/IPython/utils/tests/test_module_paths.py b/IPython/utils/tests/test_module_paths.py new file mode 100644 index 0000000..b63f581 --- /dev/null +++ b/IPython/utils/tests/test_module_paths.py @@ -0,0 +1,133 @@ +# encoding: utf-8 +"""Tests for IPython.utils.path.py""" + +#----------------------------------------------------------------------------- +# Copyright (C) 2008 The IPython Development Team +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#----------------------------------------------------------------------------- + +#----------------------------------------------------------------------------- +# Imports +#----------------------------------------------------------------------------- + +from __future__ import with_statement + +import os +import shutil +import sys +import tempfile +import StringIO + +from os.path import join, abspath, split + +import nose.tools as nt + +from nose import with_setup + +import IPython +from IPython.testing import decorators as dec +from IPython.testing.decorators import skip_if_not_win32, skip_win32 +from IPython.testing.tools import make_tempfile +from IPython.utils import path, io +from IPython.utils import py3compat + +import IPython.utils.module_paths as mp + +env = os.environ +TEST_FILE_PATH = split(abspath(__file__))[0] +TMP_TEST_DIR = tempfile.mkdtemp() +# +# Setup/teardown functions/decorators +# + +old_syspath = sys.path +sys.path = [TMP_TEST_DIR] + +def make_empty_file(fname): + f = open(fname, 'w') + f.close() + + +def setup(): + """Setup testenvironment for the module: + + """ + # Do not mask exceptions here. In particular, catching WindowsError is a + # problem because that exception is only defined on Windows... + os.makedirs(join(TMP_TEST_DIR, "xmod")) + os.makedirs(join(TMP_TEST_DIR, "nomod")) + make_empty_file(join(TMP_TEST_DIR, "xmod/__init__.py")) + make_empty_file(join(TMP_TEST_DIR, "xmod/sub.py")) + make_empty_file(join(TMP_TEST_DIR, "pack.py")) + make_empty_file(join(TMP_TEST_DIR, "packpyc.pyc")) + +def teardown(): + """Teardown testenvironment for the module: + + - Remove tempdir + """ + # Note: we remove the parent test dir, which is the root of all test + # subdirs we may have created. Use shutil instead of os.removedirs, so + # that non-empty directories are all recursively removed. + shutil.rmtree(TMP_TEST_DIR) + + +def test_get_init_1(): + """See if get_init can find __init__.py in this testdir""" + with make_tempfile(join(TMP_TEST_DIR, "__init__.py")): + assert mp.get_init(TMP_TEST_DIR) + +def test_get_init_2(): + """See if get_init can find __init__.pyw in this testdir""" + with make_tempfile(join(TMP_TEST_DIR, "__init__.pyw")): + assert mp.get_init(TMP_TEST_DIR) + +def test_get_init_3(): + """get_init can't find __init__.pyc in this testdir""" + with make_tempfile(join(TMP_TEST_DIR, "__init__.pyc")): + assert mp.get_init(TMP_TEST_DIR) is None + +def test_get_init_3(): + """get_init can't find __init__ in empty testdir""" + assert mp.get_init(TMP_TEST_DIR) is None + + +def test_find_mod_1(): + modpath = join(TMP_TEST_DIR, "xmod", "__init__.py") + assert mp.find_mod("xmod") == modpath + +def test_find_mod_2(): + modpath = join(TMP_TEST_DIR, "xmod", "__init__.py") + assert mp.find_mod("xmod") == modpath + +def test_find_mod_3(): + modpath = join(TMP_TEST_DIR, "xmod", "sub.py") + assert mp.find_mod("xmod.sub") == modpath + +def test_find_mod_4(): + modpath = join(TMP_TEST_DIR, "pack.py") + assert mp.find_mod("pack") == modpath + +def test_find_mod_5(): + assert mp.find_mod("packpyc") is None + +def test_find_module_1(): + modpath = join(TMP_TEST_DIR, "xmod") + assert mp.find_module("xmod") == modpath + +def test_find_module_2(): + """Testing sys.path that is empty""" + assert mp.find_module("xmod", []) is None + +def test_find_module_3(): + """Testing sys.path that is empty""" + assert mp.find_module(None, None) is None + +def test_find_module_4(): + """Testing sys.path that is empty""" + assert mp.find_module(None) is None + +def test_find_module_5(): + assert mp.find_module("xmod.nopack") is None