DarkTrick
DarkTrick

Reputation: 3467

Relative path of file does not get solved

Apparently python takes every related importation in relation to the first called file.

I have the following file structure

src
 |--myunittests.py
 |--subfolder1
      |--__init__.py
      |--printFileContent.py
      |--subfolder2
           |--__init__.py
           |--file

myunittests.py will test the behavior of functions inside printFileContent:

from subfolder1.printFileContent import printFileContent
printFileContent()

printFileContent prints the content of a file contained inside the subfolder:

def printFileContent():
with open("./subfolder2/file") as file:
    for line in file:
        print(line)


if __name__ == "__main__":
    printFileContent()

file just contains some text.

Question: Doing python3 printFileContent.py inside the subfolder1 will correctly output the file content. But doing python3 myunittests.py raises the error, that the file could not be found.

Is there a way to solve this problem? (Is there a way to tell python, that files refered relative programmatically should be relative to the file they are used in?

constraints

When does this behavior occur? When file is an icon that is used inside printFileContent.py, while printFileContent.py is called from myunittests.py

Sidequestion: Is there a proper title/bulletpoint word for explaining / finding out about this behavior and problems with it?

Upvotes: 2

Views: 58

Answers (1)

Holt
Holt

Reputation: 37606

If you cannot modify printFileContent.py, you can save the current directory, go to the directory of subfolder1 and then come back to the original directory:

import subfolder1
import os

# Save current directory (absolute path)
cdir = os.path.abspath(os.path.curdir)

# Change directory, and call printFileContent
os.chdir(os.path.dirname(subfolder1.__file__))
subfolder1.printFileContent()

# Go back to the original directory
os.chdir(cdir)

If you have to use this a lot of time, you can make this behavior a class usable with a with statement so that it's easier to use and more robust (you won't forget to chdir back):

import os

class TmpDirChanger:
  def __init__(self, tmpPath):
    self.currentDir = os.path.abspath(os.path.curdir)
    os.chdir(tmpPath)

  def __enter__(self): pass

  def __exit__(self, exc_type, exc_val, exc_tb):
    #change back to original dir
    os.chdir(self.currentDir)

with TmpDirChanger('path/to/some/dir'):
   do_something()

If you can modify printFileContent.py, it is less tricky:

import os

def printFileContent():
    # This will give you path to subfolder1
    sfolder1 = os.path.dirname(__file__)

    # This will give you path to "file" in subfolder2
    name = os.path.join(sfolder1, 'subfolder2', 'file')

    with open(name) as file:
        for line in file:
            print(line)

Upvotes: 2

Related Questions