Relative paths break when executing Python script from Windows batch? - python

My Python script works perfectly if I execute it directly from the directory it's located in. However if I back out of that directory and try to execute it from somewhere else (without changing any code or file locations), all the relative paths break and I get a FileNotFoundError.
The script is located at ./scripts/bin/my_script.py. There is a directory called ./scripts/bin/data/. Like I said, it works absolutely perfectly as long as I execute it from the same directory... so I'm very confused.
Successful Execution (in ./scripts/bin/): python my_script.py
Failed Execution (in ./scripts/): Both python bin/my_script.py and python ./bin/my_script.py
Failure Message:
Traceback (most recent call last):
File "./bin/my_script.py", line 87, in <module>
run()
File "./bin/my_script.py", line 61, in run
load_data()
File "C:\Users\XXXX\Desktop\scripts\bin\tables.py", line 12, in load_data
DATA = read_file("data/my_data.txt")
File "C:\Users\XXXX\Desktop\scripts\bin\fileutil.py", line 5, in read_file
with open(filename, "r") as file:
FileNotFoundError: [Errno 2] No such file or directory: 'data/my_data.txt'
Relevant Python Code:
def read_file(filename):
with open(filename, "r") as file:
lines = [line.strip() for line in file]
return [line for line in lines if len(line) == 0 or line[0] != "#"]
def load_data():
global DATA
DATA = read_file("data/my_data.txt")

Yes, that is logical. The files are relative to your working directory. You change that by running the script from a different directory.
What you could do is take the directory of the script you are running at run time and build from that.
import os
def read_file(filename):
#get the directory of the current running script. "__file__" is its full path
path, fl = os.path.split(os.path.realpath(__file__))
#use path to create the fully classified path to your data
full_path = os.path.join(path, filename)
with open(full_path, "r") as file:
#etc

Your resource files are relative to your script. This is OK, but you need to use
os.path.realpath(__file__)
or
os.path.dirname(sys.argv[0])
to obtain the directory where the script is located. Then use os.path.join() or other function to generate the paths to the resource files.

Related

Creating new CSV files from inputs in different directory

I'm simply trying to alter a CSV file with Python.
When all the files were in the same dir, everything was fine.
Now that the input files are in a different dir than where the output files will be, everything blows up, apparently b/c the files do not exist?
I first found this:
open() in Python does not create a file if it doesn't exist
Then I learned to change to the directory, which helped me loop over the CSVs in the target dir:
Moving up one directory in Python
When I run the command:
python KWRG.py ../Weekly\ Reports\ -\ Inbound/Search\ Activity/ 8/9/2021
I will get:
Traceback (most recent call last): File "KWRG.py", line 15, in <module> with open(args.input, 'r') as in_file, open(args.output, 'w') as out_file: IsADirectoryError: [Errno 21] Is a directory: '../Weekly Reports - Inbound/Search Activity/'
Sorry If I'm missing the obvious here, but why is the file not being created in the directory that I'm pointing the script to (or at all for that matter)?
The code:
import csv
import argparse
import os
# Create a parser to take arguments
#...snip...
cur_dir = os.getcwd()
reports_dir = os.chdir(os.path.join(cur_dir, args.dir))
for csv_file in os.listdir(reports_dir):
# Shorthand the name of the file
#...snip...
# Open the in and out files
with open(csv_file, 'r') as in_file, open(f'{out_name}-Search-Activity-{args.date}.csv', 'w+') as out_file:
# Re-arrange CSV
# EOF
Your problem is with this line:
reports_dir = os.chdir(os.path.join(cur_dir, args.dir))
os.chdir() doesn't return anything, it just performs the operation requested - changing the current working directory. From an interactive session with the REPL:
>>> import os
>>> result = os.chdir("/Users/mattdmo/")
>>> result
>>>
For your purposes, all you need is
reports_dir = os.path.join(cur_dir, args.dir)
and you'll be all set.

Compress photo and put to another directory with tinify and python

