pythonimportmoduleimppython-importlib

Trouble with imp.load_source: 'module' has no attribute 'foo'


I have a directory filled with an arbitrary number of modules, each of which contains only a function do_stuff. For example:

foos/
    __init__.py
    foo_1.py
    foo_2.py
    ...
    foo_n.py

foo_1.py, for example, could just be:

def do_stuff(bar):
    if bar.blah:
        return True
    return False

From elsewhere in the code, I want to collect and run all the do_stuff functions. I though this would be easy with the imp module:

import imp
...
...

FOOS_DIR = os.path.join(MY_HOME, 'foos/') 
MOD_REGEX = r'^(?!__).*\.py$'                                            

foos = [imp.load_source(fname.split('.py')[0], FOOS_DIR)              
            for fname in os.listdir(FOOS_DIR)                         
               if re.match(MOD_REGEX, fname)]                          

results = [foo.do_stuff('argument!') for foo in foos]  

However, this leads to:

AttributeError: "'module' object has no attribute 'do_stuff'"

From the top answer here, I thought this was the way to go. If it is, maybe my syntax is off? After all, load_source is really forgiving:

(pdb) imp.load_source('not_there', FOOS_DIR)
<module 'not_there' from '/home/blah/blah/foos'>

Otherwise, what could I be missing?


Solution

  • It is indeed a syntax issue! I need the full path to the module file, not just its directory, as the second argument to load_source:

    Thus,

    foos = [imp.load_source(fname.split('.py')[0], FOOS_DIR)              
                for fname in os.listdir(FOOS_DIR)                         
                   if re.match(MOD_REGEX, fname)] 
    

    Becomes

    foos = [imp.load_source(fname.split('.py')[0], '%s%s' % (FOOS_DIR, fname))              
                for fname in os.listdir(FOOS_DIR)                         
                   if re.match(MOD_REGEX, fname)] 
    

    And it works just fine!