7

I don't understand how exactly pkg_resource.resource_filename() work and what are its parameters. I searched a lot on web but their official documentation does not cover it well. Can someone explain it?

Ayush Jain
  • 316
  • 4
  • 11

2 Answers2

5

Here are a few examples. I have wheel 0.24 installed in an old environment:

pkg_resources.resource_filename('spamalot', "wheel/__init__.py")    
ImportError: No module named spamalot

The first argument has to be importable. The second argument should be a relative, /-separated path, including on systems that use \ to separate paths.

In [27]: pkg_resources.resource_filename('distutils', "wheel/__init__.py")
Out[27]: '/opt/pyenv/lib64/python2.7/distutils/wheel/__init__.py'

If it is importable, you will get a path inside the imported name. In this case it doesn't matter whether the file exists.

In [28]: pkg_resources.resource_filename(pkg_resources.Requirement.parse('wheel>0.23.0'), "core.py")
Out[28]: '/opt/pyenv/lib/python2.7/site-packages/core.py'

You can pass a requirement, and it will check if you actually have it installed. Now the path is relative to the install directory and not the wheel package.

In [29]: pkg_resources.resource_filename(pkg_resources.Requirement.parse('wheel>0.27.0'), "core.py")

VersionConflict: (wheel 0.24.0 (/opt/pyenv/lib/python2.7/site-packages), Requirement.parse('wheel>0.27.0'))

If the requirement is not installed it will complain.

One reason the Requirement feature exists is because it's possible to have eggs for multiple versions of the same package on the path, and pkg_resources will add the requested version, but this feature is not used very much any more.

These examples are pretty simple, but resource_filename will also work if your resources are inside a .zip file or any other supported import location (it is possible to hook Python's import system so that imports come from anywhere - sqlite databases, the network, ..., and resource_filename should be able to work with these if the right hooks are installed.)

joeforker
  • 40,459
  • 37
  • 151
  • 246
  • Okay Thanks for answering. I am getting how pkg_resources work but what location is resource_filename() returning? Is it the location of install module in first arguement or is it the location of the file or directory in second arguement? – Ayush Jain Mar 07 '19 at 20:37
  • The second command returns /home/ayush/anaconda3/lib/python3.6/distutils/wheel/__init__.py to me. What does it specifies? – Ayush Jain Mar 07 '19 at 20:39
  • resource_filename(a, b) is returning you a path underneath where the module a is installed. In the simple case it just joins the path of a with b. In complex cases (like a zip file) it extracts the resource to the filesystem first and returns that path. – joeforker Mar 07 '19 at 20:48
  • Ohh okay I got it. Thank you so much. – Ayush Jain Mar 07 '19 at 20:54
0

Official documentation is available here (as documented in the relevant PEP).

resource_filename(package_or_requirement, resource_name)

Sometimes, it is not sufficient to access a resource in string or stream form, and a true filesystem filename is needed. In such cases, you can use this method (or module-level function) to obtain a filename for a resource. If the resource is in an archive distribution (such as a zipped egg), it will be extracted to a cache directory, and the filename within the cache will be returned. If the named resource is a directory, then all resources within that directory (including subdirectories) are also extracted. If the named resource is a C extension or "eager resource" (see the setuptools documentation for details), then all C extensions and eager resources are extracted at the same time.

Archived resources are extracted to a cache location that can be managed by the following two methods:

Kashyap
  • 15,354
  • 13
  • 64
  • 103