How to load all modules in a folder?
List all python (.py
) files in the current folder and put them as __all__
variable in __init__.py
from os.path import dirname, basename, isfile, join
import glob
modules = glob.glob(join(dirname(__file__), "*.py"))
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]
Python: import every module from a folder?
If transforming the folder itself in a module, through the use of a __init__.py
file and using from <foldername> import *
suits you, you can iterate over the folder contents
with "os.listdir" or "glob.glob", and import each file ending in ".py" with the __import__
built-in function:
import os
for name in os.listdir("plugins"):
if name.endswith(".py"):
#strip the extension
module = name[:-3]
# set the module name in the current global name space:
globals()[module] = __import__(os.path.join("plugins", name)
The benefit of this approach is: it allows you to dynamically pass the module names to __import__
- while the ìmport statement needs the module names to be hardcoded, and it allows you to check other things about the files - maybe size, or if they import certain required modules, before importing them.
How do I load all modules under a subdirectory in Python?
This confusion happened, in part, because your module names are the same as the names of the classes you want to load from them. (At least, that's what makes it more confusing.) Your code does correctly load the modules that your classes are in. However, it doesn't load the classes out of those modules, and this is what you actually wanted to do.
Because your class DominatingSets
is in the module lib.DominatingSets
, its full path from root is lib.DominatingSets.DominatingSets
.
from lib import *
in your case will do the same thing as
from lib import DominatingSets
from lib import AnalyzeGraph
# ...
However,
from lib import DominatingSets
is equivalent to
import lib.DominatingSets
DominatingSets = lib.DominatingSets
but lib.DominatingSets
is a module (lib/DominatingSets.py
), not the class you want.
from lib.DominatingSets import DominatingSets
is equivalent to
import lib.DominatingSets
DominatingSets = lib.DominatingSets.DominatingSets
which is why it works: this is the class you want imported into the name DominatingSets
.
If you want to have from lib import *
import all the classes in the submodules, you need to import these classes into the lib
module. For example, in lib/__init__.py
:
from DominatingSets import *
from AnalyzeGraph import *
# ...
While you're making changes, I'd suggest (as others have) using normal Python naming conventions, and have your module names in lowercase: change DominatingSets.py
to dominatingsets.py
. Then this code would become
from dominatingsets import *
from analyzegraph import *
# ...
how to import all files from different folder in Python
If you have the following structure:
$ tree subdirectory/
subdirectory/
├── file1.py
├── file2.py
└── file3.py
and you want a program to automatically pick up every module which is located in this subdirectory
and process it in a certain way you could achieve it as follows:
import glob
# Get file paths of all modules.
modules = glob.glob('subdirectory/*.py')
# Dynamically load those modules here.
For how to dynamically load a module see this question.
In your subdirectory/__init__.py
you can import all local modules via:
from . import file1
from . import file2
# And so on.
You can import the content of local modules via
from .file1 import *
# And so on.
Then you can import those modules (or the contents) via
from subdirectory import *
With the attribute __all__
in __init__.py
you can control what exactly will be imported during a from ... import *
statement. So if you don't want file2.py
to be imported for example you could do:
__all__ = ['file1', 'file3', ...]
You can access those modules via
import subdirectory
from subdirectory import *
for name in subdirectory.__all__:
module = locals()[name]
Import and run all modules in folder
You can use importlib
. Assume the following simple directory structure:
- a.py
- b.py
- c.py
a.py
and b.py
contain the following simple function:
def main(name):
print name
In c.py
we can iterate over our directory and use importlib.import_module
to import each file. We must ensure to make the imported modules globally accessible, otherwise they will only be local to the for loop.
c.py
:
import importlib
files = ['a', 'b']
for f in files:
globals()[f] = importlib.import_module(f)
a.main('adam')
b.main('ben')
Running c.py
produces the following output:
adam
ben
How do I dynamically import all *.py files from a given directory AND all sub-directories?
Your problem is broken up into two steps (from my point of view):
Walk through your directories and sub-directories and find the names of all the .py files you want to import
Import them!
To solve (1), we can use the os.walk
method to find all the .py files. This function would look like this:
import os
def get_py_files(src):
cwd = os.getcwd() # Current Working directory
py_files = []
for root, dirs, files in os.walk(src):
for file in files:
if file.endswith(".py"):
py_files.append(os.path.join(cwd, root, file))
return py_files
Now that you have a list of your .py files, we need a function that can dynamically import them.
import importlib
def dynamic_import(module_name, py_path):
module_spec = importlib.util.spec_from_file_location(module_name, py_path)
module = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
return module
And now we just need to put it all together, writing a function that calls your get_py_files
function and then loops over the results, loading the modules with dynamic_import
.
I am assuming you want the module names that you use in your python script to be the same as the file name, however you can change that by modifying the module_name
variable in the function below.
def dynamic_import_from_src(src, star_import = False):
my_py_files = get_py_files(src)
for py_file in my_py_files:
module_name = os.path.split(py_file)[-1].strip(".py")
imported_module = dynamic_import(module_name, py_file)
if star_import:
for obj in dir(imported_module):
globals()[obj] = imported_module.__dict__[obj]
else:
globals()[module_name] = imported_module
return
Notice we have to call globals()
to add the module to the global namespace. Without doing this, the module will be imported but you will have no way of accessing anything inside it. You can pass star_import = True
to dynamic_import_from_src
if you want it to be a star import instead. (like from first.foo import *
. Note that this may overwrite variables in your namespace but that's one of the cons of using the *
import anyways.
Throwing it all in one block so it's easier to see it all at once:
import os
import importlib
def get_py_files(src):
cwd = os.getcwd() # Current Working directory
py_files = []
for root, dirs, files in os.walk(src):
for file in files:
if file.endswith(".py"):
py_files.append(os.path.join(cwd, root, file))
return py_files
def dynamic_import(module_name, py_path):
module_spec = importlib.util.spec_from_file_location(module_name, py_path)
module = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
return module
def dynamic_import_from_src(src, star_import = False):
my_py_files = get_py_files(src)
for py_file in my_py_files:
module_name = os.path.split(py_file)[-1].strip(".py")
imported_module = dynamic_import(module_name, py_file)
if star_import:
for obj in dir(imported_module):
globals()[obj] = imported_module.__dict__[obj]
else:
globals()[module_name] = imported_module
return
if __name__ == "__main__":
dynamic_import_from_src("first", star_import = False)
At this point, you can access any of the modules you imported the exact same way as if you did import first.whatever
. For example, if first/numbers/one.py
contained x=1
, then you would be able to access that by saying one.x
.
Importing modules from parent folder
It seems that the problem is not related to the module being in a parent directory or anything like that.
You need to add the directory that contains ptdraft
to PYTHONPATH
You said that import nib
worked with you, that probably means that you added ptdraft
itself (not its parent) to PYTHONPATH.
Importing dynamically all modules from a folder
Python does not automatically import submodules contained in a package.
Hence import tracks
only loads tracks/__init__.py
.
However you can put code inside the __init__.py
file that imports all the modules it finds in that directory.
For example putting something like this in the __init__.py
:
import os
import importlib
__globals = globals()
for file in os.listdir(os.path.dirname(__file__)):
mod_name = file[:-3] # strip .py at the end
__globals[mod_name] = importlib.import_module('.' + mod_name, package=__name__)
Should make your submodules available as tracks.trackX
when importing only tracks
.
Or you could use exec
:
import os
import importlib
for file in os.listdir(os.path.dirname(__file__)):
mod_name = file[:-3] # strip .py at the end
exec('import .' + mod_name)
A cleaner approach would be to use import hooks or implement your own custom module importer. There are multiple ways to do this using importlib
see also sys.path_hooks
Related Topics
How to Use CSS Selectors to Retrieve Specific Links Lying in Some Class Using Beautifulsoup
How to Send a Signal from a Python Program
Converting Python Objects for Rpy2
How to Install Lxml for Python Without Administative Rights on Linux
Why Not Just Use 'Shell=True' in Subprocess.Popen in Python
Pyodbc:Can't Open the Driver Even If It Exists
Launch Default Image Viewer from Pygtk Program
Changes in Import Statement Python3
How to Make My Python Module Available System Wide on Linux
Why Xgrabkey Generates Extra Focus-Out and Focus-In Events
Python Script Prints Output of Os.System Before Print
How to Pass a Keystroke (Alt+Tab) Using Popen.Communicate (On Linux)
Package Libffi Was Not Found in the Pkg-Config Search Path Redhat6.5
Python Multiprocessing - Debugging Oserror: [Errno 12] Cannot Allocate Memory