Get path to static files (static resources, test resources)

TL;DR; How do I get the file path relative to the notebook or package? I have static resources but trouble getting the path to them.

Currently, I have this ugly hack. But is there a better solution for that?

# mynb.ipynb
#| exporti
def get_test_resources_path():
    if '__file__' not in globals():
        # Case when we run the notebook (mynb.ipynb) itself 
        p =  Path.cwd().parent / 'test_resources'
        if not p.exists():
            # Case when we run e.g. nbdev_preview from the library root (my-lib/)
            p = Path.cwd() / 'test_resources'
    else:
        # Case when we use the exported script (my-lib/my_lib/mynb.py)
        p = Path(__file__).parent.parent / 'test_resources'
    assert p.exists(), f"Path {p} does not exist"
    return p

This is my project structure:

- my-lib
  - nbs
    - mynb.ipynb
  - my_lib
    - mynb.py
  - test_resources
    - static_file.txt
  - MANIFEST.ini
  - (other stuff)

To include the static files, i added this to the MANIFEST.ini

recursive-include * test_resources 

Any suggestions or solutions? I’m sure I’m not the only one with this problem…
(I’m guessing fastai does something similar with e.g. fastai/nbs/images at master · fastai/fastai · GitHub but i can’t figure out how)

IMHO, one never should try to fiddle with relative paths on your own, instead use the well-working importlib.resources module for that: importlib.resources – Package resource reading, opening and access — Python 3.12.5 documentation

And I was wondering if the MANIFEST.INI entry should not be
recursive-include test_resources *
?

1 Like

Hi Michael

  1. Thanks, importlib.resources seems to work fine. Here is my updated code for those who are interested:
from importlib_resources import files
import my_lib

def get_test_resources_path():
    return files(my_lib).parent / "test_resources"
  1. And I was wondering if the MANIFEST.INI entry should not be
    recursive-include test_resources *

Also true, I changed it. However both works (“import all* folders named test_resources” vs “from test_resources import everything*” as i understand it), but yours is more correct in this sense. Edit: Mine did actuall just include an empty folder without the files. So yours is truly correct, thanks!

Cheers
Timon