Subprocess.call() cwd cannot set from text loaded value - python

TL;DR
subprocess.call(cwd=filepath) does not work when I set the filepath variable from a text file, but does work when I set it manually using an identical path.
More Info
When I use subprocess.call I specify the cwd of the command with a string variable. When the string is manually defined, everything works how it should. However, I want to load the cwd path from a value within a text file. I have that part nailed down as well, and I am loading the correct value from the text file. When cwd=filepath and filepath is set to the string value loaded in from the text file, I get a NotADirectoryError: [WinError 267] The directory name is invalid. Keep in mind that if I set the variable manually to the exact same path, I do not get this error. I think this is some kind of formatting issue, and I've played around with it/looked around the internet for a few days, but haven't found a working solution.
Full Code
import subprocess # to run the process.
import pathlib #to get the path of the file.
programpath = str(pathlib.WindowsPath(__file__).parent.absolute())
blenderfilepath = 'C:/Program Files/Blender Foundation/Blender 2.81/'
settingsfile = 'settings'
# Load in the variables from settings.
def Load():
global blenderfilepath
# # look inside settings file for settings.
sf = open(programpath + '\\' + settingsfile, 'r')
for line in sf:
if 'BPL' in line:
bfp = line.split('-', maxsplit=1)
blenderfilepath = str(pathlib.Path(bfp[1]))
print('Path loaded for Blender: ' + blenderfilepath)
else:
print('Using default config...')
return
sf.close()
print('Settings loaded')
# Run next job executes the command to run the next job.
def RunNextJob():
print('Running next job...')
print(blenderfilepath)
currentjob = subprocess.call('blender.exe', cwd=blenderfilepath, shell=True, stdout=subprocess.PIPE)
RunNextJob()
Additional Information and Thanks!
Initially, I was just pulling the string out of the file with no pathlib element. I've tried using just pathlib without converting it to a string as well. This is notable to mention.
For additional context, the "settings" file is one line that contains one line:
BPL-C:/Program Files/Blender Foundation/Blender 2.81/
It is parsed through to extract the path. I have validated that the path is extracted correctly.
Any help is appreciated. Thanks!

For anyone else with this same issue, add .rstring() to the end of your string. It will strip off any line endings and other sometimes invisible elements in strings.
The updated line reads:
blenderfilepath = str(pathlib.Path(bfp[1]).rstring())
Thank you to jasonharper for the help!

Related

Can create and save Word files in Python, but cannot print them

