Oscar Benjamin wrote: > Hi all, > > I'm looking to import a module given a string representing the path to > the .py file defining the module. For example given this setup > > mkdir -p a/b/c > touch a/__init__.py > touch a/b/__init__.py > touch a/b/c/__init__.py > touch a/b/c/stuff.py > > I have a module a.b.c.stuff which is defined in the file > '/home/oscar/work/project/a/b/c/stuff.py'. Given that a.b.c.stuff is > importable and I have the (relative or absolute) path of stuff.py as a > string I would like to import that module. > > I want this to work in 2.7 and 3.4+ and have come up with the > following which works for valid inputs: > > import os.path > > def import_submodule(filename, rootmodule): > # Convert from path to module name > rootdir = os.path.dirname(os.path.dirname(rootmodule.__path__[0])) > filepath = os.path.relpath(filename, rootdir) > basename, ext = os.path.splitext(filepath) > modname = basename.replace('/', '.').replace('\\', '.') > subattr = modname.split(rootmodule.__name__ + '.')[-1] > modname = rootmodule.__name__ + '.' + subattr > > # Now import the module > import importlib > mod = importlib.import_module(modname) > return mod > > import a > mod = import_submodule('a/b/c/stuff.py', a) > print(dir(mod)) > > The first part of the above function is the bit that bothers me. I > think there are ways that it could import and run the wrong code if > accidentally given the wrong input (malevolent input is unimportant > here). Also it seems as if there should be a simpler way to get from > the path to the module name...
I am not aware of a clean way. I have used def guess_modulename(filename): """Infer module name from filename. >>> guess_modulename("/foo/bar/baz.py") 'baz' >>> guess_modulename("/usr/lib/python3.4/logging/handlers.py") 'logging.handlers' """ if not filename.endswith(".py"): raise ValueError("expecting .py file, but got %r" % filename) filename = filename[:-3] folder, name = os.path.split(filename) names = [name] while os.path.isfile(os.path.join(folder, "__init__.py")): folder, name = os.path.split(folder) names.append(name) return ".".join(reversed(names)) which unfortunately does not work with namespace packages. -- https://mail.python.org/mailman/listinfo/python-list