Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

71%
+3 −0
Q&A Open file in script's own folder

Theory Relative paths are relative to the current working directory of the Python process. This can be checked from within Python using the os.getcwd function and set using the os.chdir function. ...

posted 10mo ago by Karl Knechtel‭

Answer
#1: Initial revision by user avatar Karl Knechtel‭ · 2024-02-02T07:11:14Z (10 months ago)
## Theory

Relative paths are relative to the *current working directory* of the Python process. This can be checked from within Python using the `os.getcwd` function and set using the `os.chdir` function.

Whenever Python loads a module, a `__file__` attribute may be set on the resulting module object, giving the path to the source code file that the module is based on. (Normally, this will happen for all user code; but the attribute could be missing for built-in modules like `sys`, or it could be the name of a file containing compiled code if the module was implemented in C.) Within the code for that module, these attributes are just the global variables for that code. (There is also no `__file__` global variable available when using the REPL.)

## The technique

Therefore, the code in `script.py` can simply check the `__file__` global variable to find a full path to `script.py`; and the *containing folder* for `script.py` can thus be determined by parsing that path, in any number of ways. The simplest way is to take advantage of the [`pathlib` standard library module (introduced in Python 3.4)](https://docs.python.org/3/library/pathlib.html), as shown in Moshi's answer.

<section class="notice is-warning">

[In Python 3.9 and above](https://docs.python.org/3/whatsnew/3.9.html#other-language-changes), the same technique also works if `script.py` was run directly as a module. However, in Python 3.4 through 3.8, the `__file__` attribute [**will be a relative path**](https://docs.python.org/3.4/whatsnew/3.4.html#other-language-changes) if `script.py` was run directly as a module. (For example, if the command was `python script.py`, the `__file__` value will be simply `'script.py'`, and the Pathlib logic will produce just `'.'`.)

As a result, this technique *will break if the current working directory has changed* between the time the script was started and the time that the path taken from `__file__` is used.

To avoid this issue, make sure to determine `__file__` immediately, compute an absolute path immediately, and store that path until needed:

```python
from pathlib import Path

# when the script starts
here = Path(__file__).parent.absolute()

# later, possibly after an `os.chdir` call
with open(here / 'data.txt') as file:
    data = file.read()
```
</section>

## Legacy support (Python 3.3 and earlier)

In older versions of Python, `__file__` is still documented to be present on `module` objects (and thus be available as a global variable), with the same purpose. [However, it is not guaranteed to be an absolute path](https://mail.python.org/pipermail/python-dev/2010-February/097461.html). (For an absolute import, it will depend upon the entry in `sys.path` that was used for the import.) Further, `pathlib` is not available.

Thus, the necessary code might look like:
```python
import os

# when the script starts
here = os.path.split(os.path.abspath(__file__))[0]

# later, possibly after an `os.chdir` call
with open(scriptFolder / 'data.txt') as file:
    data = file.read()
```
Here, `os.path.abspath` creates an absolute path, and `os.path.split` splits it into two parts - the "path" (i.e., to the containing folder) and the filename itself.

----

Credit to kindall and wim [on Stack Overflow](https://stackoverflow.com/a/7116925) for the corresponding research about the semantics of `__file__`. kindall uncovered the legacy semantics, which agf then described in that answer; later, wim edited to supply the updated semantics in Python 3.4+.