diff --git a/README.md b/README.md index 8255d50..ac665cf 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,26 @@ simport ======= Simple Import Library for Python + +Supports importing functions or class methods from files +not in the Python Path. + +Using Simport +============= + +{{{ +import simport + +# For modules already in the Python Path +function = simport.load('mymodule.myfunction') +class_method = simport.load('mymodule:MyClass.mymethod') + +# For modules not in the Python Path +function = simport.load('/path/to/file.py|module_name:myfunction') +class_method = simport.load('/path/to/file.py|module_name:MyClasss.mymethod') +}}} + +Running Tests +============= +From the simport root directory, run `nosetests` + diff --git a/simport/__init__.py b/simport/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/simport/simport.py b/simport/simport.py index 092ee59..ba43771 100644 --- a/simport/simport.py +++ b/simport/simport.py @@ -26,7 +26,7 @@ class MissingModule(Exception): pass -class MissingFile(Exception): +class BadDirectory(Exception): pass @@ -42,45 +42,47 @@ def _get_module(target): ".../file/path|module_name:function" If a fully qualified file is specified, it implies the - file is not already on the Python Path. In this case, - the module name given will be assigned to this file. + file is not already on the Python Path, in which case + it will be added. For example, if I import /home/foo/my_code.py (and /home/foo is not in the python path) as "/home/foo/my_code.py|mycode:MyClass.mymethod" - then the MyClass class will live under the newly created - mycode module and can be referenced as mycode.MyClass + then /home/foo will be added to the python path and + the module loaded as normal. """ - filename, sep, namespace = target.rpartition('|') - # print "%s/%s/%s" % (filename, sep, namespace) - module, sep, klass_or_function = namespace.rpartition(':') + print "cwd:", os.getcwd() + directory, sep, namespace = target.rpartition('|') + module, sep, class_or_function = namespace.rpartition(':') if not module: raise MissingModule("Need a module path for %s (%s)" % (namespace, target)) - if filename: - if not module in sys.modules: - if os.path.isfile(filename): - imp.load_source(module, filename) - else: - raise MissingFile("Can not find %s" % filename) + if directory and directory not in sys.path: + print "add directory:", directory + if not os.path.isdir(directory): + raise BadDirectory("No such directory: '%s'" % directory) + sys.path.append(directory) - if not module in sys.modules: - __import__(module) - - if not klass_or_function: + if not class_or_function: raise MissingMethodOrFunction("No Method or Function specified") - klass, sep, function = klass_or_function.rpartition('.') + + print "__IMPORT__" + __import__(module) + + klass, sep, function = class_or_function.rpartition('.') + print "CLASS:", klass, "FUNCTION:", function return module, klass, function -def simport(target): +def load(target): """Get the actual implementation of the target.""" module, klass, function = _get_module(target) if not klass: + print "NOT CLASS" return getattr(sys.modules[module], function) - klass_object = getattr(sys.modules[module], klass) - return getattr(klass_object, function) - + print "DIR", dir(sys.modules[module]) + class_object = getattr(sys.modules[module], klass) + return getattr(class_object, function) diff --git a/tests/external/__init__.py b/tests/external/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/external/externalmodule.py b/tests/external/externalmodule.py new file mode 100644 index 0000000..10c745c --- /dev/null +++ b/tests/external/externalmodule.py @@ -0,0 +1,15 @@ +class Foo(object): + def method_a(self, a, b, c, d): + pass + + +class Blah(Foo): + def method_a(self, a, b, c, d): + pass + + def method_b(self, a, b, c, e): + pass + + +def function_a(a, b, c, d): + pass diff --git a/tests/localmodule.py b/tests/localmodule.py new file mode 100644 index 0000000..33f179a --- /dev/null +++ b/tests/localmodule.py @@ -0,0 +1,15 @@ +class Foo(object): + def method_a(self, a, b, c, d): + pass + + +class Blah(Foo): + def method_a(self, a, b, c, d): + pass + + def method_b(self, a, b, c, e): + pass + + +def function_a(a, b, c): + return (a, b, c) diff --git a/tests/test_simport.py b/tests/test_simport.py new file mode 100644 index 0000000..3799b05 --- /dev/null +++ b/tests/test_simport.py @@ -0,0 +1,70 @@ +import sys +import unittest + +from simport import simport + + +# Internal functions and classes. +def dummy_function(): + pass + + +class DummyClass(object): + def method_a(self): + pass + + +class TestSimport(unittest.TestCase): + def test_bad_targets(self): + self.assertRaises(simport.MissingModule, simport._get_module, + "missing.py") + self.assertRaises(simport.MissingModule, simport._get_module, + "missing.py|") + + self.assertRaises(simport.MissingModule, simport._get_module, + "simport_tests/localmodule.py|") + self.assertRaises(simport.MissingModule, simport._get_module, + "simport_tests/localmodule.py|Foo") + + self.assertFalse("AnyModuleName" in sys.modules) + self.assertRaises(simport.MissingMethodOrFunction, simport._get_module, + "tests|AnyModuleName:") + self.assertFalse("AnyModuleName" in sys.modules) + + def test_good_external_targets(self): + self.assertEquals(("localmodule", "Foo", "method_a"), + simport._get_module("tests|" + "localmodule:Foo.method_a")) + + self.assertRaises(ImportError, simport._get_module, + "tests|that_module:function_a") + + def test_bad_load(self): + self.assertRaises(AttributeError, simport.load, + "test_simport:missing") + + def test_good_load_internal(self): + self.assertEquals(dummy_function, + simport.load("test_simport:dummy_function")) + self.assertEquals(DummyClass.method_a, + simport.load("test_simport:DummyClass.method_a")) + + def test_good_load_local(self): + method = simport.load("tests|" + "localmodule:Foo.method_a") + import localmodule + self.assertEquals(method, localmodule.Foo.method_a) + self.assertEquals(localmodule.function_a, + simport.load("localmodule:function_a")) + + def test_good_load_external(self): + method = simport.load("tests/external|" + "external.externalmodule:Blah.method_b") + + self.assertTrue('external.externalmodule' in sys.modules) + old = sys.modules['external.externalmodule'] + import external.externalmodule + + self.assertEqual(external.externalmodule, + sys.modules['external.externalmodule']) + self.assertEqual(old, external.externalmodule)