Oliver Leung
Oliver Leung

Reputation: 305

Python - Relative file locations when calling submodules

In Python, I'm trying to access a file from the directory where the "last" function (for lack of a better word) is located.

For example, let's suppose I have the following files:

C:/
    foo.py
    package/
        helper.py
        text.md

foo.py has:

from package import helper

helper.edit_file("text.md")

helper.py has:

from os.path import abspath

def edit_file(file_location):
    with open(abspath(file_location), "w") as file:
        file.write("This file has been written to.")

And text.md is just an empty text file.

When I directly run edit_file("text.md") from helper.py, it writes to package/text.md properly. However, when I run foo.py, it doesn't write to package/text.md and instead creates a new text.md in the same directory level as foo.py. I'm assuming that this happens because it's taking an absolute path from where foo.py is located.

Is it possible to only take the absolute path from helper.py, so that it always writes to package/text.md, no matter where the original call to edit_file(file_location) is?

Upvotes: 5

Views: 225

Answers (1)

Evgeny
Evgeny

Reputation: 4551

I think file_location in edit_file() is ambigious - it has to be either a fullpath, or a filename that is later added to some directory. Also abspath() creates an absolute path on a given file, but does not select a directory for you.

In your case you need to set a directory for the file and create full path explicitly. A usual way to find the directory name for a given file is os.path.dirname(os.path.abspath(__file__)), __file__ is python internal variable associated with individual file, it holds the file path.

helper.py can be something like:

import os
BASEDIR = os.path.dirname(os.path.abspath(__file__))

def make_path(filename, directory=BASEDIR):
    return os.path.join(directory, filename) 

def edit_file(filename):
    with open(make_path(filename), "w") as file:
        file.write("This file has been written to.")

You can also set a specific directory for the markdown files in your package - normally you do not write to the folder where your code is. You can achieve navigating to your project root through calling dirname or Path(__file__).parents[n] in Python 3.6+.

Specifically with Python 3.6 the code in helper.py is even more concise:

from pathlib import Path 

def update(filename: str, text: str):
    path = Path(__file__).parent / filename 
    path.write_text(text)

update("text.md", "This file has been written to.")

Upvotes: 2

Related Questions