Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

zipimporter can't find/load sub-modules

I'm trying to load a sub-module from a ZIP package but it won't work. How to do it right?

foo.zip

foo/
    __init__.py
   bar.py

test.py

import os
import zipimport

dirname = os.path.dirname(__file__)
importer = zipimport.zipimporter(os.path.join(dirname, 'foo.zip'))
print importer.is_package('foo')
print importer.load_module('foo')
print importer.load_module('foo.bar')

Output

$ python test.py
True
<module 'foo' from 'foo.zip/foo/__init__.py'>
Traceback (most recent call last):
  File "test.py", line 8, in <module>
    print importer.load_module('foo.bar')
zipimport.ZipImportError: can't find module 'foo.bar'

Update 2015/04/11 06:30 AM PT

The following would work, but is this the real solution to the problem? The zipimport.zipimporter documentation explicitly states "fullname must be the fully qualified (dotted) module name." and has an is_package() method that seems to function properly.

import os
import zipimport

dirname = os.path.dirname(__file__)
importer = zipimport.zipimporter(os.path.join(dirname, 'foo.zip'))

def load_module(name):
    parts = name.split('.')
    module = importer.load_module(parts[0])
    full_name = parts[0]
    for part in parts[1:]:
        full_name += '.' + part
        if not hasattr(module, '__path__'):
            raise ImportError('%s' % full_name)
        path = module.__path__[0]
        module = zipimport.zipimporter(path).load_module(part)

    return module

print load_module('foo.bar')
like image 338
Niklas R Avatar asked Apr 11 '15 13:04

Niklas R


1 Answers

It will load if you change importer.load_module('foo.bar') to importer.load_module('foo/bar'). I am not sure why, because the documentation reads

load_module(fullname)

Load the module specified by fullname. fullname must be the fully qualified (dotted) module name. It returns the imported module, or raises ZipImportError if it wasn’t found.

like image 153
wrgrs Avatar answered Oct 29 '22 15:10

wrgrs