How to set directory in python script - python

When I run my python script via the terminal by going into the directory the python script is held and running > python toolstation.py, the script runs successfully.
Then what I try to do is run the script via a .bat file. My .bat file is set as so:
"C:\Users\xxxx\AppData\Local\Programs\Python\Python39\python.exe" "C:\Users\xxxx\Downloads\axp_solutions\python_scripts\toolstation.py"
When I run this bat file, it gives me an exception which states it cannot find the directory to open the csv file, which is one directory above the python script.
Exception:
Traceback (most recent call last):
File "C:\Users\xxx\Downloads\axp_solutions\python_scripts\toolstation.py", line 12, in <module>
f = open('../input/toolstation.csv', 'r')
FileNotFoundError: [Errno 2] No such file or directory: '../input/toolstation.csv'
The code for this in the python script is set like so:
f = open('../input/toolstation.csv', 'r')
Now I can set this via a hardcoded path like so to get around it:
f = open('C:/Users/xxxx/Downloads/axp_solutions/input/toolstation.csv', 'r')
But as I am sending this script and bat file to a friend, they will have a different path set. So my question is, how should the dynamic path be set so that it is able to recognise the directory to go to?

Instead of constructing the path to the CSV file (based on this answer), I would suggest using Python's argparse library to add an optional argument which takes the path to that CSV file.
You could give it a reasonable default value (or even use the automatically determined relative path as the default), so that you don't have to specify anything if you are on your system, while at the same time adding a lot of flexibility to your script.
You and everyone using your script, can at any moment decide which CSV file to use, while the overhead is manageable.
Here's what I would start with:
import argparse
import os
DEFAULT_PATH = r'C:\path\that\makes\sense\here\toolstation.csv'
# Alternatively, automatically determine default path:
# DEFAULT_PATH = os.path.join(
# os.path.dirname(os.path.abspath(__file__)),
# r'..\input\toolstation.csv',
# )
parser = argparse.ArgumentParser(prog='toolstation')
parser.add_argument(
'-i',
'--input-file',
default=DEFAULT_PATH,
help='Path to input CSV file for this script (default: %(default)s).'
)
args = parser.parse_args()
try:
in_file = open(args.input_file, 'r')
except FileNotFoundError:
raise SystemExit(
f"Input file '{args.input_file}' not found. "
"Please provide a valid input file and retry. "
"Exiting..."
)
Your script gets a nice and extensible interface with out-of-the-box help (you can just run python toolstation.py --help).
People using your script will love you because you provided them with the option to choose their input file via:
python toolstation.py --input-file <some_path>
The input file path passed to the script can be absolute or relative to the directory the script is executed from.

Use os module to get the script path and then add the path to the src file.
Ex:
import os
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'input', 'toolstation.csv')
with open(path, 'r') as infile:
...

You can pass the path to that CSV in as an argument to the python script.
This tutorial may be helpful.
The batch file:
set CSV_PATH="C:\...\toolstation.csv"
"C:\...\python.exe" "C:\...\toolstation.py" %CSV_PATH%
You'll have to fill in the "..."s with the appropriate paths; this isn't magic.
The Python script:
import sys
toolstation_csv = sys.argv[1]
...
f = open(toolstation_csv, 'r')
...

Related

How to take full windows file path as user input and work with the file

