How to dynamically import modules with exec - python

Now I want to built a function get_doc( ) which can get the doc of the module
Here's the code
def get_doc(module):
exec "import module"
print module.__doc__
And the information returned:
Traceback (most recent call last):
File "<pyshell#36>", line 1, in <module>
get_doc(sys)
NameError: name 'sys' is not defined

The problem is you're importing "module" instead of the specified module, and you didn't put the name module anywhere. A stupid fix to this would be to always using exec
def get_doc(module):
exec "import {}".format(module)
exec "print {}.__doc__".format(module)"
But instead of exec, i would advise you to use the __import__ function:
def get_doc(module):
module = __import__(module)
print module.__doc__
Which allows more flexibility, and you can modify, use module as you wanted.

When you say
get_doc(sys)
python will not be able to recognize sys. The actual way to do what you are trying to do would be to
pass the module name as a string parameter
use __import__ function to load the module, like this
def get_doc(module):
mod = __import__(module)
print mod.__doc__
get_doc("sys")
Note: I am not in favor of executing dynamic code in programs, but if you must use exec to solve this problem read this and have a basic understanding about the security implications and then look at aIKid's solution.

Related

Python circular reference importing doesn't work when using "as"

Let me first establish what working scenario.
main.py
module/file1.py
module/file2.py
main.py
import module.file1
print(module.file1)
module/file1.py
import module.file2
module/file2.py
import module.file1
Running python3 main.py gives me the following, which is fine.
<module 'module.file1' from '/project/module/file1.py'>
Now, if I change module/file2.py to have the following:
import module.file1 as testtt
I get this new output (error):
Traceback (most recent call last):
File "main.py", line 1, in <module>
import module.file1
File "/project/module/file1.py", line 1, in <module>
import module.file2
File "/project/module/file2.py", line 2, in <module>
import module.file1 as testtt
AttributeError: module 'module' has no attribute 'file2'
I'm guessing that python doesn't fully evaluate the imported module when simply importing, causing the circular reference to blow up only when you immediately use it within either of the two files.
I'd imagine I also would not get the error if I used the module in a function, since that would be evaluate when the function is actually called, like this:
import module.file1
def test():
print(module.file1)
What is the recommendation here? Should I just work to remove the circular reference? It seems like code smell anyway (existing code base).
Its an implementation detail. The import statement uses the __import__ function to do the work of finding and importing the module and then binds its returned module to the as testtt variable.
When doing a nested import like import module.file1 as testtt, __import__ returns the base module ("module"). Since the importer still needs to bind "file1" to the local namespace, it has to look up the submodule name "file1" on that object. Since the import of file1 is still in progress, it hasn't been bound to the "module" module yet.
It works in the import module.file1 case because file1 isn't bound to the local namespace and doesn't need a lookup.
There are many pitfalls with circular imports that will bedevil you throughout your code's life cycle. Good luck!
"import" is an executable statement, so you can just do the import inside the function
def test():
import module.file1
print(module.file1)

Python 3 issues importing multiprocessing with __import__

So the issues that I am currently hitting is with the use of __import__ and even just the standard import. When importing multiprocessing just the main package it will go through however when I run a simple test to see if everything is working for it. I come across an error, below is the current code that IS NOT working.
__import__('multiprocessing')
def my_function():
print('Hello World')
if __name__ == '__main__':
processd = multiprocessing.Process(target=my_function)
processd.start()
processd.join()
it run it will return the following error:
Traceback (most recent call last):
File "F:\Webserv\Python\MP.py", line 7, in <module>
processd = multiprocessing.Process(target=my_function)
NameError: name 'multiprocessing' is not defined
Is there something I am missing with this?
__import__ is a function, therefore you need to capture its return value:
multiprocessing = __import__('multiprocessing')
The standard way is to use the import statement:
import multiprocessing
This is the preferred way. Do programmatic imports only when you really need them. Furthermore, __import__ should not be used:
Import a module. Because this function is meant for use by the Python
interpreter and not for general use it is better to use
importlib.import_module() to programmatically import a module.

how do you reload a module in python version 3.3.2

whenever I try to reload a python module in python version 3.3.2 i get this error code
>>> import bigmeesh
>>> bob=bigmeesh.testmod()
this baby is happy
>>> imp.reload(bigmeesh)
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
imp.reload(bigmeesh)
NameError: name 'imp' is not defined
I tried researching and still got no answers.
You have to import imp before you can use it, just as with any other module:
>>> import bigmeesh
>>> import imp
>>> imp.reload(bigmeesh)
Note that the documentation clearly says:
Note: New programs should use importlib rather than this module.
However, in 3.3, importlib doesn't have a simple reload function; you'd have to build it yourself out of importlib.machinery. So, for 3.3, stick with imp. But in 3.4 and later which do have importlib.reload, use that instead.
It's also worth noting that reload is often not what you want. For example, if you were expecting bob to change into an instance of the new version of bigmeesh.testmod(), it won't. But, on the other hand, if you were expecting it to not change at all, you might be surprised, because some of its behavior might depend on globals that were changed.
This is the modern way of reloading a module:
# Reload A Module
def modulereload(modulename):
import importlib
importlib.reload(modulename)
Just type modulereload(MODULE_NAME), replacing MODULE_NAME with the name of the module you want to reload.
For example, modulereload(math) will reload the math function.

Python import hooks: no filenames in trackback of import errors

I've written an import hook according to PEP 302 and it seems to work fine except one annoying detail.
When there's an import error, say code that tries to import a module that doesn't exist, I get a trackback with lines like:
File "<string>", line 10, in helloEnv
line 10 is where the call to the non-existing import resides but there is no file name, just <string>.
My import hooks looks pretty much like the minimal one in PEP 302. In the creation of the module I always set a proper string value to __file__ and even check that new_module() sets a correct value to __name__. Also, both str() and repr() of the module return something informative.
These nameless files in the trackback makes it hard to debug import errors. Where does the trackback take its filenames from? why doesn't it see the names of the modules?
EDIT - thinking about it some more, it's probably since the module code is executed using exec(). is it possible to give exec() a filename?
Ok, so that was simple enough. instead of
exec(code, mod.__dict__)
write:
exec(compile(code, fullname, "exec"), mod.__dict__)

python __import__ all files in folder not working

from os import listdir
modo= [name.split(".py")[0] for name in listdir("scripts") if name.endswith(".py")]
modules = {}
for modu in modo:
modules[modu] = __import__(modu)
test_samp.function("test")
Hello!
If, say "test_samp.py" exists in the scripts directory, why does
this not allow me to run test_samp.function("test")?
It returns:
Unhandled exception in thread started by <function function at 0x8e39204>
Traceback (most recent call last):
File "test_this.py", line 6, in function
test_samp.function("test")
NameError: global name 'test_samp' is not defined
You have two problems in your code:
__import__ doesn't import into global namespace, it returns a module
you're trying to import test_samp while it's scripts.test_samp
What you actually want is:
scripts = __import__("scripts", fromlist=modo)
scripts.test_samp.function("test")
Above __import__ returns scripts package with all the sub-modules loaded. Don't forget to make scripts directory a package by creating __init__.py in it.
See also: Why does Python's __import__ require fromlist?
Your are not defining test_samp you are defining modules['test_samp']. Plus if it's in scripts you need to import scripts.test_samp
in yor case use a package.Add an empty (or not) __init__.py (with 2 underscores). and use import scripts. Access your function with scripts.test_samp.function("test"). And you could use reload(scripts) to reload all of the package.
You can run it using this:
modules["test_samp"].function("test")

Categories

Resources