How do I load a Python module given its full path?
Note that the file can be anywhere in the filesystem where the user has access rights.
How do I load a Python module given its full path?
Note that the file can be anywhere in the filesystem where the user has access rights.
Let's have MyClass
in module.name
module defined at /path/to/file.py
. Below is how we import MyClass
from this module
For Python 3.5+ use (docs):
import importlib.util
import sys
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
sys.modules["module.name"] = foo
spec.loader.exec_module(foo)
foo.MyClass()
For Python 3.3 and 3.4 use:
from importlib.machinery import SourceFileLoader
foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()
(Although this has been deprecated in Python 3.4.)
For Python 2 use:
import imp
foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()
There are equivalent convenience functions for compiled Python files and DLLs.
See also http://bugs.python.org/issue21436.
__import__
. –
Involved imp.load_source
only sets the .__name__
of the returned module. it doesn't effect loading. –
Obsolescent imp.load_source()
determines the key of the new entry created in the sys.modules
dictionary, so the first argument does indeed affect loading. –
Peso SourceFileLoader
is deprecated in the 3.4+ docs. –
Dubious runpy.run_path
for execution of Python code as a configuration format, rather than dynamically manipulating the import system. –
Aromatic importlib.import_module
is not mentioned here? –
Motherland /path/to/file.py
imports a sibling implicitly (e.g. import bar
to import /path/to/bar.py
), the solution yields ModuleNotFoundError: No module named 'bar'
. Any way to fix this? –
Archeology importlib.util.spec_from_file_location
won't import files that don't end in .py
=( –
Globeflower python 3.6.3
on Sierra 10.12.6
and using option 1 (for python 3.5+). The code works, but when I run the line foo.MyClass()
I get the error AttributeError: module 'myFileName' has no attribute 'MyClass'
, where myFileName
is the name of the python file I pass to the first arg of importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
. Yet when I comment out the line foo.MyClass()
the script executes the imported script without issue. Would someone please explain what foo.MyClass()
is doing in the suggested code? –
Grist foo.
(or however you call that variable). –
Ringside sys.path
, and then ask for the specific module that you want? –
Hexameter spec.loader.exec_module(foo)
also ensure that the script is completely run? I have a set-up where I import a list of a variables (and purposely not a class), that all need to be valid and active within the script from which I'm calling it. In contrast to the regular import
statement, however, my variables cannot be further recalled. –
Goggleeyed importlib
module still could not handle module file names with periods: bugs.python.org/issue38000 –
Rehabilitation ImportError: attempted relative import with no known parent package
–
Whiteness module.name
is the module from which I run? –
Arleta sys.modules[spec.name] = foo
–
Matlock module.name
?? I'm importing a file, or something from a file. It does not have a namespace. –
Jackquelinejackrabbit cd "folder"
and then I was fine. Hope this helps someone. –
Nelia pydoc
yet -- here are my two cents: pydoc::importfile() –
Nocti class MyClass
into the current namespace (like I did during a dynamic Py2 vs Py3 import), try this: MyClass = getattr(foo, "MyClass")
Discovered here: https://mcmap.net/q/20036/-import-class-from-module-dynamically –
Surrealism import importlib
NAME, PATH = 'coverage', '/usr/bin/coverage'
loader = importlib.machinery.SourceFileLoader(NAME, PATH)
spec = importlib.util.spec_from_file_location(NAME, loader=loader)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
Annoying as hell. –
Ancestral The advantage of adding a path to sys.path (over using imp) is that it simplifies things when importing more than one module from a single package. For example:
import sys
# the mock-0.3.1 dir contains testcase.py, testutils.py & mock.py
sys.path.append('/foo/bar/mock-0.3.1')
from testcase import TestCase
from testutils import RunTests
from mock import Mock, sentinel, patch
sys.path.append
to point to a single python file instead of a directory? –
Ureter importlib
) with this worked for me. –
Supersession importlib.import_module(mod_name)
can be used instead of the explicit import here if the module name isn't known at runtime I would add a sys.path.pop()
in the end, though, assuming the imported code doesn't try to import more modules as it is used. –
Tawny sys.path.append
, so with this answer if your working directory was /foo/bar/
, you could use sys.path.append('./mock-0.3.1')
–
Terminology To import your module, you need to add its directory to the environment variable, either temporarily or permanently.
import sys
sys.path.append("/path/to/my/modules/")
import my_module
Adding the following line to your .bashrc
(or alternative) file in Linux
and excecute source ~/.bashrc
(or alternative) in the terminal:
export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"
Credit/Source: saarrrr, another Stack Exchange question
If your top-level module is not a file but is packaged as a directory with __init__.py, then the accepted solution almost works, but not quite. In Python 3.5+ the following code is needed (note the added line that begins with 'sys.modules'):
MODULE_PATH = "/path/to/your/module/__init__.py"
MODULE_NAME = "mymodule"
import importlib
import sys
spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
Without this line, when exec_module is executed, it tries to bind relative imports in your top level __init__.py to the top level module name -- in this case "mymodule". But "mymodule" isn't loaded yet so you'll get the error "SystemError: Parent module 'mymodule' not loaded, cannot perform relative import". So you need to bind the name before you load it. The reason for this is the fundamental invariant of the relative import system: "The invariant holding is that if you have sys.modules['spam'] and sys.modules['spam.foo'] (as you would after the above import), the latter must appear as the foo attribute of the former" as discussed here.
mymodule
? –
Arleta /path/to/your/module/
is actually /path/to/your/PACKAGE/
? and by mymodule
you mean myfile.py
? –
Arleta mymodule
in relation to /path/to/your/module/__init__.py
? –
Dentistry __init__.py
, you can still import it as a package. Include spec.submodule_search_locations = [os.path.dirname(MODULE_PATH)]
after creating the spec. You can also treat a __init__.py
as a non-package (e.g. single module) by setting this value to None
–
Urban MODULE_PATH
. Took me quite a while to figure out –
Secret It sounds like you don't want to specifically import the configuration file (which has a whole lot of side effects and additional complications involved). You just want to run it, and be able to access the resulting namespace. The standard library provides an API specifically for that in the form of runpy.run_path:
from runpy import run_path
settings = run_path("/path/to/file.py")
That interface is available in Python 2.7 and Python 3.2+.
result[name]
, result.get('name', default_value)
, etc) –
Aromatic from runpy import run_path; from argparse import Namespace; mod = Namespace(**run_path('path/to/file.py'))
–
Lissa runpy.run_module
and said that python -m module_name
now delegates to it. 1. Did you write a similar PEP for the function runpy.run_path
? 2. Does python file_path.py
now delegate to runpy.run_path
? –
Raymer runpy.run_path
, but if a given path is a directory or zipfile, then it ends up delegating to runpy.run_module
for the __main__
execution. The duplicated logic for "Is it a script, directory, or zipfile?" isn't complicated enough to be worth delegating to Python code. –
Aromatic runpy.run_module
for a given module name (python -m name
) happen exactly here and for a given directory or zip file path (python path
) happen exactly here? –
Raymer pymain_run_module
, it seems that CPython delegates to the Python function runpy._run_module_as_main
instead of runpy.run_module
—though if I understood correctly the only difference is that the first function executes the code in the built-in __main__
environment (cf. here) while the second function executes it in a new environment? –
Raymer -i
option (which drops you into an interactive shell in the original __main__
module, so -m
running in a new module was inconvenient) –
Aromatic You can also do something like this and add the directory that the configuration file is sitting in to the Python load path, and then just do a normal import, assuming you know the name of the file in advance, in this case "config".
Messy, but it works.
configfile = '~/config.py'
import os
import sys
sys.path.append(os.path.dirname(os.path.expanduser(configfile)))
import config
I have come up with a slightly modified version of @SebastianRittau's wonderful answer (for Python > 3.4 I think), which will allow you to load a file with any extension as a module using spec_from_loader
instead of spec_from_file_location
:
from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader
spec = spec_from_loader("module.name", SourceFileLoader("module.name", "/path/to/file.py"))
mod = module_from_spec(spec)
spec.loader.exec_module(mod)
The advantage of encoding the path in an explicit SourceFileLoader
is that the machinery will not try to figure out the type of the file from the extension. This means that you can load something like a .txt
file using this method, but you could not do it with spec_from_file_location
without specifying the loader because .txt
is not in importlib.machinery.SOURCE_SUFFIXES
.
I've placed an implementation based on this, and @SamGrondahl's useful modification into my utility library, haggis. The function is called haggis.load.load_module
. It adds a couple of neat tricks, like the ability to inject variables into the module namespace as it is loaded.
To add to Sebastian Rittau's answer: At least for CPython, there's pydoc, and, while not officially declared, importing files is what it does:
from pydoc import importfile
module = importfile('/path/to/module.py')
PS. For the sake of completeness, there's a reference to the current implementation at the moment of writing: pydoc.py, and I'm pleased to say that in the vein of xkcd 1987 it uses neither of the implementations mentioned in issue 21436 -- at least, not verbatim.
from module import *
one would need to filter "internal" module content -- like names starting with an underscrore. –
Nocti Here is some code that works in all Python versions, from 2.7-3.5 and probably even others.
config_file = "/tmp/config.py"
with open(config_file) as f:
code = compile(f.read(), config_file, 'exec')
exec(code, globals(), locals())
I tested it. It may be ugly, but so far it is the only one that works in all versions.
load_source
did not because it imports the script and provides the script access to the modules and globals at the time of importing. –
Lowboy globals
and locals
) –
Scarce imp.load_dynamic(module_name, path_to_file)
for DLLs –
Orchidectomy Do you mean load or import?
You can manipulate the sys.path
list specify the path to your module, and then import your module. For example, given a module at:
/foo/bar.py
You could do:
import sys
sys.path[0:0] = ['/foo'] # Puts the /foo directory at the start of your path
import bar
sys.path[0:0] = ['/foo']
–
Schapira Explicit is better than implicit.
So why not sys.path.insert(0, ...)
instead of sys.path[0:0]
? –
Inconstant sys.path.append(...)
then. It's clearer. –
Sibling You can do this using __import__
and chdir
:
def import_file(full_path_to_module):
try:
import os
module_dir, module_file = os.path.split(full_path_to_module)
module_name, module_ext = os.path.splitext(module_file)
save_cwd = os.getcwd()
os.chdir(module_dir)
module_obj = __import__(module_name)
module_obj.__file__ = full_path_to_module
globals()[module_name] = module_obj
os.chdir(save_cwd)
except Exception as e:
raise ImportError(e)
return module_obj
import_file('/home/somebody/somemodule.py')
except:
clause is rarely a good idea. –
Polyzoan save_cwd = os.getcwd()
try: …
finally: os.chdir(save_cwd)
–
Hesitation this is already addressed by the standard library
yeah, but python has nasty habit of not being backward-compatible... as the checked answer says there're 2 different ways before and after 3.3. In that case I'd rather like to write my own universal function than check version on the fly. And yes, maybe this code isn't too well error-protected, but it shows an idea (which is os.chdir(), I haven't though about it), basing on which I can write a better code. Hence +1. –
Verleneverlie If we have scripts in the same project but in different directory means, we can solve this problem by the following method.
In this situation utils.py
is in src/main/util/
import sys
sys.path.append('./')
import src.main.util.utils
#or
from src.main.util.utils import json_converter # json_converter is example method
I believe you can use imp.find_module()
and imp.load_module()
to load the specified module. You'll need to split the module name off of the path, i.e. if you wanted to load /home/mypath/mymodule.py
you'd need to do:
imp.find_module('mymodule', '/home/mypath/')
...but that should get the job done.
You can use the pkgutil
module (specifically the walk_packages
method) to get a list of the packages in the current directory. From there it's trivial to use the importlib
machinery to import the modules you want:
import pkgutil
import importlib
packages = pkgutil.walk_packages(path='.')
for importer, name, is_package in packages:
mod = importlib.import_module(name)
# do whatever you want with module now, it's been imported!
Create Python module test.py:
import sys
sys.path.append("<project-path>/lib/")
from tes1 import Client1
from tes2 import Client2
import tes3
Create Python module test_check.py:
from test import Client1
from test import Client2
from test import test3
We can import the imported module from module.
There's a package that's dedicated to this specifically:
from thesmuggler import smuggle
# À la `import weapons`
weapons = smuggle('weapons.py')
# À la `from contraband import drugs, alcohol`
drugs, alcohol = smuggle('drugs', 'alcohol', source='contraband.py')
# À la `from contraband import drugs as dope, alcohol as booze`
dope, booze = smuggle('drugs', 'alcohol', source='contraband.py')
It's tested across Python versions (Jython and PyPy too), but it might be overkill depending on the size of your project.
This area of Python 3.4 seems to be extremely tortuous to understand! However with a bit of hacking using the code from Chris Calloway as a start I managed to get something working. Here's the basic function.
def import_module_from_file(full_path_to_module):
"""
Import a module given the full path/filename of the .py file
Python 3.4
"""
module = None
try:
# Get module name and path from full path
module_dir, module_file = os.path.split(full_path_to_module)
module_name, module_ext = os.path.splitext(module_file)
# Get module "spec" from filename
spec = importlib.util.spec_from_file_location(module_name,full_path_to_module)
module = spec.loader.load_module()
except Exception as ec:
# Simple error printing
# Insert "sophisticated" stuff here
print(ec)
finally:
return module
This appears to use non-deprecated modules from Python 3.4. I don't pretend to understand why, but it seems to work from within a program. I found Chris' solution worked on the command line but not from inside a program.
I made a package that uses imp
for you. I call it import_file
and this is how it's used:
>>>from import_file import import_file
>>>mylib = import_file('c:\\mylib.py')
>>>another = import_file('relative_subdir/another.py')
You can get it at:
http://pypi.python.org/pypi/import_file
or at
This should work
path = os.path.join('./path/to/folder/with/py/files', '*.py')
for infile in glob.glob(path):
basename = os.path.basename(infile)
basename_without_extension = basename[:-3]
# http://docs.python.org/library/imp.html?highlight=imp#module-imp
imp.load_source(basename_without_extension, infile)
name, ext = os.path.splitext(os.path.basename(infile))
. Your method works because the previous restriction to .py extension. Also, you should probably import the module to some variable/dictionary entry. –
Infuscate I'm not saying that it is better, but for the sake of completeness, I wanted to suggest the exec
function, available in both Python 2 and Python 3.
exec
allows you to execute arbitrary code in either the global scope, or in an internal scope, provided as a dictionary.
For example, if you have a module stored in "/path/to/module
" with the function foo()
, you could run it by doing the following:
module = dict()
with open("/path/to/module") as f:
exec(f.read(), module)
module['foo']()
This makes it a bit more explicit that you're loading code dynamically, and grants you some additional power, such as the ability to provide custom builtins.
And if having access through attributes, instead of keys is important to you, you can design a custom dict class for the globals, that provides such access, e.g.:
class MyModuleClass(dict):
def __getattr__(self, name):
return self.__getitem__(name)
To import a module from a given filename, you can temporarily extend the path, and restore the system path in the finally block reference:
filename = "directory/module.py"
directory, module_name = os.path.split(filename)
module_name = os.path.splitext(module_name)[0]
path = list(sys.path)
sys.path.insert(0, directory)
try:
module = __import__(module_name)
finally:
sys.path[:] = path # restore
A simple solution using importlib
instead of the imp
package (tested for Python 2.7, although it should work for Python 3 too):
import importlib
dirname, basename = os.path.split(pyfilepath) # pyfilepath: '/my/path/mymodule.py'
sys.path.append(dirname) # only directories should be added to PYTHONPATH
module_name = os.path.splitext(basename)[0] # '/my/path/mymodule.py' --> 'mymodule'
module = importlib.import_module(module_name) # name space of defined module (otherwise we would literally look for "module_name")
Now you can directly use the namespace of the imported module, like this:
a = module.myvar
b = module.myfunc(a)
The advantage of this solution is that we don't even need to know the actual name of the module we would like to import, in order to use it in our code. This is useful, e.g. in case the path of the module is a configurable argument.
sys.path
, which does not fit every use case. –
Salo sys.path.pop()
–
Hillinck Import package modules at runtime (Python recipe)
http://code.activestate.com/recipes/223972/
###################
## #
## classloader.py #
## #
###################
import sys, types
def _get_mod(modulePath):
try:
aMod = sys.modules[modulePath]
if not isinstance(aMod, types.ModuleType):
raise KeyError
except KeyError:
# The last [''] is very important!
aMod = __import__(modulePath, globals(), locals(), [''])
sys.modules[modulePath] = aMod
return aMod
def _get_func(fullFuncName):
"""Retrieve a function object from a full dotted-package name."""
# Parse out the path, module, and function
lastDot = fullFuncName.rfind(u".")
funcName = fullFuncName[lastDot + 1:]
modPath = fullFuncName[:lastDot]
aMod = _get_mod(modPath)
aFunc = getattr(aMod, funcName)
# Assert that the function is a *callable* attribute.
assert callable(aFunc), u"%s is not callable." % fullFuncName
# Return a reference to the function itself,
# not the results of the function.
return aFunc
def _get_class(fullClassName, parentClass=None):
"""Load a module and retrieve a class (NOT an instance).
If the parentClass is supplied, className must be of parentClass
or a subclass of parentClass (or None is returned).
"""
aClass = _get_func(fullClassName)
# Assert that the class is a subclass of parentClass.
if parentClass is not None:
if not issubclass(aClass, parentClass):
raise TypeError(u"%s is not a subclass of %s" %
(fullClassName, parentClass))
# Return a reference to the class itself, not an instantiated object.
return aClass
######################
## Usage ##
######################
class StorageManager: pass
class StorageManagerMySQL(StorageManager): pass
def storage_object(aFullClassName, allOptions={}):
aStoreClass = _get_class(aFullClassName, StorageManager)
return aStoreClass(allOptions)
I have written my own global and portable import function, based on importlib
module, for:
sys.path
or on a what ever search path storage.The examples directory structure:
<root>
|
+- test.py
|
+- testlib.py
|
+- /std1
| |
| +- testlib.std1.py
|
+- /std2
| |
| +- testlib.std2.py
|
+- /std3
|
+- testlib.std3.py
Inclusion dependency and order:
test.py
-> testlib.py
-> testlib.std1.py
-> testlib.std2.py
-> testlib.std3.py
Implementation:
Latest changes store: https://github.com/andry81/tacklelib/tree/HEAD/python/tacklelib/tacklelib.py
test.py:
import os, sys, inspect, copy
SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("test::SOURCE_FILE: ", SOURCE_FILE)
# portable import to the global space
sys.path.append(TACKLELIB_ROOT) # TACKLELIB_ROOT - path to the library directory
import tacklelib as tkl
tkl.tkl_init(tkl)
# cleanup
del tkl # must be instead of `tkl = None`, otherwise the variable would be still persist
sys.path.pop()
tkl_import_module(SOURCE_DIR, 'testlib.py')
print(globals().keys())
testlib.base_test()
testlib.testlib_std1.std1_test()
testlib.testlib_std1.testlib_std2.std2_test()
#testlib.testlib.std3.std3_test() # does not reachable directly ...
getattr(globals()['testlib'], 'testlib.std3').std3_test() # ... but reachable through the `globals` + `getattr`
tkl_import_module(SOURCE_DIR, 'testlib.py', '.')
print(globals().keys())
base_test()
testlib_std1.std1_test()
testlib_std1.testlib_std2.std2_test()
#testlib.std3.std3_test() # does not reachable directly ...
globals()['testlib.std3'].std3_test() # ... but reachable through the `globals` + `getattr`
testlib.py:
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("1 testlib::SOURCE_FILE: ", SOURCE_FILE)
tkl_import_module(SOURCE_DIR + '/std1', 'testlib.std1.py', 'testlib_std1')
# SOURCE_DIR is restored here
print("2 testlib::SOURCE_FILE: ", SOURCE_FILE)
tkl_import_module(SOURCE_DIR + '/std3', 'testlib.std3.py')
print("3 testlib::SOURCE_FILE: ", SOURCE_FILE)
def base_test():
print('base_test')
testlib.std1.py:
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("testlib.std1::SOURCE_FILE: ", SOURCE_FILE)
tkl_import_module(SOURCE_DIR + '/../std2', 'testlib.std2.py', 'testlib_std2')
def std1_test():
print('std1_test')
testlib.std2.py:
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("testlib.std2::SOURCE_FILE: ", SOURCE_FILE)
def std2_test():
print('std2_test')
testlib.std3.py:
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("testlib.std3::SOURCE_FILE: ", SOURCE_FILE)
def std3_test():
print('std3_test')
Output (3.7.4
):
test::SOURCE_FILE: <root>/test01/test.py
import : <root>/test01/testlib.py as testlib -> []
1 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE: <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE: <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE: <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib'])
base_test
std1_test
std2_test
std3_test
import : <root>/test01/testlib.py as . -> []
1 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE: <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE: <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE: <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib', 'testlib_std1', 'testlib.std3', 'base_test'])
base_test
std1_test
std2_test
std3_test
Tested in Python 3.7.4
, 3.2.5
, 2.7.16
Pros:
testlib.std.py
as testlib
, testlib.blabla.py
as testlib_blabla
and so on).sys.path
or on a what ever search path storage.SOURCE_FILE
and SOURCE_DIR
between calls to tkl_import_module
.3.4.x
and higher] Can mix the module namespaces in nested tkl_import_module
calls (ex: named->local->named
or local->named->local
and so on).3.4.x
and higher] Can auto export global variables/functions/classes from where being declared to all children modules imported through the tkl_import_module
(through the tkl_declare_global
function).Cons:
3.3.x
and lower] Require to declare tkl_import_module
in all modules which calls to tkl_import_module
(code duplication)Update 1,2 (for 3.4.x
and higher only):
In Python 3.4 and higher you can bypass the requirement to declare tkl_import_module
in each module by declare tkl_import_module
in a top level module and the function would inject itself to all children modules in a single call (it's a kind of self deploy import).
Update 3:
Added function tkl_source_module
as analog to bash source
with support execution guard upon import (implemented through the module merge instead of import).
Update 4:
Added function tkl_declare_global
to auto export a module global variable to all children modules where a module global variable is not visible because is not a part of a child module.
Update 5:
All functions has moved into the tacklelib library, see the link above.
In Linux, adding a symbolic link in the directory your Python script is located works.
I.e.:
ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py
The Python interpreter will create /absolute/path/to/script/module.pyc
and will update it if you change the contents of /absolute/path/to/module/module.py
.
Then include the following in file mypythonscript.py:
from module import *
git
and checking your git status
to verify that your changes to the script are actually making it back to the source document and not getting lost in the ether. –
Snaffle This will allow imports of compiled (pyd) Python modules in 3.4:
import sys
import importlib.machinery
def load_module(name, filename):
# If the Loader finds the module name in this list it will use
# module_name.__file__ instead so we need to delete it here
if name in sys.modules:
del sys.modules[name]
loader = importlib.machinery.ExtensionFileLoader(name, filename)
module = loader.load_module()
locals()[name] = module
globals()[name] = module
load_module('something', r'C:\Path\To\something.pyd')
something.do_something()
A quite simple way: suppose you want import file with relative path ../../MyLibs/pyfunc.py
libPath = '../../MyLibs'
import sys
if not libPath in sys.path: sys.path.append(libPath)
import pyfunc as pf
But if you make it without a guard you can finally get a very long path.
These are my two utility functions using only pathlib. It infers the module name from the path.
By default, it recursively loads all Python files from folders and replaces init.py by the parent folder name. But you can also give a Path and/or a glob to select some specific files.
from pathlib import Path
from importlib.util import spec_from_file_location, module_from_spec
from typing import Optional
def get_module_from_path(path: Path, relative_to: Optional[Path] = None):
if not relative_to:
relative_to = Path.cwd()
abs_path = path.absolute()
relative_path = abs_path.relative_to(relative_to.absolute())
if relative_path.name == "__init__.py":
relative_path = relative_path.parent
module_name = ".".join(relative_path.with_suffix("").parts)
mod = module_from_spec(spec_from_file_location(module_name, path))
return mod
def get_modules_from_folder(folder: Optional[Path] = None, glob_str: str = "*/**/*.py"):
if not folder:
folder = Path(".")
mod_list = []
for file_path in sorted(folder.glob(glob_str)):
mod_list.append(get_module_from_path(file_path))
return mod_list
Here's my 2024 solution to this question - does not require path to a .py
file, path to the parent of the module folder is sufficient.
import importlib
import importlib.machinery
import importlib.util
pkg = "mypkg"
spec = importlib.machinery.PathFinder().find_spec(pkg, ["/path/to/mypkg-parent"])
mod = importlib.util.module_from_spec(spec)
sys.modules[pkg] = mod # needed for exec_module to work
spec.loader.exec_module(mod)
sys.modules[pkg] = importlib.import_module(pkg)
The last statement is necessary to ensure that the full module is present in sys.modules
(including submodules).
This answer is a supplement to Sebastian Rittau's answer responding to the comment: "but what if you don't have the module name?" This is a quick and dirty way of getting the likely Python module name given a filename -- it just goes up the tree until it finds a directory without an __init__.py
file and then turns it back into a filename. For Python 3.4+ (uses pathlib), which makes sense since Python 2 people can use "imp" or other ways of doing relative imports:
import pathlib
def likely_python_module(filename):
'''
Given a filename or Path, return the "likely" python module name. That is, iterate
the parent directories until it doesn't contain an __init__.py file.
:rtype: str
'''
p = pathlib.Path(filename).resolve()
paths = []
if p.name != '__init__.py':
paths.append(p.stem)
while True:
p = p.parent
if not p:
break
if not p.is_dir():
break
inits = [f for f in p.iterdir() if f.name == '__init__.py']
if not inits:
break
paths.append(p.stem)
return '.'.join(reversed(paths))
There are certainly possibilities for improvement, and the optional __init__.py
files might necessitate other changes, but if you have __init__.py
in general, this does the trick.
Assuming that your MyClass
is in MyClass.py
, you can use this one line to dynamically import it/
cls = `MyClass`
MyClass = getattr(__import__(cls, globals(), locals(), [cls], 0), cls)
$ pip install importmonkey
[github] [pip] [docs]
# In test.py
from importmonkey import add_path
add_path("../relative/path") # relative to current __file__
add_path("/my/absolute/path/to/somewhere") # absolute path
import project
# You can add as many paths as needed, absolute or relative, in any file.
# Relative paths start from the current __file__ directory.
# Normal unix path conventions work so you can use '..' and '.' and so on.
# The paths you try to add are checked for validity etc. help(add_path) for details.
Disclosure of affiliation: I made importmonkey.
Here's a way of loading files sorta like C, etc.
from importlib.machinery import SourceFileLoader
import os
def LOAD (MODULE_PATH):
if (MODULE_PATH [ 0 ] == "/"):
FULL_PATH = MODULE_PATH;
else:
DIR_PATH = os.path.dirname (os.path.realpath (__file__))
FULL_PATH = os.path.normpath (DIR_PATH + "/" + MODULE_PATH)
return SourceFileLoader (FULL_PATH, FULL_PATH).load_module ()
Implementations Where:
Y = LOAD ("../Z.py")
A = LOAD ("./A.py")
D = LOAD ("./C/D.py")
A_ = LOAD ("/IMPORTS/A.py")
Y.DEF ();
A.DEF ();
D.DEF ();
A_.DEF ();
Where each of the files looks like this:
def DEF ():
print ("A");
You can use importfile from pydoc
from pydoc import importfile
module = importfile('/full/path/to/module/module.py')
name = module.myclass() # myclass is a class inside your python file
import module
i mean it is can compile variables, functions and classes ? –
Terresaterrestrial The best way, I think, is from the official documentation (29.1. imp — Access the import internals):
import imp
import sys
def __import__(name, globals=None, locals=None, fromlist=None):
# Fast path: see if the module has already been imported.
try:
return sys.modules[name]
except KeyError:
pass
# If any of the following calls raises an exception,
# there's a problem we can't handle -- let the caller handle it.
fp, pathname, description = imp.find_module(name)
try:
return imp.load_module(name, fp, pathname, description)
finally:
# Since we may exit via an exception, close fp explicitly.
if fp:
fp.close()
I find this is a simple answer:
module = dict()
code = """
import json
def testhi() :
return json.dumps({"key" : "value"}, indent = 4 )
"""
exec(code, module)
x = module['testhi']()
print(x)
Something special is to import a module with absolute path with Exec(): (exec takes a code string or code object. While eval takes an expression.)
PYMODULE = 'C:\maXbox\mX47464\maxbox4\examples\histogram15.py';
Execstring(LoadStringJ(PYMODULE));
And then get values or object with eval():
println('get module data: '+evalStr('pyplot.hist(x)'));
Load a module with exec is like an import with wildcard namespace:
Execstring('sys.path.append(r'+'"'+PYMODULEPATH+'")');
Execstring('from histogram import *');
© 2022 - 2024 — McMap. All rights reserved.
import
,virtualenv
,pip
,setuptools
whatnot should all be thrown out and replaced with working code. I just tried to grokvirtualenv
or was itpipenv
and had to work thru the equivalent of a Jumbo Jet manual. How that contrivance is paraded as The Solution to dealing with deps totally escapes me. – Revels#ifndef
idiom? It's absolutely mind-boggling to me that there are so many people out there who will complain about Python while praising absolutely bizarre alternatives. – Abedimport
, and it was designed by the Python dev team and it works very well. By default, symbols with a leading underscore are not exposed; you can modify the behaviour using__all__
. You can alsodel
unneeded symbols at the end of the top-level code. – Abedsys.path
. If its not in there, there are multiple ways to add it either dynamically or permanently depending on how you are launching your python code. The best way is to not do this, make it a python package and install it to your virtual environment. – Elytron