0

So I'm developing a python package, and one of the classes pulls data from a .txt on instantiation. However when I instantiate that class in unit tests, python attempts to load a txt in the test directory rather than the class'. I'm assuming this will cause further problems when importing this package into other projects, so I want to figure out how consistently reach that target .txt (Kinda in a similar fashion to java's Class.getResource, if that helps)

This is how my project is currently set up:

rootdir
  |
  |----> module
  |       |
  |       |----> __init__.py
  |       |----> class.py
  |       |----> resource.txt (the resource I'm trying to target)
  |
  |----> tests
          |
          |----> __init__.py
          |----> test_class.py

The inside of my class is set up like this:

class Foo:

   def __init__(self, file_path='resource.txt'):
       with open(file_path) as file:
           **do stuff**

As of now, any attempts to provide relative pathing to my resource file causes python to search for the that relative path within /tests (i.e. file_path='module/resource.txt' leads to 'tests/module/resource.txt'). Is there any way to have python find the right resource no matter where this class is called up?

j_wash_BL
  • 45
  • 4
  • Does https://stackoverflow.com/questions/6028000/how-to-read-a-static-file-from-inside-a-python-package answer you question? – Pythocrates Jul 02 '21 at 20:08

1 Answers1

0

In each module, Python injects a __file__ variable at runtime with the full path to the current module file.

So, you take this variable, reach for its parent, and append the desired filename in the same directory.

The pathlib.Path class facilitates doing this:

from pathlib import Path

class Foo:

   def __init__(self, file_name='resource.txt'):
       file_path = Path(__file__).parent / file_name
       with open(file_path) as file:
           **do stuff**

This is the main way this is done. However, Python packages can also be run packaged in a ".zip" or ".egg" file - in that case, your "resource.txt" file won't exist on the filesystem. If you want your package to maintain the ability to run zipped, there is importlib.resources, and, in this case, its read_text call, which would work without resorting to the __file__ variable.

jsbueno
  • 99,910
  • 10
  • 151
  • 209