I am writing a Python script that has to execute a shell script. In my GIT repo I have plans to commit both (Python program + Shell script) in same directory in my repo.
My issue is that when someone pulls out my code and wants to run my Python script from any relative / absolute location - I need to refer the shell script in the directory where my Python script resided.
I am not sure which one I should make use of
os.path.dirname(os.path.realpath(__file__))
OR
os.path.abspath(os.path.dirname(__file__))
OR
os.path.dirname(os.path.abspath(__file__))
If I run my python script in same directory it prints same values - even if I execute from a separate directory and run my script as mentioned below I still get same values:
python ./test/test1/1.py
/x/home02/myhome/test/test1
If it so which one I should actually make use of? What is the difference in between each of them?
========== Updated =========
I created a symbolic link to my code like as mentioned below:
cd
ln -s /x/home02/myhome/test/test1/1.py 2.py
Now when I re-run my code as mentioned below -
cd
python 2.py
cd test
python ../2.py
I get the below output
/x/home02/myhome/test/test1
/x/home02/myhome
/x/home02/myhome
So I think the below one is the correct one as I am always getting the expected output:
os.path.dirname(os.path.realpath(__file__))
Well first you want the directory, so let's use os.path.dirname(...)
And os.path.abspath(__file__) should get you the path of the script, the difference between this and os.path.realpath() is the latter eliminates symbolic links, so not sure if you want that
So I'd use os.path.dirname(os.path.abspath(__file__))
The difference between os.path.realpath and os.path.abspath is the former eliminates symbolic links whereas the latter be the absolute path of a symbolic link.
In this case, the order of os.path.dirname and abspath or realpath shouldn't matter -- It would only matter if the file you passed in didn't have a directory portion.
You should use absolute path with directory name of pathname, like this:
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
Find the common pathname manipulations (os.path) documentation to find the difference between the usage here: https://docs.python.org/3/library/os.path.html
Related
I've seen the following code in a couple Python projects, in __main__.py. Could someone explain the purpose? Of course it puts the directory containing __main__.py at the head of sys.path, but why? And why the tests (__package__ is None and not hasattr(sys, 'frozen')? Also, in the sys.path.insert, why is os.path.dirname called twice?
import sys
if __package__ is None and not hasattr(sys, 'frozen'):
# direct call of __main__.py
import os.path
path = os.path.realpath(os.path.abspath(__file__))
sys.path.insert(0, os.path.dirname(os.path.dirname(path)))
os.path.dirname(os.path.dirname(path)) - Gets the grand-parent directory (the directory containing the directory of the given path variable); this is being added to the system's PATH variable.
os.path.realpath(os.path.abspath(__file__)) - Gets the realpath (resolves symbolic linking) of the absolute path of the running file.
Through this method, the project can now execute binary files that are included in that grandparent directory without needing to prefix the binary executable.
Sidenote: Without context of where you see this code, it's hard to give more of an answer as to why its used.
The test for __package__ lets the code run when package/__main__.py has been run with a command like python __main__.py or python package/ (naming the file directly or naming the package folder's path), not the more normal way of running the main module of a package python -m package. The other check (for sys.frozen) tests if the package has been packed up with something like py2exe into a single file, rather than being in a normal file system.
What the code does is put the parent folder of the package into sys.path. That is, if __main__.py is located at /some/path/to/package/__main__.py, the code will put /some/path/to in sys.path. Each call to dirname strips off one item off the right side of the path ("/some/path/to/package/__main__.py" => "/some/path/to/package" => "/some/path/to").
A script at /foo/bar.py tries to run a second script /main.py using the subprocess module. Although main.py runs fine with python main.py in the Windows command prompt, running bar.py which calls main.py causes an error
ConfigParser.NoSectionError: No section: 'user'
Why is there now a problem with the path to settings.ini, and how can we fix it?
~/settings.ini
[user]
id: helloworld
~/foo/bar.py
subprocess.Popen([sys.executable, "../main.py"])
~/main.py
Config = ConfigParser.ConfigParser()
Config.read("settings.ini")
userId = Config.get('user', 'id')
If settings.ini is presumed to be in the same directory as main.py you can deduce its full path from __file__ and read the settings using the full path.
main.py:
import os
ini_path = os.path.join(os.path.dirname(__file__), "settings.ini")
Config = ConfigParser.ConfigParser()
Config.read(ini_path)
Check that the read() method returns a non-empty list otherwise it means that settings.ini is not found. Relative paths are resolved relative to the current working directory (place where you've run python), not script's directory (where bar.py is stored).
You should probably use appdirs.user_config_dir(), to get the directory where to put user's configuration files. Different OSes such as Windows, macOS, Linux distributions may use different defaults. appdirs follows conventions that are appropriate for a given OS.
If you want to get data stored in a file that is packaged with your installed Python modules then you could use pkgutil.get_data() or setuptools' pkg_resources.resource_string() that work even if your package is inside an archive. It is not recommended to construct the paths manually but if you need the directory with the current script then you could put get_script_dir() function into your script—it is more general than os.path.dirname(os.path.abspath(__file__)). If the relative position is always the same then you could use:
#!/usr/bin/env python
import os
import subprocess
import sys
main_script_dir = os.path.join(get_script_dir(), os.pardir)
subprocess.check_call([sys.executable, '-m', 'main'], cwd=main_script_dir)
See Python : How to access file from different directory
I have following simple script test.py in directory /Users/apps:-
import os
os.chdir("/Users/apps/update/diiferent_path")
path = os.path.dirname(os.path.abspath(__file__))
print(path)
I am getting path value as /Users/apps/update/diiferent_path because I have changed the directory. How can I get test.py path i.e. /Users/apps after changing directory.
It's impossible to do it after the chdir (unless, of course, if __file__ already contains the absolute path), because the information is lost. There is no such thing as what was the current directory when the process started stored anywhere automatically. But you can store it manually by calling os.path.abspath(__file__) before calling the chdir.
I agree with pts post that storing the path is the way to go. It best shows your intention of getting the original path, despite what modifications are done throughout the script.
For reference sake two workarounds. The path changes because the script is executed by name. The interpreter then finds the file in the current directory. The current directory changes, and thus the absolute path of both __file__ and sys.argv.
One way around that is to call the script with an absolute path. Another is to realize that the path of the script is automatically added to the PYTHONPATH, i.e. to sys.path. The following script illustrates that:
#!/usr/bin/python
import os
import sys
os.chdir("/usr/bin")
print(os.path.abspath(__file__))
print(os.path.abspath(sys.argv[0]))
print(sys.path[0])
The output:
# /tmp$ ./so24323731.py
/usr/bin/so24323731.py
/usr/bin/so24323731.py
/tmp
# /tmp$ /tmp/so24323731.py
/tmp/so24323731.py
/tmp/so24323731.py
/tmp
If we can directly access and manipulate files in other directories (for example, using the Python code below), when would we need to change our current working directory? What is the advantage of changing the current directory?
import os
print(os.getcwd())
f=open(os.path.join(os.getcwd(),"test_folder")+"\\testfile","w")
f.close()
print(os.getcwd())
os.makedirs("test_folder_2")
print(os.getcwd())
Output:
c:\Users\me
c:\Users\me
c:\Users\me
In the example you're not changing the working directory. You're just getting (printing) it. You do not need to change the working directory. But it's just like you are navigating your files from explorer, to keep your files organised. Sometimes it's done for the file permissions.
The current working directory is the base directory for relative paths. It is the place where you start looking for files and folders, if you don't supply an absolute path. Execute the following script from 2 different directories and examine the difference.
# a.py
import os
print "\tcwd:", os.getcwd()
print "\tpth:", os.path.abspath("a")
Now from a dos box, you get the following output:
C:\Users\user> python a.py
cwd: C:\Users\user
pth: C:\Users\user\a
C:\Users\user> cd ..
C:\Users> python user\a.py
cwd: C:\Users
pth: C:\Users\a
From a different working directory, you target different files with relative paths. It is generally a good idea to use relative paths, because otherwise a script may only work for a single user, or the installation directory of a program must be the same on all computers, which is usually not the case. You must change the working directory to target files and directories correctly with relative paths.
I am attempting to make a Python testing script module self-contained directory-wise for scalability and maintainability purposes.
I have done some research and haven't been able to find the answer i'm looking for. Basically, I would like to determine if there is a function in Python that can do something similar to cd - in shell.
I would generally like to avoid typing in full path-names, and have all the paths relative to a specified environment.
Example:
I have my main directory where my scripts are located python-scripts, I have folders for each testing environment demo, and a screenshot folder for each testing environment demo-screenshots.
If i wanted to save a screenshot to the screenshot with Python, while working in the demo directory, I would just send it to the directory below: demo-screenshots, using the path '/demo-screenshots/example.png'. The problem is that I don't understand how to move back a directory.
Thank you.
You're looking to change the working directory? The OS module in python has a lot of functions to help with this.
import os
os.chdir( path )
path being ".." to go up one directory. If you need to check where you are before/after a change of directory you can issue the getcwd() command:
mycwd = os.getcwd()
os.chdir("..")
#do stuff in parent directory
os.chdir(mycwd) # go back where you came from
path = os.path.dirname(__file__)
print(path)
will print the CWD of the file, say C:\Users\Test\Documents\CodeRevamp\Joke
path2 = os.path.dirname(path)
print(path2)
will print the Parent directory of of the file: C:\Users\Test\Documents\CodeRevamp