I am trying to write a program in python that will take a windows file path (uses backslashes not forward slashes) and converts the file to another file type. I think some combination of input() and windows using backslashes is what is causing errors.
For example, the user would input something like
C:\Users\user\Downloads\file.tdms
I want to tell the user to copy the file path from their file explorer and paste it into the program. I cannot alter what the user inputs, it has to be in the above form.
Here is my code thus far:
from nptdms import TdmsFile
from pathlib import Path, PurePosixPath
path = Path(input('enter file path: '))
path1 = PurePosixPath(path)
print(path1)
with open(path1, mode='r') as f:
tdms_file = TdmsFile.read(f)
tdms_file.to_csv(path + '.csv')
Here is the error I get:
(base) H:\Private\ahirani\python TDMS to CSV>testing.py
enter file path: "C:/Users/user/Downloads/file.tdms"
"C:/Users/user/Downloads/file.tdms"
Traceback (most recent call last):
File "H:\Private\ahirani\python TDMS to CSV\testing.py", line 11, in <module>
with open(path, mode='r') as f:
OSError: [Errno 22] Invalid argument: '"C:/Users/user/Downloads/file.tdms"'
It looks like you are using PurePosixPath although your question is specifically about Windows. I would try using WindowsPath and the specific open method on the Path object as listed in the official documentation. Additionally it looks like you have an extra set of double quotes around your input
from nptdms import TdmsFile
from pathlib import WindowsPath
input_path = input('enter file path: ')
path = WindowsPath(input_path.replace('"', ''))
with path.open() as f:
tdms_file = TdmsFile.read(f)
tdms_file.to_csv(path + '.csv')
I don't have immediate access to a Windows Machine to test this but it should work. Also good way to test what your issues are would be to search for your error and try hardcoding it as a debugging step. i.e. take a look at this SO thread

Python split and subsequent join on os.sep does not yield properly joint string

python 3.8 on Windows 10
I'm trying to create a script to automatically create a .bat file to activate the correct environment or the current script. For this I need to do some path manipulation, which includes in essence the following code:
import os
cwd = os.getcwd()
s = cwd.split(os.sep)
n = os.path.join(*s,'test.bat')
print(n)
Expected outcome:
C:\\Data\\test.bat
Actual outcome:
C:Data\\test.bat
This is missing the \ separator after the drive.
Also with deeper folder structures, this goes wrong only in joining the drive. What is going wrong here?
Full code:
import os
python_file = 'python_file_name.py' # file to run
program_name = 'Start Python Program' # Name of the resulting BAT file
cwd = os.getcwd() # directory in which the Python file lives
env = os.environ['CONDA_PREFIX'] # environment name in Conda
act = os.environ['CONDA_EXE'].split(os.sep)[:-1] # activate.bat lives in the same directory as conda.exe
act = os.path.join(*act,'activate.bat')
# Construct the commands
text = f'''ECHO ON
CD {cwd}
CALL {act} {env}
CALL {python_file}
'''
with open(f'{program_name}.bat', 'w') as f:
f.write(text)
Strangely enough this seems to be a feature, not a bug...
https://docs.python.org/3/library/os.path.html

Reading a file from directory

I am trying to read a file in the directory ./resources/input_file.utf8.
However, when I compile the following code from the terminal with the command:
python namefile.py input
this error appears:
[Errno 2] No such file or directory: 'input'
This is my code:
from argparse import ArgumentParser
def parse_args():
parser = ArgumentParser()
parser.add_argument("input_path", help="./resources/input_file.utf8")
return parser.parse_args()
def foo(input_path):
file_input = open(input_path, "r", encoding='utf-8-sig')
for line in file_input:
[...]
if __name__ == '__main__':
args = parse_args()
predict(args.input_path)
One of the specification I have to respect is to not to put hard paths directly in the foo function, but only in the parser.add_argument() function.
How can I fix it?
If you are running the command python namefile.py input, make sure that:
1) Files - You have both your input file and the python script in the same folder.
2) Location - The working directory in you terminal is the one that contains the files (use pwd to check).
3) File name - Your filename is exactly input and not input.txt or input.utf8.
If your file is in the path that you have provided in your example, then you would need to call the script with that path.
Example:
python namefile.py "./resources/input_file.utf8"

Error when creating directory and then opening a file within it in Python, but no error if directory already exists

I expect a directory to be created and then a file to be opened within it for writing to when I execute my code below in Python 2.6.6,
import subprocess
def create_output_dir(work_dir):
output_dir = '/work/m/maxwell9/some_name5/'
subprocess.Popen(['mkdir', output_dir])
return output_dir
if __name__ == '__main__':
work_dir = '/work/m/maxwell9/'
output_dir = create_output_dir(work_dir)
#output_dir = '/work/m/maxwell9/some_name5/'
filename = output_dir + 'bt.sh'
with open(filename, 'w') as script:
print('there')
but instead I get the error,
Traceback (most recent call last):
File "slurm_test.py", line 13, in <module>
with open(filename, 'w') as script:
IOError: [Errno 2] No such file or directory: '/work/m/maxwell9/some_name5/bt.sh'
If I run the script, I can then see that the directory is created. If I then uncomment the line,
#output_dir = '/work/m/maxwell9/some_name5/'
and comment the line,
output_dir = create_output_dir(work_dir)
then the file is output fine. So there is something about creating the folder and then writing to it in the same script that is causing an error.
subprocess.Popen starts up an external process but doesn't wait for it to complete unless you tell it to (e.g. by calling .wait on the returned Popen instance). Most likely, mkdir is in the process of creating a directory while open(filename, 'w') attempts to create a file in that directory. This is an example of a "race condition".
The solution is to .wait on the open process (as noted above), or you can use one of the convenience wrappers subprocess.check_output, subprocess.check_call or (even better), you can avoid subprocess entirely by using os.mkdir or os.makedirs.
You could use the os library instead of subprocess, which makes for a more straightforward implementation. Try swapping out your create_output_dir function with this:
import os
def create_output_dir(work_dir):
try:
os.makedirs(work_dir)
except OSError:
pass
return work_dir

Opening a file in pwdir's folder in Python through Applescript

Opening a file available in present working directory's temp folder in python
I tried
pwdir=os.getcwd()
tempdir=pwdir+"/temp/test.txt"
f=open(tempdir,'r+')
When I print the path of tempdir, it is showing up correctly and also the contents of file are also read.
When I try to combine this operation from an Applescript, which calls this python script. I get an error like this
f=open(pwdir1,'r+')
IOError: [Errno 2] No such file or directory: '//temp/test.txt'" number 1
EDIT:
I am using Shell script from Applescript to call this pythonscript
do shell script "/Users/mymac/Documents/'Microsoft User Data'/test.py"
EDIT:
Python Code:
tempdir = os.path.join(os.getcwd(),'temp','htmlinput.html')
print tempdir
with open(tempdir) as f:
html=f.read()
Python output from terminal:(works perfectly fine)
/Users/mymac/Documents/Microsoft User Data/Outlook Script Menu Items/temp/htmlinput.html
I am also able to see the file contents.
Applescript Code:
do shell script "/Users/mymac/Documents/'Microsoft User Data'/'Outlook Script Menu Items'/new.py"
Applescript Error:
error "Microsoft Outlook got an error: Traceback (most recent call last):
File \"/Users/mymac/Documents/Microsoft User Data/Outlook Script Menu Items/new.py\", line 12, in <module>
with open(tempdir) as f:
IOError: [Errno 2] No such file or directory: '/temp/htmlinput.html'" number 1
I don't know Applescript -- or OS X in general. It looks like the script is being run from the root folder, and os.getcwd() returns '/'. The directory of the script itself is sys.path[0] or the dirname of the current module -- dirname(__file__) -- if it's a single script instead of a package. Try one of the following
import os, sys
tempdir = os.path.join(sys.path[0], 'temp', 'temp.txt')
or
import os
tempdir = os.path.join(os.path.dirname(__file__), 'temp', 'temp.txt')
The double slash is your problem. The right way to join file and path names in Python is with os.path.join. Try:
tempdir = os.path.join(os.getcwd(), 'temp', 'test.txt')
Also, you should probably be doing:
with open(tempdir) as f:
which will make sure tempdir gets closed even if you have an error.
Edit:
We need to see what tempdir is when the script is invoked by the AppleScript, not when it is invoked from the terminal. If you do
tempdir = os.path.join(os.getcwd(),'temp','htmlinput.html')
with open('/Users/mymac/Documents/temp.txt', 'w') as fwrite:
fwrite.write(tempdir)
What exactly ends up in the file /Users/mymac/Documents/temp.txt?

Categories

Resources