1

I'm using Python for a weeks now and i'm confronted to an issue with dynamic import. I have a file Test.py that in which a class is defined. I would like to use this class after the dynamic import of Test.py from another file.

My final goal is more complex but I simplified it but i still get the same problem.

File : Test.py

class Test :
    def __init__ ( self ) :
        print ( "instance" )

File : Main.py

def allImports ( ) :
    __import__ ( "Test" )

What i get :

>>> import Main
>>> Main.allImports()
>>> myInstance = Test ()
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
NameError: name 'Test' is not defined

I cannot specify in the fromlist which element from Test.py i have to import because i'm not supposed to know them.

What should i do ?

sloth
  • 99,095
  • 21
  • 171
  • 219
ibi0tux
  • 2,481
  • 4
  • 28
  • 49

4 Answers4

3

For a solution closer to your intent:

import importlib
def allImports(globals):
    mod = importlib.import_module('Test', globals['__name__'])

    try:
        keys = mod.__all__
    except AttributeError:
        keys = dir(mod)

    for key in keys:
        if not key.startswith('_'):
            globals[key] = getattr(mod, key)

# …

allImports(globals())
Test # should work, you can also look into dir(Test) to find the class.

If your module doesn't have an __all__ the code above /will/ clobber your namespace something fierce. Either make sure you define __all__, or modify allImports() to only import the things you want. (E.g. only classes, or only classes defined in the module. This part really depends on your use case.)

millimoose
  • 39,073
  • 9
  • 82
  • 134
  • @millimose, don't you know how to make the class usable without prefixing the module name ? – ibi0tux Jul 05 '12 at 13:46
  • @ibi0tux I changed the code to do something kinda sorta maybe similar to `from Test import *`. You should probably take caution so you only really import the things you want from a module using it. – millimoose Jul 05 '12 at 13:58
  • Ty. This seems to work but i don't understand what's the problem with __all__. – ibi0tux Jul 05 '12 at 14:09
  • If you import any modules into the `Test` module, but don't specify `__all__`, then `from Test import *` will re-export those modules. This means that you're going to reexport a whole lot of crap that you probably didn't mean to. Same goes for helper functions or classes that people using your module don't need / shouldn't use. `__all__` means "these things are interesting to people using this module", and defining it is a best practice. – millimoose Jul 05 '12 at 14:49
  • @millimose, i tried this to import packages but this fails when a file from the package imports another one. Is the problem due to the relative path which is not based on the package's root ? – ibi0tux Jul 06 '12 at 08:42
  • @ibi0tux I honestly have no clue from that description, it might be a problem in my code or it might be that `import_module()` just doesn't do what you want it to right away. You should probably post it as a separate question with an actual example of what you're trying to achieve and the code above. – millimoose Jul 06 '12 at 17:23
1

this code makes __import__ ( "Test" ) a local variable, so you can't access it outside the function.

   def allImports ( ) :
        __import__ ( "Test" )

try:

def allImports ( ) :
   test= __import__ ( "Test" )
   return test   #return the module

>>> import Main
>>> x=Main.allImports()  #store the returned module in x
>>> myInstance = x.Test ()
instance
>>>myInstance
<Test.Test instance at 0x011D7F80>
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
1

When using __import__() to load a module, you have to look it up in sys.modules:

>>> import sys
>>> import Main
>>> Main.allImports()
>>> myInstance = sys.modules['Test'].Test()
instance
>>>

More information in the documentation and here, here, and here.

Community
  • 1
  • 1
sloth
  • 99,095
  • 21
  • 171
  • 219
1

__import__ doesn't modify magically neither global nor local namespaces.

Modules and classes are first class citizens in Python i.e., you can use them as any other object in Python (bind to a name, pass as a parameter to a function, return as a value from a function).

def allImports():
    return __import__("Test")

Test_module = allImports()
Test = Test_module.Test # class
test_instance = Test()

If the above code is inside a function then to put Test into global namespace: globals()['Test'] = Test. Note most probably you don't need it and there are better ways to do whatever you want without modifying global namespace inside a function.

Usage of __import__() is discouraged use importlib.import_module() instead.

If the name of the module and the class are known you could just write at the module level:

from Test import Test
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • Ok. Thank you. The problem is that neither the name of the module and the name of the classes are known. The name of the module is a variable and i want to import all the module content (classes and functions). – ibi0tux Jul 05 '12 at 14:00
  • @ibi0tux: you could get all classes and functions using `inspect.getmembers()` and `inspect.isclass()`, `inspect.isfunction` predicates. If you're creating some kind of plugin system; consider using an existing one such as yapsy – jfs Jul 05 '12 at 14:06
  • yes, i'm working about a plugin system but it is very basic so i didn't look for existing systems. – ibi0tux Jul 05 '12 at 14:20