Determine if subdirectory is on a mounted file system with Python - python

In this path, the directory 'foo' is mounted on an external file system. The directory 'bar' is a subdirectory of 'foo'.
'/Volumes/foo/bar'
Using os.path.ismount('/Volumes/foo'), I can determine correctly that 'foo' is indeed an external mount. However, using os.path.ismount('/Volumes/foo/bar') on 'bar' determines correctly that it is NOT mounted externally.
So, my question is, how can I correctly determine that 'bar' is a subdirectory of an externally mounted file system? I need to be able to determine the same about many directories of varying depth. Any clues would be great!

From the documentation:
Return True if pathname path is a mount point
emphasis mine. A subdirectory of a mount pointed directory is on a mount drive, but not a mount "point".
how can I correctly determine that 'bar' is a subdirectory of an externally mounted file system?
In this case, I would iterate through the parent hierarchy until I reach the root, or I hit a mount-point. Whichever comes first.
Assuming a Unix type filesystem:
def is_on_mount(path):
while True:
if path == os.path.dirname(path):
# we've hit the root dir
return False
elif os.path.ismount(path):
return True
path = os.path.dirname(path)
path = '/mount/one/two/three'
is_on_mount(path)

import os
import subprocess
def is_on_mounted_volume(path):
try:
df = subprocess.check_output(['df', path]).split('\n')
mountpoint = df[1].split()[-1][0]
return os.path.ismount(mountpoint)
except subprocess.CalledProcessError:
pass

Related

if user input is not a directory, how can I make the directory a default value

Let us say a user input is an invalid directory. if so how can I make a script automatically set a default directory to a local file or the desktop?
You have to use the os library and check if a directory exists:
isFile = os.path.isdir(path)
if isFile is false then set it to whatever default directory you want. If you want it to be set to Desktop, then use:
os.environ['USERPROFILE'] + '\Desktop'
docs: https://docs.python.org/3/library/os.html#os.environ
You can use
os.path.exists(path)
to see if it exists. If it does not, you can set set another path.
If you want to change directory, you can use
os.chdir(path)

Read file in Django Management Command

I'm trying to read credentials for the Google Sheets API using gspread. I wrote the following code:
class Command(BaseCommand):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def handle(self, *args, **kwargs):
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name('/static/json/spreadsheets.json', scope)
gc = gspread.authorize(credentials)
wks = gc.open("Where is the money Lebowski?").sheet1
self.stdout.write(self.style.SUCCESS('Succesfully ran "sheets" command'))
Reading the file returns the following error:
FileNotFoundError: [Errno 2] No such file or directory: 'static/json/spreadsheets.json'
I tried multiple paths like:
'~/static/json/spreadsheets.json'
'/json/spreadsheets.json'
'spreadsheets.json'
But none seem to work. Could anybody help me out here?
When you use an absolute path, it is taken literally i.e. from starting from the root of the filesystem i.e. /.
When you use a relative path i.e. without / at start, it is resolved from the directory where script is invoked from, not where the script actually lies in the filesystem.
So when you invoke the Django management command via e.g. ./manage.py <command>, it looks for a path starting from the current directory of manage.py i.e. os.path.dirname('manage.py'). If you give the path as static/json/spreadsheets.json, the full path it looks for is:
os.path.join(
os.path.abspath(os.path.dirname('manage.py')),
'/static/json/spreadsheets.json'
)
So you need to make sure you have the spreadsheets.json file in the right directory. A better approach would be to use an absolute path for these kind of scenarios. If you're on GNU/Linux, you can use:
readlink -f static/json/spreadsheets.json
to get the absolute path.
Also, rather than hardcoding the file, you should take the file as an argument to the management command. Django management command uses argparse for argument parsing, so you can take a peek at the doc.
First of all: ~ symbol should not work in this case, because it's just a glob which is being expanded to full path by *nix shell, so in this case it can't be expanded as shell is not involved here.
Leading / symbol will move you to the root directory.
I don't know all situation (because you didn't provided info about in which directory you run this command and where the file is located in comparison to that directory.
But you can use method getcwd from os library like this:
import os
print(os.getcwd())
Or from debugger, to get know your current location. Then you can pass absolute path to file or use ".." to get to parent directory if needed or even change current working directory using os.chdir() method, but it's not recommended to do because it can have some side-effects on Django or other libraries used in project which doesn't expect that directory could be changed in runtime.

Find C:\Programs path (not scripts path)

I've made a game and I'd like to save the highscore. So I need a place to do that. I chose to put it in the C:\All Programs directory. My problem is that that directory name isn't the same on every computer. For example on mine it's C:/Program Files (x86).
So my question:
Is there a way, to discover that path on any computer?
PROBLEM SOLVED:
os.getenv('PROGRAMFILES')
I second #iCodez's answer to use os.getenvto get the path string from a system environment variable, but you might want to use the paths defined for APPDATA or LOCALAPPDATA instead.
Windows permissions settings on the Program Files directory may prevent a standard user account from writing data to the directory.
I believe the APPDATA and LOCALAPPDATA paths were designed for just such a use. On my system, APPDATA = C:\Users\myname\AppData\Roaming and LOCALAPPDATA = C:\Users\myname\AppData\Local. My user account has full read/write permission for both directories.
You could use os.getenv or os.environ:
>>> import os
>>>> os.getenv('PROGRAMFILES')
'C:\\Program Files'
>>> os.environ['PROGRAMFILES']
'C:\\Program Files'
>>>
Note that you can also specify a default return value for when an environment variable is not set:
>>> os.getenv('BADVAR', 'default')
'default'
>>> os.environ.get('BADVAR', 'default')
'default'
>>>

