Python dynamic import [duplicate] - python

This question already has answers here:
How can I import a module dynamically given the full path?
(35 answers)
Closed 6 years ago.
I have a list of tuples like [(module_name, module_abs_path)(mod2, path2), ...]
The modules are located in the 'modules' subdir where my script lives. I am trying to write a script which reads a conf file and makes some variables from the conf file available to the modules from the modules dir. My intention is to load and run all the modules from this script, so they get access to these variables.
Things I have tried so far but failed:
Tried using __import__() but it says running by file name is not allowed
Tried importlib.import_module() but gives the same error.
How should I go about doing this?

Have you tried to fix up the path before importing?
from __future__ import print_function
import importlib
import sys
def import_modules(modules):
modules_dict = dict()
for module_name, module_path in modules:
sys.path.append(module_path) # Fix the path
modules_dict[module_name] = importlib.import_module(module_name)
sys.path.pop() # Undo the path.append
return modules_dict
if __name__ == '__main__':
modules_info = [
('module1', '/abs/path/to/module1'),
]
modules_dict = import_modules(modules_info)
# At this point, we can access the module as
# modules_dict['module1']
# or...
globals().update(modules_dict)
# ... simply as module1

Related

Unable to import a function from outside the current working directory

I am currently having difficulties import some functions which are located in a python file which is in the parent directory of the working directory of the main flask application script. Here's how the structure looks like
project_folder
- public
--app.py
-scripts.py
here's a replica code for app.py:
def some_function():
from scripts import func_one, func_two
func_one()
func_two()
print('done')
if __name__ == "__main__":
some_function()
scripts.py contain the function as such:
def func_one():
print('function one successfully imported')
def func_two():
print('function two successfully imported')
What is the pythonic way of importing those functions in my app.py?
Precede it with a dot so that it searches the current directory (project_folder) instead of your python path:
from .scripts import func_one, func_two
The details of relative imports are described in PEP 328
Edit: I assumed you were working with a package. Consider adding an __init__.py file.
Anyways, you can import anything in python by altering the system path:
import sys
sys.path.append("/path/to/directory")
from x import y
1.
import importlib.util
def loadbasic():
spec = importlib.util.spec_from_file_location("basic", os.path.join(os.path.split(__file__)[0], 'basic.py'))
basic = importlib.util.module_from_spec(spec)
spec.loader.exec_module(basic)
return basic #returns a module
Or create an empty file __init__.py in the directory.
And
do not pollute your path with appends.

Python ImportLib 'No Module Named'

I'm trying to use a variable as a module to import from in Python.
Using ImportLib I have been successfully able to find the test...
sys.path.insert(0, sys.path[0] + '\\tests')
tool_name = selected_tool.split(".")[0]
selected_module = importlib.import_module("script1")
print(selected_module)
... and by printing the select_module I can see that it succesfully finds the script:
<module 'script1' from 'C:\\Users\\.....">
However, when I try to use this variable in the code to import a module from it:
from selected_module import run
run(1337)
The program quits with the following error:
ImportError: No module named 'selected_module'
I have tried to add a init.py file to the main directory and the /test directory where the scripts are, but to no avail. I'm sure it's just something stupidly small I'm missing - does anyone know?
Import statements are not sensitive to variables! Their content are treated as literals
An example:
urllib = "foo"
from urllib import parse # loads "urllib.parse", not "foo.parse"
print(parse)
Note that from my_module import my_func will simply bind my_module.my_func to the local name my_func. If you have already imported the module via importlib.import_module, you can just do this yourself:
# ... your code here
run = selected_module.run # bind module function to local name

From *folder_name* import *variable* Python 3.4.2

File setup:
...\Project_Folder
...\Project_Folder\Project.py
...\Project_folder\Script\TestScript.py
I'm attempting to have Project.py import modules from the folder Script based on user input.
Python Version: 3.4.2
Ideally, the script would look something like
q = str(input("Input: "))
from Script import q
However, python does not recognize q as a variable when using import.
I've tried using importlib, however I cannot figure out how to import from the Script folder mentioned above.
import importlib
q = str(input("Input: "))
module = importlib.import_module(q, package=None)
I'm not certain where I would implement the file path.
Repeat of my answer originally posted at How to import a module given the full path?
as this is a Python 3.4 specific question:
This area of Python 3.4 seems to be extremely tortuous to understand, mainly because the documentation doesn't give good examples! This was my attempt using non-deprecated modules. It will import a module given the path to the .py file. I'm using it to load "plugins" at runtime.
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
# load module dynamically
path = "<enter your path here>"
module = import_module_from_file(path)
# Now use the module
# e.g. module.myFunction()
I did this by defining the entire import line as a string, formatting the string with q and then using the exec command:
imp = 'from Script import %s' %q
exec imp

How to import a function which is in a different directory

I am trying to calling a function from a module which is located in different directory than the current.
This is code I am using
c:\commands contains a file nlog.py which contains function parselog . i would like to importing this function
into a python file in other directory c:\applications
def parselog(inFileDir = )
### This is in directory c:\commands which need to imported ####
c:\applications\pscan.py is the script which is calling / importing from the above file / directory
if __name__ == '__main__':
#sys.path.append("C:/commands")
sys.path.insert(0,'C:/commands')
from commands import nlog
def pscan (infileDir = )
parselog(inFileDir=r'os.getcwd()') # I am calling the function here
We are getting error
NameError: global name 'parselog' is not defined
I am not sure if I am importing in a wrong way. The C:\commands folder contains _init_.py file. Please let me know what I am missing.
Make and empty __init__.py file in the folder of the module you want to import.
Below code should work.
import sys
sys.path.append(r'c:\commands')
import nlog
parselog(inFileDir=r'os.getcwd()')