I have made a Client Report Generator - by entering info into the various fields, the app will generate a Word file, save it, print it, and then clear the entry fields to be used for the next report. I have gotten everything working, except for the printing. I have tried multiple solutions, and the one that seems to have the most promise is included in my code. If anyone can figure out what is going on, I would greatly appreciate it. File locations are not final, but I will set those up once ready to package the app. The problem is that the program halts with no error message, so I don't even know what to look for. If I use the alternate syntax for the current print module (arguments added as separate strings), I get a "File Not Found" error, and that's it. I am open to a completely different approach to printing, if that has a better chance of working.
Code follows:
#Save and Print
def SavePrint ():
# Create Word Document
CliNameVar = CliName.get('1.0', 'end-1c')
AppDateVar=AppDate.get('1.0', 'end-1c')
RepBodyVar=RepBody.get('1.0', 'end-1c')
from docx import Document
from docx.shared import Pt
from docx.shared import Inches
CliDoc = Document ()
body_style = CliDoc.styles['Body Text']
body = CliDoc.add_paragraph(style=body_style).add_run(f'{CliNameVar} - {AppDateVar}')
body.font.name = 'Arial'
body.font.size = Pt(12)
body = CliDoc.add_paragraph
body = CliDoc.add_paragraph(style=body_style).add_run(f'{RepBodyVar}')
CliDoc.add_picture('D:/Documents/DavidSignatureBlue.png', width=Inches(2.5))
#Save
FileLoc=Path("C:/Claire's Documents/AAAAFidler/Clients/%s" % CliNameVar)
FileName="C:/Claire's Documents/AAAAFidler/Clients/%s/%s - %s.docx" %(CliNameVar, CliNameVar, AppDateVar)
FileLoc.mkdir(parents=True)
CliDoc.save(FileName)
#Print
import subprocess
subprocess.Popen("'C:\Program Files (x86)\Microsoft Office\root\Office16\winword.exe' '%s' /mFilePrintDefault /mFileExit", shell=True).communicate() %FileName
UPDATE:
So, after wrestling with the fact that I can't seem to pass variables to the subprocess module, I tried using a TEMP folder, and hard-code the print filename. I got a bit further, in that Word opens (though I would prefer it happen in the background), but it still complains that the file name is not valid - even though I can see that the file exists.
#Print
import time
import shutil
import subprocess
tmpdir = "C:/Claire's Documents/TMPFILE"
os.mkdir(tmpdir)
tmpfil = "C:/Claire's Documents/TMPFILE/prntfile.docx"
shutil.copy(FileName, tmpfil)
time.sleep(3)
subprocess.Popen(["C:/Program Files (x86)/Microsoft Office/root/Office16/winword.exe", "C:/Claire's Documents/TMPFILE/prntfile.docx", "/mFilePrintDefault", "/mFileExit"]).communicate()
time.sleep(5)
shutil.rmtree(tmpdir)
SECOND UPDATE:
Turns out, the subprocess module does not like spaces, even inside double quotes. Removed the space between "Claire's Documents", and now it prints - except it will not close again, per the "/mFileExit". Going to look at closing it as a separate instruction.
So, as mentioned in my update, I found the problem to be twofold: The subprocess module does not like to have variables passed to it, and it doesn't like spaces in the path to the file it will be working on.
As such, the solution was to make a temporary file that always has the same name, and making sure that there were no spaces in the path to the temp file for the subprocess to get hung up on. I didn't even need the temp folder - just dropped the print file in the parent directory, and deleted it afterwards. It also turns out that the fact that the Word document opens in the foreground, and doesn't close is actually a feature, not a bug, so no further wrestling with this problem.
Code follows:
#FileName variable set in Save section
#Print
import time
import shutil
import subprocess
tmpfil = "C:/Claire'sDocuments/prntfile.docx"
shutil.copy(FileName, tmpfil)
time.sleep(3)
subprocess.Popen(["C:/Program Files (x86)/Microsoft Office/Office12/winword.exe", "C:/Claire'sDocuments/prntfile.docx", "/mFilePrintDefault"]).communicate()
os.remove(tmpfil)

Write Path Names to a File (Python)

I'm dealing with a large number of images and am trying to conduct a search for jpegs and then write their paths to a file.
Currently, I can find all the jpegs I want. However, each new path in my 'index' file overwrites the last. Consequently, it's not an index/list at all, but a text file containing a/path/to/just/one/file.jpg
I've simplified my code and added it below. It's verbose but that's for my reading benefit as well as for others who are new like myself.
#----------
#-->Import Modules
#I'm pretty sure there is redundancy here and it's not well laid out
#but I'm new to coding and it works
import os
import pathlib
import glob, os
from pathlib import Path
import os.path
from os import path
#----------
#-->Global Vars
#Simplified example of my variables
working_dir = "/Users/myname/path/to/working dir"
records_dir = str(working_dir + "/Records")
#----------
#-->Search Location
#Define where the jpeg search is to take place
#(actually dictated via user input, Minecraft is just an example)
search_locations = ["/Users/myname/minecraft"]
#---------
#--> Search for jpgs and write their paths to a file
#define the file where the jpeg paths are to be stored,
#(I'm referring to the storage file as an index of sorts)
jpg_index = str(records_dir + "/index_for_all_jpgs")
#Its embedded in a forloop because the user can add multiple locations
for search_location in search_locations:
#get the desired paths from the search location
for path in Path(search_location).rglob('*.jpg'):
#Open the index where paths are to be stored
with open(jpg_index, 'w') as filehandle:
#This is supposed to write each paths as a new line
#But it doesn't work
filehandle.writelines('%s\n' % path)
I have also tried using a simpler idea;
filehandle.write(path)
and a more complex one that I don't fully understand;
filehandle.writelines("%s\n" % path for path in search_location)
Yet all I have done is failed in a slightly different way.
The 'w' option tells the open() method to overwrite anything previously in the jpg_index file. Because you call this method each time before you write a jpeg path to it, only the last one remains. Use 'a' (append) in place of 'w' (write) to tell the open() method to append to the file instead of overwriting it each time.
For instance:
for search_location in search_locations:
for path in Path(search_location).rglob('*.jpg'):
with open(jpg_index, 'a') as filehandle:
filehandle.writelines('%s\n' % path)
Alternatively, you could move the with... as statement outside of the for loops. This way, the jpg_index file will only be opened and overwritten once at the beginning and not after there is already information in it.
For example:
with open(jpg_index, 'w') as filehandle:
for search_location in search_locations:
for path in Path(search_location).rglob('*.jpg'):
filehandle.writelines('%s\n' % path)

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.

