0

Suppose I have a collection of functions in a module called my_functions.py. One of these functions must load data from a text file that is stored in the same directory as my_functions.py. For example:

# contents of my_functions.py
def func1():
    # first thing, load a file in same directory as my_functions.py
    data = open("blah.txt", "r").read()

If I import my_functions into calling_code.py and then call func1 I get an error telling me blah.txt is not a file. This occurs because calling_code.py is not in the same directory as my_functions. I tried tricking func1 to define it's relative path using this line from here, but even this defines the path as the calling_code.py's directory.

__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))

The only other thing I can think of is to load my_functions.py in func1 so I can then call it's __file__ attribute. e.g.

# contents of my_functions.py
def func1():
    # load my_functions.py
    import my_functions as mf
    root = os.path.dirname(my_functions.__file__)
    src = os.path.join(root, "blah.txt")

    # load a file in same directory as my_functions.py
    data = open(src, "r").read()

While this works, it seems like a bit of a hack. Is there another way to go about this?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
tnknepp
  • 5,888
  • 6
  • 43
  • 57

1 Answers1

1

This is a design problem. If the location of blah.txt is fixed relative to my_functions.py, then func1 cannot use a hard coded relative path, because it relates to the working directory, not to the location of the source code.

If you don't want to use __file__, other solutions are:

  • Pass the path to blah.txt as an argument to func1:

    def func1(blah_path):
        data = open(blah_path, "r").read()
    
  • Use an environment variable to specify the path to blah.txt:

    import os
    
    def func1():
        data = open(os.environ["FUNC1_BLAH_PATH"], "r").read()
    
  • Replace blah.txt by a module containing the data and use a relative import:

    from . import blah
    
    def func1():
        data = blah.data
    
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • Well, I'm trying to avoid hard coding the path since I use this module on different systems (different servers at different times), so I'm trying to avoid rewriting the path each time I export the module to a new/different server (or use it locally). – tnknepp Feb 17 '21 at 19:22