Subprocess doesn't open the correct directory - python

I'm running a script which prompts the user to select a directory, saves a plot to that directory and then uses subprocess to open that location:
root = Tkinter.Tk()
dirname = tkFileDialog.askdirectory(parent=root,initialdir="/",title='Please select a directory')
fig.savefig(dirname+'/XXXXXX.png',dpi=300)
plt.close("all")
root.withdraw()
subprocess.Popen('explorer dirname')
When I run the file I select a sub-directory in D:\Documents and the figure save is correct. However the subprocess simply opens D:\Documents as opposed to D:\Documents\XXX.
Ben

To open a directory with the default file explorer:
import webbrowser
webbrowser.open(dirname) #NOTE: no quotes around the name
It might use os.startfile(dirname) on Windows.
If you want to call explorer.exe explicitly:
import subprocess
subprocess.check_call(['explorer', dirname]) #NOTE: no quotes
dirname is a variable. 'dirname' is a string literal that has no relation to the dirname name.

You are only passing the string 'dirname' not the variable that you have named dirname in your code. Since you (presumably) don't have a directory called dirname on your system, explorer opens the default (Documents).
You may also have a problem with / vs \ in directory names. As shown in comments, use os.path module to convert to the required one.
You want something like
import os
win_dir = os.path.normpath(dirname)
subprocess.Popen('explorer "%s"' %win_dir)
or
import os
win_dir = os.path.normpath(dirname)
subprocess.Popen(['explorer', win_dir])

Add ,Shell=True after 'explorer dirname'
If Shell is not set to True, then the commands you want to implement must be in list form (so it would be ['explorer', ' dirname']. You can also use shlex which helps a lot if you don't want to make Shell = True and don't want to deal with lists.
Edit: Ah I miss read the question. often you need a direct path to the directory, so that may help.

Related

The python code needs to get the user's username to open a file on the C:/Users/USERNAME/ directory

I want to open a file in the desktop, or anywhere else in the C:/Users/USERNAME/ directory. but I don't know what the code to get the username is.
for example, in batch-file programming I could use:]
c:/Users/%USERNAME%/...
I want to use it in the open function. I have tried both:
open('C:/Users/%%USERNAME/Desktop/data3.txt')
open('C:/Users/%USERNAME%/Desktop/data3.txt')
I know there should be an import that can give the username to my code. But I don't know what it is. And I also would like to know if I can use the username like %USERNAME% or %%USERNAME or a single thing that doesn't need any import.
Three ways to do this using the os module:
Use os.getlogin():
import os
>>> os.path.join("C:", os.sep, "Users", os.getlogin(), "Desktop")
'C:\\Users\\your_username\\Desktop'
Use os.environ():
>>> os.path.join(os.environ['userprofile'], "Desktop")
'C:\\Users\\your_username\\Desktop'
Use os.path.exapndvars():
>>> os.path.join(os.path.expandvars("%userprofile%"), "Desktop")
'C:\\Users\\your_username\\Desktop'
you can use expanduser and ~ for that :
import os
open(os.path.expanduser('~\\Desktop\\data3.txt'))
or if you want to use os.path.join :
open(os.path.join(os.path.expanduser('~'), 'Desktop', 'data3.txt'))

Accessing networked file locations with pathlib

