My script.py creates a temporary file using a relative path.
When running it as:
python script.py
it works as expected.
But it doesn't work when you run it like:
python /path/to/script.py
The problem is that I don't know which path it will be running in. How can I get the absolute path to the script folder (the "/path/to") so the temporary file can be created in the same directory as the script?
What about the following?
os.path.abspath(os.path.dirname(__file__))
Per the great Dive Into Python:
import sys, os
print 'sys.argv[0] =', sys.argv[0] 1
pathname = os.path.dirname(sys.argv[0]) 2
print 'path =', pathname
print 'full path =', os.path.abspath(pathname)
The two current answers reflect the ambiguity of your question.
When you've run python /path/to/script.py, where do you want your tempfile? In the current directory (./tempfile.txt) or in /path/to/tempfile.txt?
If the former, you can simply use the relative path (or, for weird and arcane purposes, get the absolute path equivalent to the current directory as #Desintegr suggests, with os.getcwd).
If the latter, you can learn exactly how the script was invoked with sys.argv[0], as #Jonathan suggests, and manipulate that path with the functions in os.path (of course you can also apply those functions to what os.getcwd returns, if the former case applies), or work with os.path.dirname(__file__) and the like (the latter's necessary if you want this latter behavior also when the script is imported as a module, not just when it's run as a main script).
You can use the os.getcwd() method to know the current working directory.
Return a string representing the current working directory.
Availability: Unix, Windows.
You can use the os.chdir(path) method to change the current working directory.
Change the current working directory to path.
Availability: Unix, Windows.
Related
This question already has answers here:
Closed 12 years ago.
Duplicate:
In Python, how do I get the path and name of the file that is currently executing?
How do I get the path of a the Python script I am running in? I was doing dirname(sys.argv[0]), however on Mac I only get the filename - not the full path as I do on Windows.
No matter where my application is launched from, I want to open files that are relative to my script file(s).
Use this to get the path of the current file. It will resolve any symlinks in the path.
import os
file_path = os.path.realpath(__file__)
This works fine on my mac. It won't work from the Python interpreter (you need to be executing a Python file).
import os
print os.path.abspath(__file__)
7.2 of Dive Into Python: Finding the Path.
import sys, os
print('sys.argv[0] =', sys.argv[0])
pathname = os.path.dirname(sys.argv[0])
print('path =', pathname)
print('full path =', os.path.abspath(pathname))
The accepted solution for this will not work if you are planning to compile your scripts using py2exe. If you're planning to do so, this is the functional equivalent:
os.path.dirname(sys.argv[0])
Py2exe does not provide an __file__ variable. For reference: http://www.py2exe.org/index.cgi/Py2exeEnvironment
If you have even the relative pathname (in this case it appears to be ./) you can open files relative to your script file(s). I use Perl, but the same general solution can apply: I split the directory into an array of folders, then pop off the last element (the script), then push (or for you, append) on whatever I want, and then join them together again, and BAM! I have a working pathname that points to exactly where I expect it to point, relative or absolute.
Of course, there are better solutions, as posted. I just kind of like mine.
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?
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.
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
I have a script called "test.py" and refers to a config file called "cfg.yaml". These two reside in the same directory called "test/scripts".
test/scripts/test.py
test/script/cfg.yaml
Now I am writing a bash script inside "test/data1/data2" called task.sh
From inside of task.sh, I want to make a call to the python script
test.sh contents are as below:
#!/bin/sh
python ../../scripts/test.py
test.py opens and reads the cfg.yaml like open("cfg.yaml") but when the test.sh is called, it fails because "cfg.yaml" is NOT referred with relative path. How do I resolve this?
try
#!/bin/sh
cd ../../scripts
python test.py
I assume in test.py you are referencing the yaml with a local path that expects the script to be running from the scripts directory (not from data1/data2)
as an aside you can always print os.getcwd() to see what your working directory is while running the python script (or just pwd in bash)
If you want to refer to a file in terms of its relative location to the script, you can't just use a relative path for that, because the script may not be in the current working directory. In fact, in your case, it's guaranteed not to be in the current working directory.
The usual quick&dirty solution is to get the script path explicitly:
import os
import sys
scriptdir = os.path.abspath(os.path.dirname(sys.argv[0]))
That sys.argv[0] is the full name of your script—which on most platforms means either an absolute path, or a relative path that's at least still valid at this point. If you're worried about those other platforms, you may want to look at __file__. Of course if you're running the script out of a zipfile or similar, neither one will be useful.
open(os.path.join(scriptdir, "cfg.yaml"))
(Or you can even forcibly os.chdir(scriptdir) if you want, but that can be a bad idea if you're, e.g., accepting pathnames from the user.)
The right solution is to write your script and data files to be installed (even if you don't actually install anything and run it out of the source tree), and then use pkg_resources to find the data files. That will also solve a whole lot of other problems for you—but it does require a bit more learning first. See the Python Packaging User Guide if you want to get started on that road, and Package Data and Data Files as particular starting points.
I am experiencing an odd problem that I'm not quite sure how to tackle. I have a Python-selenium script that uses relative paths to log results to a text-file.
Here is the part of the script which sets up the log-file:
log_file = './demo-logfiles/log_file_template.txt'
sys.stdout = open('log_file_template.txt', 'a',)
As you can see, it uses a relative path to a folder. If I run this script as:
python demo.py firefox MAC, it runs flawlessly and the logfile gets sent to the proper folder.
If I run this exact Python script from within a larger shell-script, it returns an error that the './demo-logfiles/log_file_template.txt' doesn't exist.
I have found that if I change the script to '../demo-logfiles/log_file_template.txt' it works in the larger shell script, but stops working if I run it normally.
It either works in one, or the other. What is the reason for the relative directories being interpreted in different ways? I would not like to have two separate scripts for running in Python/shell.
The original python script is in the directory /blah/blah/DEMO/demo.py, and the the shell script that runs it is in /blah/blah/DEMO/demo-autotest/autotest_logger.sh
I have confirmed that this problem occurs for any script I try to run. I shouldn't have to change the original Python code to make it work with the shell script. I already accounted for it in the shell script, and it successfully runs the file.
Thanks.
You should never use a "." (or any relative path) in a directory path in a script unless you really mean you want to refer to the directory that the user is running the script from. If you want to refer to a location relative to the script that's running, you can do the following:
import os
import sys
directory = os.path.dirname(os.path.abspath(__file__))
sys.stdout = open(os.path.join(directory, "demo-logfiles", "log_file_template.txt"), "a")
Best practices side note: you should probably use the logging module rather than reassigning sys.stdout.
The term "relative directories" means a path is relative to something. You probably assume it's relative to the script which contains the path but that's not correct.
Relative paths are relative to the current directory of the process which interprets the script, i.e. the folder in which you started python. If you're in the shell, you can see the current directory with echo $PWD
If you start python in /blah/blah, then that becomes the current directory and all relative paths are relative to /blah/blah.
See the answer of David Hollman for how to get the path of the current script and then how to build paths relative to that.
This question already has answers here:
Closed 12 years ago.
Duplicate:
In Python, how do I get the path and name of the file that is currently executing?
How do I get the path of a the Python script I am running in? I was doing dirname(sys.argv[0]), however on Mac I only get the filename - not the full path as I do on Windows.
No matter where my application is launched from, I want to open files that are relative to my script file(s).
Use this to get the path of the current file. It will resolve any symlinks in the path.
import os
file_path = os.path.realpath(__file__)
This works fine on my mac. It won't work from the Python interpreter (you need to be executing a Python file).
import os
print os.path.abspath(__file__)
7.2 of Dive Into Python: Finding the Path.
import sys, os
print('sys.argv[0] =', sys.argv[0])
pathname = os.path.dirname(sys.argv[0])
print('path =', pathname)
print('full path =', os.path.abspath(pathname))
The accepted solution for this will not work if you are planning to compile your scripts using py2exe. If you're planning to do so, this is the functional equivalent:
os.path.dirname(sys.argv[0])
Py2exe does not provide an __file__ variable. For reference: http://www.py2exe.org/index.cgi/Py2exeEnvironment
If you have even the relative pathname (in this case it appears to be ./) you can open files relative to your script file(s). I use Perl, but the same general solution can apply: I split the directory into an array of folders, then pop off the last element (the script), then push (or for you, append) on whatever I want, and then join them together again, and BAM! I have a working pathname that points to exactly where I expect it to point, relative or absolute.
Of course, there are better solutions, as posted. I just kind of like mine.