traverse upward on a directory structure until it gets to the file system top level

I have already created a script which sets "FLAG" after backup on uppermost level of each directory.
now I need a script that could be run "in any directory" and that would tell me "when the last successful backup ran" by reading the last modification time of the "FLAG".
Of course I can also manually find out on what file system my current directory is located and then go up in the directory hierarchy until I get to the file system's top level directory and find the flag file there but that is not very convenient. The command that I would like to write would do the same thing, but automatically.
1) I do not know how to do the part where it traverses upward on a directory structure until it gets to the file system top level.
2) reading the Flag time might work sth like this:
import time
fileTileInSeconds = os.path.getmtime("FLAG") (not sure)
ModDate = time.localtime(fileTileInSeconds)
print ModDate.tm_year,ModDate.tm_mon,ModDate.tm_mday,ModDate.tm_hour,ModDate.tm_min,ModDate.tm_sec
quit()
Any idea/suggestion would be appreciated.
Use os.path.parent to go up the directory tree, and use os.stat to see which device each directory is on. When the device changes, you have crossed the boundary of the filesystem. Like this:
#!/usr/bin/python
import os
import stat
import sys
def find_mount(path):
path = os.path.realpath(path)
s = os.stat(path)[stat.ST_DEV]
ps = s
while path != '/' and ps == s:
parent = os.path.dirname(path)
ps = os.stat(parent)[stat.ST_DEV]
if ps == s:
path = parent
return path
if __name__ == "__main__":
for path in sys.argv[1:]:
print find_mount(path)

py2exe and the file system

I have a Python app. It loads config files (and various other files) by
doing stuff such as:
_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CONFIG_DIR = os.path.join(_path, 'conf')
This works fine. However, when I package the app with py2exe, bad things happen:
File "proj\config.pyc", line 8, in <module>
WindowsError: [Error 3] The system cannot find the path specified: 'C:\\proj\
\dist\\library.zip\\conf'
Obviously that's an invalid path... What's a more robust way of doing this? I don't
want to specify absolute paths in the program because it could be placed in different
folders. Should I just say "if it says the folder name is 'library.zip', then go
one more level down to the 'dist' folder"?
Note that I have pretty nested directory hierarchies... for example, I have
a module gui.utils.images, stored in "gui/utils/images.py", and it uses its path
to access "gui/images/ok.png", for example. Right now the py2exe version
would try to access "proj/dist/library.zip/gui/images/ok.png", or something,
which just won't work.
The usual approach to doing this sort of thing (if I understand properly) is this:
check sys.frozen, which py2exe contrives to set, using something like getattr(sys, 'frozen', '')
if that's not set, use the usual method since you're running from source
if it's set, check sys.executable since that will point you to where the .exe is (instead of to where python.exe is, which is what it normally points to). Use something like os.path.dirname(sys.executable) and then join that with your relative paths to find subfolders etc
Example:
frozen = getattr(sys, 'frozen', '')
if not frozen:
# not frozen: in regular python interpreter
approot = os.path.dirname(__file__)
elif frozen in ('dll', 'console_exe', 'windows_exe'):
# py2exe:
approot = os.path.dirname(sys.executable)
elif frozen in ('macosx_app',):
# py2app:
# Notes on how to find stuff on MAC, by an expert (Bob Ippolito):
# http://mail.python.org/pipermail/pythonmac-sig/2004-November/012121.html
approot = os.environ['RESOURCEPATH']
Or some variant thereof... the latter one handles the use of py2app. You could extend this for other builders, if needed.
What do you think about using relative paths for all of the included files? I guess it should be possible to use sys.path.append(".." + os.path.sep + "images") for your example about ok.png, then you could just open("ok.png", "rb"). Using relative paths should fix the issues with the library.zip file that's generated by py2exe, at least that's what it does for me.
Use os.path.dirname(os.path.abspath(sys.argv[0])) from a py2exe app, it'll work the same way from the python script (so you can test without creating the exe every time) and from the exe.
This can be much better than using relative paths because you don't have to worry about where your app (.py or .exe) is running from.
Here's my solution (tested on Windows, Linux and Mac). It also works if the application or Python script is started via a symbolic link.
# Get if frozen
is_frozen = bool( getattr(sys, 'frozen', None) )
# Get path variable
path = sys.path if is_frozen else sys.argv
# Get nonempty first element or raise error
if path and path[0]:
apppath = path[0]
elif is_frozen():
raise RuntimeError('Cannot determine app path because sys.path[0] is empty.')
else:
raise RuntimeError('Cannot determine app path in interpreter mode.')
# Make absolute (eliminate symbolic links)
apppath = os.path.abspath( os.path.realpath(apppath) )
# Split and return
appdir, appname = os.path.split(apppath)
I use the following trick in windows.
When the program is frozen in a py2exe 'executable' (i.e my_application.exe), dirname(__file__) returns the folder where your main python script is running.
Oddly enough, that folder is not the folder containing my_application.exe but my_application.exe itself.
Note that my_application.exe is not a binary file but a compressed folder (you can unzip it) that contains python libs and your compiled scripts.
That's why the os.path.dirname of your __file__ is in fact my_application.exe.
Thus, this code gives you the root directory for your configuration files or images (in case of a frozen application, the folder containing the py2exe executable, otherwise the folder from where your python script is running):
dirname = os.path.dirname(__file__)
if dirname.endswith('.exe'):
dirname = os.path.split(dirname)[0]
Obviously you can use more general, portable methods to detect if the file is frozen as other answers show instead of the endswith method.

Categories