Skip to content

Instantly share code, notes, and snippets.

@mdevaev
Last active August 29, 2015 14:03
Show Gist options
  • Save mdevaev/b7eb44fc7d96d4f5414b to your computer and use it in GitHub Desktop.
Save mdevaev/b7eb44fc7d96d4f5414b to your computer and use it in GitHub Desktop.
Import module from path
import sys
import importlib.abc
# =====
def setup(*args, **kwargs):
finder = _Finder(*args, **kwargs)
sys.meta_path = [finder] + sys.meta_path
return finder
def remove(finder):
sys.meta_path.remove(finder)
# =====
class _Finder(importlib.abc.Finder):
def __init__(self, root_name, get_path):
assert callable(get_path), "get_path() must be a callable"
self._root_name = root_name
self._get_path = get_path
def find_module(self, fullname, path=None):
if fullname.split(".")[0] == self._root_name:
if sys.version_info[:2] == (3, 2): # PyPy/Python 3.2 hacks
import importlib._bootstrap # pylint: disable=W0621
finder = importlib._bootstrap._file_path_hook(self._get_path()) # pylint: disable=W0212
return finder.find_module(fullname)
elif sys.version_info[:2] == (3, 4): # Python 3.4
import importlib.machinery
finder = importlib.machinery.PathFinder
return finder.find_module(fullname, [self._get_path()])
else:
RuntimeError("No importlib hacks for your Python: {}".format(sys.version_info))
return None
@mdevaev
Copy link
Author

mdevaev commented Jul 4, 2014

Test:

# pylint: disable=R0904


import sys
import os
import unittest
import tempfile
import shutil
import contextlib

import impfrom


# =====
@contextlib.contextmanager
def _new_module(name):
    path = tempfile.mkdtemp(prefix="/tmp/")
    finder = impfrom.setup(name, lambda: path)
    yield (path, finder)
    impfrom.remove(finder)
    try:
        del sys.modules[name]
    except KeyError:
        pass
    shutil.rmtree(path)


# =====
class TestImpFrom(unittest.TestCase):
    def test_setup_remove(self):
        with _new_module("test_setup_remove") as (_, finder):
            self.assertTrue(finder in sys.meta_path)

    def test_import_module(self):
        with _new_module("test_import_module") as (path, _):
            with open(os.path.join(path, "test_import_module.py"), "w") as module_file:
                module_file.write("VAR1 = 1")
            import test_import_module  # pylint: disable=F0401
            self.assertEqual(test_import_module.VAR1, 1)

    def test_import_var_from_module(self):
        with _new_module("test_import_var_from_module") as (path, _):
            with open(os.path.join(path, "test_import_var_from_module.py"), "w") as module_file:
                module_file.write("VAR2 = 2")
            from test_import_var_from_module import VAR2  # pylint: disable=F0401
            self.assertEqual(VAR2, 2)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment