22

How do I reference a file relatively to a package's directory?

My directory structure is:

    /foo
     package1/
      resources/
      __init__.py
     package2/
      resources/
      __init__.py
     script.py

script.py imports packages package1 and package2. Although the packages can be imported by any other script on the system. How should I reference resources inside, say, package1 to ensure it would work in case os.path.curdir is arbitrary?

5 Answers 5

27

If you want to reference files from the foo/package1/resources folder you would want to use the __file__ variable of the module. Inside foo/package1/__init__.py:

from os import path
resources_dir = path.join(path.dirname(__file__), 'resources')
Sign up to request clarification or add additional context in comments.

1 Comment

As noted by another answer, this won't work if your application is packaged in a zip file.
14

A simple/safe way to do this is using the resource_filename method from pkg_resources (which is distributed with setuptools) like so:

from pkg_resources import resource_filename
filepath = resource_filename('package1', 'resources/thefile')

Or, if you're implementing this inside package1/___init___.py:

from pkg_resources import resource_filename
filepath = resource_filename(__name__, 'resources/thefile')

This gives you a clean solution that is also (if I'm not mistaken) zip safe.

1 Comment

It looks like pkg_resources has been deprecated in favor of importlib.resources and its backport importlib_resources
4

You can be zip-safe and at the same time use a nice convenient API if you use twisted.python.modules.

For example, if I have a data.txt with some text in it and and this sample.py in one directory:

from twisted.python.modules import getModule
moduleDirectory = getModule(__name__).filePath.parent()
print repr(moduleDirectory.child("data.txt").open().read())

then importing sample will do this:

>>> import sample
'Hello, data!\n'
>>>

If your module is in a regular directory, getModule(__name__).filePath will be a FilePath; if it's in a zip file, it will be a ZipPath, which supports most, but not all, of the same APIs.

Comments

0

Use importlib_resources.

Adding to the the example in the question, you might have something that looks like this:

    /foo
     package1/
      resources/
      __init__.py
      resource1.txt
     package2/
      resources/
      __init__.py
     script.py

In Python you can use:

from importlib_resources import files
resource_path = files('package1.resources').joinpath('resource1.txt')
resource_contents = resource_path.read_text()

Comments

-1

This is a bad idea, because, if your package was installed as zipped egg, then resources can be unavailable.

If you use setuptool, don't forget to add zip_safe=False to the setup.py config.

1 Comment

This is true, but it should really have been in a comment rather than an answer, since it doesn't answer the question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.