Search code examples
pythonimportcompiledpyc

trying to import a *.pyc as a module


I have a python script that is trying to import another script somewhere in the file-system (path is only known at runtime). To my understanding I need to use the imp module and this might work, but when loading the module I get an error that modules used by the imported module are not found.

Heres the code:

importer.py:

import imp
imp.load_compiled("my_module","full_path_to_my_module\\my_module.pyc")

my_module.py:

import sys
import another_module

When I run importer.py I get htis error message:

ImportError: No module named another_module

Whats going wrong here ? I suspect that when 'importer.py' is loading 'my_module.pyc' hes also trying to load 'another_module' (thats good) but is looking in the wrong place (eg not 'full_path_to_my_module')

EDIT: I tried adding 'full_path_to_my_module' to the system path:

import imp
import sys

sys.path.append(full_path_to_my_module)
imp.load_compiled("my_module",full_path_to_my_module+my_module)

But I still get the same error

Maybe I do something thats not necessary - Here's my goal: I want to be able to use all functionality of 'my_module.pyc' inside 'importer.py'. But the location of 'my_module.pyc' is given as a parameter to 'importer.py'.


Solution

  • imp.load_compiled returns the compiled module object, it is different to the import statement which also binds the module to a name

    import imp
    my_module = imp.load_compiled("my_module", "full_path_to_my_module/my_module.pyc")
    

    Then you can do something like:

    my_module.yayfunctions('a')
    

    Complete example session:

    $ cat /tmp/my_module.py
    def yayfunctions(a):
        print a
    $ python -m compileall /tmp/my_module.py
    $ ls /tmp/my_module.py*
    my_module.py   my_module.pyc
    $ python
    >>> import imp
    >>> my_module = imp.load_compiled("my_module", "/tmp/my_module.pyc")
    >>> my_module.yayfunctions('a')
    a
    

    Edit regarding comment (ImportError: No module named another_module), I assume the error is caused by the code in my_module.pyc, and the another_module.py lives in the same directory

    In that case, as others have suggested, it's simpler to just add the directory containing my_module to sys.path and use the regular import mechanism, specifically __import__

    Here's a function which should do what you want:

    import os
    
    
    def load_path(filepath):
        """Given a path like /path/to/my_module.pyc (or .py) imports the
        module and returns it
        """
    
        path, fname = os.path.split(filepath)
        modulename, _ = os.path.splitext(fname)
    
        if path not in sys.path:    
            sys.path.insert(0, path)
    
        return __import__(modulename)
    
    
    if __name__ == '__main__':
        # Example usage
        my_module = load_path('/tmp/my_module.py')
        my_module.yayfunctions('test')