I'm slowly starting to study about python and wanted to write simple script which use tinify api, takes photos from unoptimalized directiory, compress it and put to optimalized directory. So far works partly, I mean weirdly I need to keep photos in main directory and unoptimalized one. If I dont have another copy in one of these directories, I have error. another thing is that after I launch script, only first photo is compressed and put inside optimalized directory, and then error appears.
So far I'm experimenting on two photos: lew.jpg and kot.jpg
My directory structure is like this:
Main root directory with script, and two other directories inside (optimalized and unoptimalized)
def optimalizeImages():
for fname in os.listdir('./unoptimalized'):
if fname.endswith(".jpg"):
print(fname)
source = tinify.from_file(fname)
print("processing", fname)
os.chdir("./optimalized")
source.to_file("optimalized-" + fname)
print("changed", fname)
optimalizeImages()
Error after processing first image:
Traceback (most recent call last):
File "python.py", line 20, in <module>
optimalizeImages()
File "python.py", line 11, in optimalizeImages
source = tinify.from_file(fname)
File "/home/grzymowiczma/.local/lib/python2.7/site-packages/tinify/__init__.py", line 79, in from_file
return Source.from_file(path)
File "/home/grzymowiczma/.local/lib/python2.7/site-packages/tinify/source.py", line 13, in from_file
with open(path, 'rb') as f:
IOError: [Errno 2] No such file or directory: 'kot.jpg'
and if i keep photos only in root directory, no error but also no any action, if i keep them only in unoptimalized i get same error:
Traceback (most recent call last):
File "python.py", line 20, in <module>
optimalizeImages()
File "python.py", line 11, in optimalizeImages
source = tinify.from_file(fname)
File "/home/grzymowiczma/.local/lib/python2.7/site-packages/tinify/__init__.py", line 79, in from_file
return Source.from_file(path)
File "/home/grzymowiczma/.local/lib/python2.7/site-packages/tinify/source.py", line 13, in from_file
with open(path, 'rb') as f:
IOError: [Errno 2] No such file or directory: 'lew.jpg'
There are two issues here, both because you are using relative filenames. os.listdir() gives you those relative filenames, without a path. Instead of ./unoptimalized/kot.jpg, you get just kot.jpg.
So when you try to load the image:
source = tinify.from_file(fname)
you tell the library to load image.jpg without any context other than the current working directory. And that's not the right directory, not if os.listdir('./unoptimalized') worked to list all image files; that indicates that the current working directory is in the parent directory of both unoptimalized and optimalized.
You solved that by putting an image file with the same name in the parent directory, but that's not quite the right way to solve this. More on this below.
The next issue is that you change the working directory:
os.chdir("./optimalized")
You do this for the first image, so now the current working directory has changed to optimalized. When you then loop back up for the next file, you are now in the wrong location altogether to read the next file. Now lew.jpg, which might exist in ./unoptimalized or the parent directory, can't be found because it is not there in ./optimalized.
The solution is to add on the directory name. You can do so with os.path.join(), and not changing directories:
def optimalizeImages():
input_dir = './unoptimalized'
output_dir = './optimalized'
for fname in os.listdir(input_dir):
if fname.endswith(".jpg"):
print(fname)
source = tinify.from_file(os.path.join(input_dir, fname))
print("processing", fname)
source.to_file(os.path.join(output_dir, "optimalized-" + fname))
print("changed", fname)
Note that this still depends heavily on the current working directory being correct, but at least it is now stable and stays at the parent directory of both optimalized and unoptimalized. You may want to change that to using absolute paths.
And a side note on language: In English, the correct spelling of the two terms is optimized and unoptimized. I didn't correct those in my answer to keep the focus on what is going wrong.

FileNotFoundError but file exists