Importing classes from different files in a subdirectory

Here's the structure I'm working with:
directory/
script.py
subdir/
__init__.py
myclass01.py
myclass02.py
What I want to do is import in script.py the classes defined in myclass01.py and myclass02.py. If I do:
from subdir.myclass01 import *
It works fine for the class defined in myclass01.py. But with this solution if there are many classes defined in different files in subdir and I want to import all of them, I'd have to type one line for each file. There must be a shortcut for this. I tried:
from subdir.* import *
But it didn't work out.
EDIT: here are the contents of the files:
This is __init__.py (using __all__ as Apalala suggested):
__all__ = ['MyClass01','MyClass02']
This is myclass01.py:
class MyClass01:
def printsomething():
print 'hey'
This is myclass02.py:
class MyClass02:
def printsomething():
print 'sup'
This is script.py:
from subdir import *
MyClass01().printsomething()
MyClass02().printsomething()
This is the traceback that I get when I try to run script.py:
File "script.py", line 1, in <module>
from subdir import *
AttributeError: 'module' object has no attribute 'MyClass01'
Although the names used there are different from what's shown in your question's directory structure, you could use my answer to the question titled Namespacing and classes. The __init__.py shown there would have also allowed the usepackage.py script to have been written this way (package maps to subdir in your question, and Class1 to myclass01, etc):
from package import *
print Class1
print Class2
print Class3
Revision (updated):
Oops, sorry, the code in my other answer doesn't quite do what you want — it only automatically imports the names of any package submodules. To make it also import the named attributes from each submodule requires a few more lines of code. Here's a modified version of the package's __init__.py file (which also works in Python 3.4.1):
def _import_package_files():
""" Dynamically import all the public attributes of the python modules in this
file's directory (the package directory) and return a list of their names.
"""
import os
exports = []
globals_, locals_ = globals(), locals()
package_path = os.path.dirname(__file__)
package_name = os.path.basename(package_path)
for filename in os.listdir(package_path):
modulename, ext = os.path.splitext(filename)
if modulename[0] != '_' and ext in ('.py', '.pyw'):
subpackage = '{}.{}'.format(package_name, modulename) # pkg relative
module = __import__(subpackage, globals_, locals_, [modulename])
modict = module.__dict__
names = (modict['__all__'] if '__all__' in modict else
[name for name in modict if name[0] != '_']) # all public
exports.extend(names)
globals_.update((name, modict[name]) for name in names)
return exports
if __name__ != '__main__':
__all__ = ['__all__'] + _import_package_files() # '__all__' in __all__
Alternatively you can put the above into a separate .py module file of its own in the package directory—such as _import_package_files.py—and use it from the package's __init__.py like this:
if __name__ != '__main__':
from ._import_package_files import * # defines __all__
__all__.remove('__all__') # prevent export (optional)
Whatever you name the file, it should be something that starts with an _ underscore character so it doesn't try to import itself recursively.
Your best option, though probably not the best style, is to import everything into the package's namespace:
# this is subdir/__init__.py
from myclass01 import *
from myclass02 import *
from myclass03 import *
Then, in other modules, you can import what you want directly from the package:
from subdir import Class1
I know it's been a couple months since this question was answered, but I was looking for the same thing and ran across this page. I wasn't very satisfied with the chosen answer, so I ended up writing my own solution and thought I'd share it. Here's what I came up with:
# NOTE: The function name starts with an underscore so it doesn't get deleted by iself
def _load_modules(attr_filter=None):
import os
curdir = os.path.dirname(__file__)
imports = [os.path.splitext(fname)[0] for fname in os.listdir(curdir) if fname.endswith(".py")]
pubattrs = {}
for mod_name in imports:
mod = __import__(mod_name, globals(), locals(), ['*'], -1)
for attr in mod.__dict__:
if not attr.startswith('_') and (not attr_filter or attr_filter(mod_name, attr)):
pubattrs[attr] = getattr(mod, attr)
# Restore the global namespace to it's initial state
for var in globals().copy():
if not var.startswith('_'):
del globals()[var]
# Update the global namespace with the specific items we want
globals().update(pubattrs)
# EXAMPLE: Only load classes that end with "Resource"
_load_modules(attr_filter=lambda mod, attr: True if attr.endswith("Resource") else False)
del _load_modules # Keep the namespace clean
This simply imports * from all .py files in the package directory and then only pulls the public ones into the global namespace. Additionally, it allows a filter if only certain public attributes are desired.
I use this simple way:
add the directory to the system path, then
import module or from module import function1, class1 in that directory.
notice that the module is nothing but the name of your *.py file, without the extension part.
Here is a general example:
import sys
sys.path.append("/path/to/folder/")
import module # in that folder
In your case it could be something like this:
import sys
sys.path.append("subdir/")
import myclass01
# or
from myclass01 import func1, class1, class2 # .. etc
from subdir.* import *
You can not use '*' this way directly after the 'from' statement.
You need explict imports. Please check with the Python documentation on imports and packages.

Categories