Change Saving-Path - Python

I´m trying to save a file, which I create with the "open" function.
Well I tried nearly everything to change the directory, but nothing works. The file gets always saved in the folder of my file, which I read in before.
file = open(fname[0] + ft, 'w')
file.write("Test")
file.close()
So this is it simple, but what do I have to add, to change the path of creation?
The File Dialog in a individual Function:
global fname
fname = QFileDialog.getOpenFileName(None, 'Please choose your File.',"C:\\Program Files", "Text-Files(*.txt)")
And the File Typ ( in a individual Function too) I set the file type by ticking a check box and ft will set to .py or .pyw
if self.exec_py.isChecked() == True:
global ft
ft = ".py"
I should have mentioned that I already tried os.path.join and os.chdir, but the file will get printed in the file anyway. Any solutions or approaches how to fix it? Here is how i tried it:
tmppath = "C:/temp"
tmp = os.path.join(tmppath,fname[0]+ft)
file = open(tmp, 'w')
Your question is a little short on details, but I am guessing that fname is the tuple returned by QFileDialog, and so fname[0] is the absolute path of the original file. So if you display fname[0], you will see something like this:
>>> fname[0]
'C:\\myfolder\\file.txt'
Now look what happens when you try to use that with os.path.join:
>>> tmppath = 'C:\\temp'
>>> os.path.join(tmppath, fname[0])
'C:\\myfolder\\file.txt'
Nothing! Conclusion: attempting to join two absolute paths will simply return the original path unchanged. What you need to do instead is take the basename of the original path, and join it to the folder where you want to save it:
>>> basename = os.path.basename(fname[0])
>>> basename
'file.txt'
>>> os.path.join(tmppath, basename)
'C:\\tmp\\file.txt'
Now you can use this new path to save your file in the right place.
You need to provide the full filepath
with open(r'C:\entire\path\to\file.txt', 'w') as f:
f.write('test')
If you just provide a file name without a path, it will use the current working directory, which isn't necessarily the directory where the python script your running is located. It will be the directory where you launched the script from.
C:\Users\admin> python C:\path\to\my_script.py
In this instance, the current working directory is C:\Users\admin, not C:\path\to.

Python reading files in different local drive locations

Could someone shed me some lights on the file path matter in Python?
For example my codes need to read a batch of files, the file names are listed and stored in a .txt file, C:\filelist.txt, which content is:
C:\1stfile.txt
C:\2ndfile.txt
C:\3rdfile.txt
C:\4thfile.txt
C:\5thfile.txt
And the codes start with:
list_open = open('c:\\aaa.txt')
read_list = list_open.read()
line_in_list = read_list.split('\n')
all run fine. But if I want to read files in another path, such as:
C:\WorkingFolder\6thfile.txt
C:\WorkingFolder\7thfile.txt
C:\WorkingFolder\8thfile.txt
C:\WorkingFolder\9thfile.txt
C:\WorkingFolder\10thfile.txt
It doesn’t work. I guess the path here C:\WorkingFolder\ is not properly put so Python cannot recognize it.
So in what way I shall put it? Thanks.
hello all,
sorry that maybe i didn't make my self clear.
the problem is, a text file, c:\aaa.txt contains below:
C:\1stfile.txt
C:\WorkingFolder\1stfile.txt
why only C:\1stfile.txt is readable, but the other one not?
The reason your program isn't working is that you're not changing the directory properly. Use os.chdir() to do so, then open the files as normal:
import os
path = "C:\\WorkingFolder\\"
# Check current working directory.
retval = os.getcwd()
print "Current working directory %s" % retval
# Now change the directory
os.chdir( path )
# Check current working directory.
retval = os.getcwd()
print "Directory changed successfully %s" % retval
REFERENCES:
http://www.tutorialspoint.com/python/os_chdir.htm
import os
BASEDIR = "c:\\WorkingFolder"
list_open = open(os.path.join(BASEDIR, 'aaa.txt'))
Simply try using forward slashes instead.
list_open = open("C:/WorkingFolder/6thfile.txt", "rt")
It works for me.

Categories