0

I discovered that a script's "current working directory" is, initially, not the where the script is located, but rather where the user is when he/she runs the script.

If the script is at /Desktop/Projects/pythonProject/myscript.py, but I'm at /Documents/Arbitrary in my terminal when I run the script, then that's going to be it's present working directory, and an attempt at open('data.txt') is going to give File Not Found because it's not looking in the right directory.

So how is a script supposed to open files if it can't know where it's being run from? How is this handled?

My initial thought was to use absolute paths. Say my script needs to open data.txt which is stored alongside it in its package pythonProject. Then I would just say open('/Desktop/Projects/pythonProject/data.txt').

But then you can't ever move the project without editing every path in it, so this can't be the right solution.

Or is the answer simply that you must be in the directory where the script is located whenever you run the script? That doesn't seem right either.

Is there some simple manipulation for this that I'm not thinking of? Are you just supposed to os.chdir to the script's location at the beginning of the script?

temporary_user_name
  • 30,801
  • 41
  • 120
  • 186
  • You can use `__file__` to determine the script's location. – user94559 Apr 04 '17 at 04:14
  • Possible duplicate of [How do I get the path and name of the file that is currently executing?](http://stackoverflow.com/questions/50499/how-do-i-get-the-path-and-name-of-the-file-that-is-currently-executing) – congusbongus Apr 04 '17 at 04:15

2 Answers2

2

Get the current file's directory path, using os.path.dirname, os.path.abspath, os.path.realpath, and the __file__ variable:

import os
file_dir = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))

Then, to create cross-platform filepaths, use os.path.join():

os.path.join(file_dir, "test.txt")

Alternatively, you can change the current working directory to the running file's directory so you don't have to os.path.join every time:

os.path.chdir(os.path.dirname(os.path.abspath(os.path.realpath(__file__))))

Why use os.path.abspath and os.path.realpath? The inner realpath resolves symbolic links, while the abspath resolves relative paths. If you know for sure no symbolic links are being used, you can omit this inner realpath call.

Julien
  • 3,861
  • 2
  • 30
  • 27
  • This is a good answer, but scripts are more useful if they accept the name of files to act on as command-line parameters and only use these techniques to locate static files they need to operate. – cco Apr 04 '17 at 04:54
  • Accepting dynamic filenames as command-line parameters does not seem to be in the scope of the question asked. – Julien Apr 04 '17 at 04:58
  • That is why I added my thoughts as a comment. The question did not seem to consider accepting a filename as an alternative, when in fact it is a common pattern. Your answer is a good one for the question asked. – cco Apr 04 '17 at 05:43
1

A module's location is always available in the __file__ variable. You can use the functions in os.path (I'm mainly thinking of basedir and join) to transform module-relative paths to absolute paths

3Doubloons
  • 1,980
  • 13
  • 25