Import module from file path
Peter Otten
__peter__ at web.de
Wed Dec 5 02:55:09 EST 2018
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.
More information about the Python-list
mailing list