[Distutils] PATCH: setuptools-0.4a3 resource loading from egg problem

Ryan Tomayko rtomayko at gmail.com
Tue Jun 14 14:17:55 CEST 2005

I've been getting the following when trying to use resource_filename  
when my package is in a zipped egg (since somewhere around 0.3a2 or so):

Traceback (most recent call last):
   File "/usr/local/bin/somescript.py", line 4, in ?
     pkg_resources.run_main('somepackage==1.0', 'somescript.py')
   File "setuptools/pkg_resources.py", line 110, in run_main
   File "setuptools/pkg_resources.py", line 599, in run_script
     exec script_code in namespace, namespace
   File "/usr/local/bin/somescript.py", line 7, in ?

   File "egg/somepackage/somemodule.py", line 3, in ?
   File "setuptools/pkg_resources.py", line 388, in resource_filename
     return get_provider(package_name).get_resource_filename(
   File "setuptools/pkg_resources.py", line 728, in  
     return self._extract_resource(manager, resource_name)
   File "setuptools/pkg_resources.py", line 745, in _extract_resource
     zip_stat = self.zipinfo[os.path.join(*self.prefix+parts)]
KeyError: 'somepackage/someresource.txt'

Here's a test egg that illustrates the problem:


Install that and then run the included "somescript.py". You should  
see the traceback above.

The problem seems to be with loading resources relative to a module  
in a package. The egg contains a package "somepackage" and a module  
within that package "somemodule". somemodule calls ``resource_filename 
(__name__, 'someresource.txt')``. The ZipProvider seems to handle  
this case badly.

Attached is a patch against 0.4a3 that fixes this particular case but  
I'm not confident it won't cause problems elsewhere. I'll comment  
each hunk here with an explanation of what I think may be happening.

@@ -573,7 +573,7 @@
      def resource_listdir(self,resource_name):
-        return self._listdir(self._fn(self.egg_info,resource_name))
+        return self._listdir(self._fn(self.module_path, resource_name))
      def metadata_listdir(self,name):
          if self.egg_info:

Here we see NullProvider.resource_listdir using [path]/EGG_INFO  
instead of [path]. This seems like a simple typo to me as there are  
resource_XXX and metadata_XXX methods, the first based on the module  
path and the second set based on the EGG_INFO dir.

@@ -703,7 +703,7 @@
      def __init__(self, module):
          self.zipinfo = zipimport._zip_directory_cache 
-        self.zip_pre = self.loader.archive+os.sep
+        self.zip_pre = self.module_path + os.sep
      def _short_name(self, path):
          if path.startswith(self.zip_pre):

This is where I was a bit shaky:

     loader_archive = /path/to/the-egg.egg
     module_path = /path/to/the-egg.egg/package

Shouldn't resource loading be relative to the package directory and  
not the root of the egg?

@@ -738,7 +738,7 @@
      def _extract_resource(self, manager, resource_name):
          if self.resource_isdir(resource_name):
-            return self._extract_dir(resource_name)
+            return self._extract_directory(manager, resource_name)
          parts = resource_name.split('/')
          zip_path = os.path.join(self.module_path, *parts)

I believe this was a simple typo / refactoring-miss. This isn't  
breaking the test case but is causing problems in another package  
that is using resource_filename to get a directory.


Ryan Tomayko
                                  rtomayko at gmail.com

-------------- next part --------------
A non-text attachment was scrubbed...
Name: zip-resource-loading.patch
Type: application/octet-stream
Size: 1107 bytes
Desc: not available
Url : http://mail.python.org/pipermail/distutils-sig/attachments/20050614/23661a54/zip-resource-loading.obj
-------------- next part --------------

More information about the Distutils-SIG mailing list