I'm trying to test a program using Python's pathlib module. With the os module, you used to be able to access networked drives by just following the same url-like form. But for some reason, you can't do this with pathlib. Or at least I can't figure out how to do it.
With the os module, all one would have to do is:
path = os.path.join(r'//server-01', 'directory', 'filename.txt')
But if you try to do this with the pathlib module, one could try something like:
path = Path('//server-01', 'directory', 'filename.txt')
If I'm on a Windows machine, path will resolve to:
>> WindowsPath('/server-01/directory/filename.txt)
And if I were to say path.exists() I will of course get False. Because yes, /server-01 does NOT exist, however //server-01 does exist.
Ideally of course, the result I expect to get when I run path.exists() is True and if I were to display path it would look something like:
>> WindowsPath('//server-01/directory/filename.txt')
Update
It's kind of hacky, but it works I guess, regardless I'd like to know the right way to do it.
In order to get to the network location you can:
os.chdir(join(r'//server-01', 'directory', 'filename.txt'))
path = Path()
path = path.resolve()
The result is something like:
>> WindowsPath('//server-01/directory/filename.txt')
path.exists()
>> True
If anyone knows the better way to do it, let me know.
If you create your path as:
path = Path('//server-01/directory/filename.txt')
instead of comma separating each directory it will work.
The server name by itself is not a valid component of a UNC path. You must also include a share. So path = Path('//server-01/directory', 'file') will work. It should resolve and return True when you run path.exists().
Microsoft docs here: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dfsc/149a3039-98ce-491a-9268-2f5ddef08192
after several attempts, I think you can visit the smb folder/file with pathlib by:
folder = pathlib.Path('//server/')
file = pathlib.Path('//server/') / 'relative/path/to/file'
# or
file = pathlib.Path('//server/relative/path/to/file')
the key is that if you want to visit a smb folder, the arg should end with '/'.
Instantiating path as a PureWindowsPath should do the trick:
path = PureWindowsPath("//server-01", "directory", "file") # '\\\\server-01\\directory\\file'

File not found from Python although file exists

I'm trying to load a simple text file with an array of numbers into Python. A MWE is
import numpy as np
BASE_FOLDER = 'C:\\path\\'
BASE_NAME = 'DATA.txt'
fname = BASE_FOLDER + BASE_NAME
data = np.loadtxt(fname)
However, this gives an error while running:
OSError: C:\path\DATA.txt not found.
I'm using VSCode, so in the debug window the link to the path is clickable. And, of course, if I click it the file opens normally, so this tells me that the path is correct.
Also, if I do print(fname), VSCode also gives me a valid path.
Is there anything I'm missing?
EDIT
As per your (very helpful for future reference) comments, I've changed my code using the os module and raw strings:
BASE_FOLDER = r'C:\path_to_folder'
BASE_NAME = r'filename_DATA.txt'
fname = os.path.join(BASE_FOLDER, BASE_NAME)
Still results in error.
Second EDIT
I've tried again with another file. Very basic path and filename
BASE_FOLDER = r'Z:\Data\Enzo\Waste_Code'
BASE_NAME = r'run3b.txt'
And again, I get the same error.
If I try an alternative approach,
os.chdir(BASE_FOLDER)
a = os.listdir()
then select the right file,
fname = a[1]
I still get the error when trying to import it. Even though I'm retrieving it directly from listdir.
>> os.path.isfile(a[1])
False
Using the module os you can check the existence of the file within python by running
import os
os.path.isfile(fname)
If it returns False, that means that your file doesn't exist in the specified fname. If it returns True, it should be read by np.loadtxt().
Extra: good practice working with files and paths
When working with files it is advisable to use the amazing functionality built in the Base Library, specifically the module os. Where os.path.join() will take care of the joins no matter the operating system you are using.
fname = os.path.join(BASE_FOLDER, BASE_NAME)
In addition it is advisable to use raw strings by adding an r to the beginning of the string. This will be less tedious when writing paths, as it allows you to copy-paste from the navigation bar. It will be something like BASE_FOLDER = r'C:\path'. Note that you don't need to add the latest '\' as os.path.join takes care of it.
You may not have the full permission to read the downloaded file. Use
sudo chmod -R a+rwx file_name.txt
in the command prompt to give yourself permission to read if you are using Ubuntu.
For me the problem was that I was using the Linux home symbol in the link (~/path/file). Replacing it with the absolute path /home/user/etc_path/file worked like charm.

How to set current working directory in python in a automatic way

How can I set the current path of my python file "myproject.py" to the file itself?
I do not want something like this:
path = "the path of myproject.py"
In mathematica I can set:
SetDirectory[NotebookDirectory[]]
The advantage with the code in Mathematica is that if I change the path of my Mathematica file, for example if I give it to someone else or I put it in another folder, I do not need to do anything extra. Each time Mathematica automatically set the directory to the current folder.
I want something similar to this in Python.
The right solution is not to change the current working directory, but to get the full path to the directory containing your script or module then use os.path.join to build your files path:
import os
ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
# then:
myfile_path = os.path.join(ROOT_PATH, "myfile.txt")
This is safer than messing with current working directory (hint : what would happen if another module changes the current working directory after you did but before you access your files ?)
I want to set the directory in which the python file is, as working directory
There are two step:
Find out path to the python file
Set its parent directory as the working directory
The 2nd is simple:
import os
os.chdir(module_dir) # set working directory
The 1st might be complex if you want to support a general case (python file that is run as a script directly, python file that is imported in another module, python file that is symlinked, etc). Here's one possible solution:
import inspect
import os
module_path = inspect.getfile(inspect.currentframe())
module_dir = os.path.realpath(os.path.dirname(module_path))
Use the os.getcwd() function from the built in os module also there's os.getcwdu() which returns a unicode object of the current working directory
Example usage:
import os
path = os.getcwd()
print path
#C:\Users\KDawG\Desktop\Python

Save a file depending on the user Python

I try to write a script in Python that saves the file in each user directory.
Example for user 1, 2 and 3.
C:\Users\user1\Documents\ArcGIS\file1.gdb
C:\Users\user2\Documents\ArcGIS\file1.gdb
C:\Users\user3\Documents\ArcGIS\file1.gdb
How can I do this?
As one commenter pointed out, the simplest solution is to use the USERPROFILE environment variable to write the file path. This would look something like:
import os
userprofile = os.environ['USERPROFILE']
path = os.path.join(userprofile, 'Documents', 'ArcGIS', 'file1.gdb')
Or even more simply (with better platform-independence, as this will work on Mac OSX/Linux, too; credit to Abhijit's answer below):
import os
path = os.path.join(os.path.expanduser('~'), 'Documents', 'ArcGIS', 'file1.gdb')
Both of the above may have some portability issues across Windows versions, since Microsoft has been known to change the name of the "Documents" folder back and forth from "My Documents".
If you want a Windows-portable way to get the "Documents" folder, see the code here: https://stackoverflow.com/questions/3858851#3859336
In Python you can use os.path.expanduser to get the User's home directory.
>>> import os
>>> os.path.expanduser("~")
This is a platform independent way of determining the user's home directory.
You can then concatenate the result to create your final path
os.path.join(os.path.expanduser("~"), 'Documents', 'ArcGIS', 'file1.gdb')
You want to use the evironment variable HOME, something like this:
import os
homeDir = os.environ["HOMEPATH"]
file = open(homeDir+"Documents\ArcGIS\file1.gdb")
file.write("Hello, World")
file.close()
Notice that I've used HOMEPATH considering you're using Windows, it may be wrong depending on your OS. Take a look at this: http://en.wikipedia.org/wiki/Environment_variable

Categories