Python— access relative file path from two different files from different directory in same project

Tags: , ,



If the question is not clear, Let me give an example. Suppose this is my project structure:

app.py
dir1  
   ... Workflow.py
   ... config.yml

In app.py I import Workflow. Workflow.py reads from config.yml. If I want to run workflow.py individually I can simply give the file path as config.yml because it is in the same folder. However, when I import Workflow in app.py and run it, the path can not be resolved. If I change the path in workflow.py as dir1/config.yml, app.py runs successfully but now workflow.py does not run.

I want to be able to run both the file individually. How do I resolve this path issue?

Thank you very much in advance

Answer

Here is how you directory structure looks like:

rootdir
├───app.py
└───dir1
    ├───workflow.py
    └───config.yml

For example, workflow.py looks like this:

def run():
with open('config.yml') as c:
    print(c.read())

if __name__ == '__main__':
    run()

Running python app.py from rootdir, will produce an error due to the fact that config.yml is a relative path and it is relative to your current working directory which is rootdir and rootdir/config.yml does not exist.

Running python workflow.py from dir1 would succeed, because the relative path would point to an existing file in this case.

Simple Solution

You could make the path different depending on how the script was called using the __name__ variable:

CONFDIR = 'dir1'

def run():
    with open(f'{CONFDIR}/config.yml') as c:
        print(c.read())

if __name__ == '__main__':
    CONFDIR = '.'
    run()

This way, the if block will get executed only if the script is run directly (python workflow.py) and the import from app.py will work correctly. On the other hand, if you wanted to run python dir1/workflow.py from rootdir, it would fail, because the relative path to config is wrong again.

Better Solution

You could create an environment variable and store the path to the file there. workflow.py would look like this:

import os

def run():
    with open(os.environ.get("CONFIG_PATH", "./config.yml")) as c:
        print(c.read())

if __name__ == '__main__':
    run()

Run app.py like this:

CONFIG_PATH="dir1/config.yml" python ./app.py

Run workflow.py like this:

CONFIG_PATH="./config.yml" python ./workflow.py

or like this if CONFIG_PATH is not set:

python ./workflow.py

This way the path to the configuration file is also configurable and you don’t need to hardcode it. It also provides a default value of ./config.yml if CONFIG_PATH is not set.



Source: stackoverflow