I am creating a Python application that imports many JSON files. The files are in the same folder as the python script's location. Before I moved the entire folder someplace else, the files imported perfectly. Since the script creates a files if none exists, it keeps creating the file in the home directory while ignoring the one in the same folder as it is in. When I specify an absolute path (code below):
startT= time()
with open('~/Documents/CincoMinutos-master/settings.json', 'a+') as f:
f.seek(0,0) # places pointer at start of file
corrupted = False
try:
# turns all json info into vars with load
self.s_settings = json.load(f)
self.s_allVerbs = []
# --- OFFLINE MODE INIT ---
if self.s_settings['Offline Mode']: # conjugation file reading only happens if setting is on
with open('~/Documents/CincoMinutos-master/verbconjugations.json', 'r+', encoding='utf-8') as f2:
self.s_allVerbs = [json.loads(line) for line in f2]
# --- END OFFLINE MODE INIT ---
for key in self.s_settings:
if not isinstance(self.s_settings[key], type(self.s_defaultSettings[key])): corrupted = True
except Exception as e: # if any unexpected error occurs
corrupted = True
print('File is corrupted!\n',e)
if corrupted or not len(self.s_settings):
f.truncate(0) # if there are any errors, reset & recreate the file
json.dump(self.s_defaultSettings, f, indent=2, ensure_ascii=False)
self.s_settings = {key: self.s_defaultSettings[key] for key in self.s_defaultSettings}
# --- END FILE & SETTINGS VAR INIT ---
print("Finished loading file in {:4f} seconds".format(time()-startT))
It spits out a FileNotFound error.
Traceback (most recent call last):
File "/Users/23markusz/Documents/CincoMinutos-master/__main__.py", line 709, in <module>
frame = CincoMinutos(root)
File "/Users/23markusz/Documents/CincoMinutos-master/__main__.py", line 42, in __init__
with open('~/Documents/CincoMinutos-master/settings.json', 'a+') as f:
FileNotFoundError: [Errno 2] No such file or directory: '~/Documents/CincoMinutos-master/settings.json'
Keep in mind that I am perfectly able to access it with the same absolute path when I operate from terminal. Can somebody please explain what I need to do in order for the files to import correctly?
Also, I am creating this application for multiple users. While /Users/23markusz/Documents/CincoMinutos-master/verbconjugations.json does work, it will not on another user's system. This file is also in the SAME FOLDER as the script so it should import correctly.
UPDATE:
While my issue is solved using os.path.expanduser(), I still do not understand why python refuses to open a file that is within the same folder as the python script. It should automatically open the file with just the filename and not the absolute path.
"~" isn't a real directory (and would not qualify as an "absolute path"), and that's why the open doesn't work.
In order to expand the tilde to an actual directory (e.g. /Users/23markusz), you can use os.path.expanduser:
import os
...
with open(os.path.expanduser('~/Documents/CincoMinutos-master/settings.json'), 'a+') as f:
# Do stuff

My program runs from Esclipse, but not from terminal, citing that a file does not exist (but it does)

So I have this code to open the file "setup.json", and it works fine when i run the program from eclipse but when I run it from terminal on my Mac I get this error:
IOError: [Errno 2] No such file or directory: 'setup.json'
Here is the relevant code:
file = "setup.json"
for f in os.listdir(os.getcwd()):
if f == file:
file = f
with open(file,"r") as fi:
#(other code, irrelevant because the program crashes before this point
setup.json is in a folder HueSunset with two other files, "\__init__.py" and \__main__.py. \__main__.py is the file that this code is running from.
Following are the cases I could come up with:
Clear the IDEs cache and re-run
Make sure you do not have another file with the same name
Check for files permission
At the last you can run your code on online editor to make sure the code you are running is correct. If yes, then it is the problem of your file and location.
Your code will leave file unchanged if it does not find it in the current directory. The current directory is the directory you are in when you execute the script.
Try this:
file = "setup.json"
for f in os.listdir(os.getcwd()):
if f == file:
break
else:
print("Oops. File not found") # or in real production code, raise an exception
with open(f,"r") as fi:
#rest of your code

Getting Error while trying to save file in a folder in Python?

Folder Structure
Project_Folder -|
Scripts-|
images -|
file.py
Inside file.py
import requests
import os
import sys
sys.path.append('.')
url = "http://d2np4vr8r37sds.cloudfront.net/800313-kkenlukmjy-1481094947.jpg"
image = requests.get(url)
IMG_DIR = 'images'
IMG_DIR_ABS = os.path.join('.', IMG_DIR)
filename = "800313-kkenlukmjy-1481094947.jpg"
fullfilename = os.path.join(IMG_DIR_ABS, filename)
with open(fullfilename, 'wb') as f:
f.write(image.content)
f.close()
When I am running this code I am getting following error
python scripts/file.py
Traceback (most recent call last):
File "scripts/file.py", line 9, in <module>
with open(fullfilename, 'wb') as f:
IOError: [Errno 2] No such file or directory: './images/800313-kkenlukmjy-1481094947.jpg'
IMG_DIR_ABS = os.path.join('.', IMG_DIR) does not resolve the location of the current script. . is the current directory, not the directory of the current script.
What you want to do is:
IMG_DIR_ABS = os.path.join(os.path.dirname(__file__), IMG_DIR)
__file__ being the full filepath of the currently running script, which matches your expectations given your directory tree.
the advantage of this method is that you can launch your script from any directory.
Aside: no need for f.close() within the with block. with context handles that for you when exiting the block.
You are running your script from Project_Folder, but there is no such path './images/800313-kkenlukmjy-1481094947.jpg' if You look from that directory. Try using './scripts/images/800313-kkenlukmjy-1481094947.jpg' instead.

Categories