Python subprocess doesn't run until calling process finished - python

EDIT 1 - added more code
I'm not sure that proc.communicate was needed, it was one of the suggestions I found from some other stackoverflow code.(Sorry I was tired last night and didn't think too much before asking the question.)
I should add that I am not an experienced coder (mechanical engineer) as you can probably tell from my code
In my Gui I have a button to call a subprocess
The subprocess (screenshot-cmd.exe) creates a png of a cropped screen shot but it won't actually produce the file until there is an error or if the button click event is over.
This makes me think that the subprocess is not actually run until the event is finished
I want to call the process several times after a single button press and move the files that it produces after each one is produced
if I use proc.wait(), the process hangs indefinitely.
How do I stop this?
# function to take a single image called 'fileName' and place it in directory 'dir'
def takeImage(dir,fileName):
# calculate the view to capture to get the whole display window in.
clientRect = win32gui.GetClientRect(win32gui.GetForegroundWindow())
windowRect = win32gui.GetWindowRect(win32gui.GetForegroundWindow())
print(windowRect)
windowSize = [windowRect[2]-windowRect[0],windowRect[3]-windowRect[1]]
print(windowSize)
print(clientRect)
diffSize = [windowSize[0] -clientRect[2], windowSize[1] - clientRect[3]]
lrbBorder = diffSize[0]/2
topBorder = diffSize[1] - lrbBorder
print("sizeDiff = " + str(diffSize))
windowName = win32gui.GetWindowText(win32gui.GetForegroundWindow())
handleId = win32gui.GetForegroundWindow()
leftMar = designLabel.GetPosition()[0] + lrbBorder
topMar = designLabel.GetPosition()[1] + topBorder + designLabel.GetSize()[1]
rightMar = leftMar + scene.width
bottMar = topMar+scene.height
margins = [leftMar,topMar,rightMar,bottMar]
print(margins)
# now print the view.
#command_line = r"screenshot-cmd -wt '" + windowName + "' -rc " + str(margins[0]) + " " + str(margins[1]) + " " + str(margins[2]) + " " + str(margins[3]) + " -o " + fileName
command_line = r"screenshot-cmd -wt '" + windowName + "' -rc " + str(margins[0]) + " " + str(margins[1]) + " " + str(margins[2]) + " " + str(margins[3]) + " -o " + fileName
print(command_line)
args = shlex.split(command_line)
proc = subprocess.Popen(args)
proc.wait()
wx.Yield()
if not os.path.isdir(dir):
os.makedirs(dir)
newPath = os.path.join(dir,fileName)
if os.path.exists(newPath):
os.remove(newPath)
oldPath = os.path.join(os.getcwd(), fileName)
print("Old Path: " + oldPath)
print("Exists: " + str(os.path.exists(oldPath)))
shutil.move(oldPath,newPath)
return
#event called upon clicking 'takeTenImag' button
def takeTenImgE(evt):
global designNo
global workingDirectory
global numDesigns
fileNameRoot = "test_"
fileExtention = ".png"
# check there are at least 10 designs
if numDesigns > 9 and os.path.exists(workingDirectory):
# find directory path to put images in
dir = os.path.join(workingDirectory, "images")
# for each design
for x in range(10):
print("design =" + str(designNo))
fileName = fileNameRoot + str(designNo) + fileExtention
print("------------------")
print("for x = " + str(x) + " " + fileName)
# create image and save
print(dir)
takeImage(dir,fileName)
#move to next design
wx.PostEvent(forwardDesign, wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, forwardDesign.GetId()) )
wx.Yield()
print("design =" + str(designNo))
return
takeTenImg = wx.Button(p, label='Take Ten Images', pos=(rb + visScaleText.GetSize()[0]+10,takeImg.GetPosition()[1]+5 +takeImg.GetSize()[1]), size = (100,30))
takeTenImg.Bind(wx.EVT_BUTTON, takeTenImgE)
https://code.google.com/p/screenshot-cmd/

Barnaby, you may be over-complicating your subprocess use. Popen is typically used for when you need to communicate with the process during the time it is running. From the sound of it, you don't need to do that, so might want to use a higher level function. See the docs on subprocess' various invocations, and perhaps try using the call method. You'll need shell=True, as detailed in SO questions such as this one.

I've found that the error is in my calling of subprocess.
I was using:
command_line = r"screenshot-cmd -wt '" + windowName + ...."
args = shlex.split(command_line)
subprocess.call(args,shell=True)
changing this to:
command_line = r"screenshot-cmd -wt '" + windowName + ...."
subprocess.call(command_line,shell=True)
solves the hang.
What is peculiar is that both options work when not inside a wx button click event(i.e. a python script launched from the command line), but only the second works when inside the wx button click event.
If anyone could enlighten me why that would be most appreciated.
EDIT:
upon further investigation, the hang is caused by trying to specify the active window in screenshot-cmd.
To solve this I find the position of the window using
windowRect = win32gui.GetWindowRect(win32gui.GetForegroundWindow())
and then use screenshot-cmd without specifying a window.
This solves all issues although it is unclear why this causes problems

Related

Arcmap script will not print messages in arcmap console

I have a Python script for Arcmap that I wrote. I'm trying to create a tool that reprojects all the feature classes within the workspace to a specified feature class.
The problem that I'm having is that I cannot get Arcmap to print the "completed" messages. The messages that I want to have appear will print when I hard-code the variables and run it as a script, but they will not print in Arcmap. You can see in the code below that I have specific printed messages that I want printed, but they just won't appear.
Code:
#Import modules
import arcpy, os
#Set workspace directory
from arcpy import env
#Define workspace
inWorkspace = arcpy.GetParameterAsText(0)
env.workspace = inWorkspace
env.overwriteOutput = True
try:
#Define local feature class to reproject to:
targetFeature = arcpy.GetParameterAsText(1)
#Describe the input feature class
inFc = arcpy.Describe(targetFeature)
sRef = inFc.spatialReference
#Describe input feature class
fcList = arcpy.ListFeatureClasses()
#Loop to re-define the feature classes and print the messages:
for fc in fcList:
desc = arcpy.Describe(fc)
if desc.spatialReference.name != sRef.name:
print "Projection of " + str(fc) + " is " + desc.spatialReference.name + ", so re-defining projection now:\n"
newFc = arcpy.Project_management(fc, "projected_" + fc, sRef)
newFeat = arcpy.Describe(newFc)
count = arcpy.GetMessageCount()
print "The reprojection of " + str(newFeat.baseName) + " " + arcpy.GetMessage(count-1) + "\n"
#Find out which feature classes have been reprojected
outFc = arcpy.ListFeatureClasses("projected_*")
#Print a custom messagae describing which feature classes were reprojected
for fc in outFc:
desc = arcpy.Describe(fc)
name = desc.name
name = name[:name.find(".")]
name = name.split("_")
name = name[1] + "_" + name[0]
print "The new file that has been reprojected is named " + name + "\n"
except arcpy.ExecuteError:
pass
severity = arcpy.GetMaxSeverity()
if severity == 2:
print "Error occurred:\n{0}".format(arcpy.GetMessage(2))
elif severity == 1:
print "Warning raised:\n{1}".format(arcpy.GetMessage(1))
else:
print "Script complete"
When I upload a script into an Arcmap toolbox, the following lines (From the above code) will NOT print:
print "Projection of " + str(fc) + " is " + desc.spatialReference.name + ", so re-defining projection now:\n"
print "The reprojection of " + str(newFeat.baseName) + " " + arcpy.GetMessage(count-1) + "\n"
print "The new file that has been reprojected is named " + name + "\n"
How can I fix this?
print only prints the messages while your script is running in Python interpreter. In order to print logs while the script is running in ArcGIS Toolbox, you need to use arcpy.AddMessage()
arcpy.AddMessage("Projection of {0} is {1}, so re-defining projection now: ".format(str(fc), desc.spatialReference.name)

python invoking PV-Wave

'/usr/local/bin/wave' only accepts a filename as input, so I need to invoke the process, then "send in" the commands, and wait for the output file to be written. Then my process can proceed to read the output file. Here is my code that does not write to the output file:
hdfFile = "/archive/HDF/16023343.hdf"
pngFile = "/xrfc_calib/xrfc.130.png"
lpFile = os.environ['DOCUMENT_ROOT'] + pngFile
waveCmd = "hdfview, '" + hdfFile + "', outfile='" + lpFile + "', web, view='RASTER', /neg"
os.environ['WAVE_PATH'] = "/oudvmt/wave/pro:/dvmt/wave/pro"
wfile = subprocess.Popen ('/usr/local/bin/wave >&2', shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
wfile.stdin = "\#hdf_startup\n\#hdf_common\n" + waveCmd + "\nquit\n"
I found what I was missing. The change is to the last 2 lines. They are:
wfile = subprocess.Popen ('/usr/local/bin/wave', stdin=subprocess.PIPE, stdout=subprocess.PIPE)
wfile.communicate("\#hdf_startup\n\#hdf_common\n" + waveCmd + "\nquit\n")
I needed to set "stdout" to avoid extra output from PV-Wave.
I needed to use "communicate" to wait for the process to complete.

Python file asks whether batch file to be continued

please refer following code, which creates batch file for executing certain programs synchronously. but after execution of first file, the program stops and asks whether the batch to be continued. This is causing a delay for user input. Since i wish to run several files overnight, the program waits for user input. Could anyone help me with this error ?
import os
from subprocess import call
version = "0.1"
os.system('CLS')
print("////////////////////////////////////////////////")
print("// LS-DYNA Simulation Start Script, V" + version + " //")
print("////////////////////////////////////////////////\n")
input_flag = 0
while input_flag == 0:
solver_type_string = raw_input("Use single or double precision solver (s/d)?")
if solver_type_string == "s":
solver_type_string = "ls971_s_R5.1.1_winx64_p.exe"
print("Choosen Solver: " + solver_type_string + "\n")
input_flag = 1
elif solver_type_string == "d":
solver_type_string = "ls971_d_R5.1.1_winx64_p.exe"
print("Choosen Solver: " + solver_type_string + "\n")
input_flag = 1
else:
print("Invalid input!\n")
current_path = os.path.dirname(os.path.abspath(__file__))
solver_path = "C:\Programme\LSDyna-971.1\program\\" + solver_type_string
batch_file = open("sim_start.bat", "w")
batch_file.write("#echo off\n")
sim_counter = 0
for (path, dirs, files) in os.walk(current_path):
for sim_file in files:
if sim_file.endswith((".k", ".dyn")):
sim_counter = sim_counter + 1
sim_path = path
print("Found: \'" + sim_file + "\'")
batch_file.write("pushd " + sim_path + "\\\n")
batch_file.write(solver_path + " i=" + sim_path + "\\" + sim_file + "\n")
print "\nDone! Found ", sim_counter, " simulation files in total."
batch_file.close()
print "\nStarting LS-DYNA batch run...\n"
call(current_path + "\sim_start.bat")
The created file looks like
#echo off
pushd E:\Shah\CPW\t25_nw100_amp25_ptr35_matDC04\
C:\Programme\LSDyna-971.1\program\ls971_d_R5.1.1_winx64_p.exe i=E:\Shah\CPW\t25_nw100_amp25_ptr35_matDC04\t25_nw100_amp25_ptr35_matDC04.dyn
pushd E:\Shah\CPW\t25_nw100_amp30_ptr40_matDC04\
C:\Programme\LSDyna-971.1\program\ls971_d_R5.1.1_winx64_p.exe i=E:\Shah\CPW\t25_nw100_amp30_ptr40_matDC04\t25_nw100_amp30_ptr40_matDC04.dyn
pushd E:\Shah\CPW\t25_nw10_amp15_ptr25_matDC04\
C:\Programme\LSDyna-971.1\program\ls971_d_R5.1.1_winx64_p.exe i=E:\Shah\CPW\t25_nw10_amp15_ptr25_matDC04\t25_nw10_amp15_ptr25_matDC04.dyn
pushd E:\Shah\CPW\t25_nw10_amp20_ptr30_matDC04\
C:\Programme\LSDyna-971.1\program\ls971_d_R5.1.1_winx64_p.exe i=E:\Shah\CPW\t25_nw10_amp20_ptr30_matDC04\t25_nw10_amp20_ptr30_matDC04.dyn
pushd E:\Shah\CPW\t25_nw10_amp25_ptr35_matDC04\
C:\Programme\LSDyna-971.1\program\ls971_d_R5.1.1_winx64_p.exe i=E:\Shah\CPW\t25_nw10_amp25_ptr35_matDC04\t25_nw10_amp25_ptr35_matDC04.dyn
pushd E:\Shah\CPW\t25_nw10_amp30_ptr40_matDC04\
C:\Programme\LSDyna-971.1\program\ls971_d_R5.1.1_winx64_p.exe i=E:\Shah\CPW\t25_nw10_amp30_ptr40_matDC04\t25_nw10_amp30_ptr40_matDC04.dyn
pushd E:\Shah\CPW\t25_nw30_amp15_ptr25_matDc04\
C:\Programme\LSDyna-971.1\program\ls971_d_R5.1.1_winx64_p.exe i=E:\Shah\CPW\t25_nw30_amp15_ptr25_matDc04\t25_nw30_amp15_ptr25_matDc04.dyn
After some research, I can conclude that, when we press 'ctrl + c' during the batch run (i was pressing ctrl + c to check the execution time of ls dyna program ), the window of "whether you want to terminate the batch prohgram" appears and program waits for user input..

Python code to send command through command line

final="cacls " + "E:/" + "\"" + list1[2] + " " + list1[3] + "\"" + " /p " + str
os.system(final)
I am trying to set permission to a folder Using Python but while running this command , User input needs to be provided too i.e
it asks ARE YOU SURE(Y/N) and the user needs to enter "Y" or "N"
Is there any way to use python to send the user input "Y" along with the above code?
pro = subprocess.Popen(final,shell=True, stdin=subprocess.PIPE)
pro.communicate(bytes("Y\r\n",'utf-8'))
I have added the following code . The program exits without setting the permission.
http://jimmyg.org/blog/2009/working-with-python-subprocess.html#writing-to-standard-input
Try using the subprocess module
import subprocess
cmd = ["cacls", "E:/" + list1[2], list1[3], "/p", str]
pro = subprocess.Popen(final, stdin=subprocess.PIPE)
pro.communicate("y\r\n")
As a smart programmer, use PBS
Then, the code is:
from pbs import type as echo# Isn't it echo for Windows? If not, use the correct one
script = Command("/path/to/cacls ")
print script(echo("Y"), ("E:/" + "\"" + list1[2] + " " + list1[3] + "\"" + " /p " + str).split())

Usage of subprocess class in Python

final="cacls " + "E:/" + "\"" + list1[2] + " " + list1[3] + "\"" + " /p " + str
pro = subprocess.Popen(final,shell=True, stdin=subprocess.PIPE)
pro.communicate(bytes("Y\r\n",'utf-8'))
Trying to set permission to a folder Using Python but while running this command , User input needs to be provided too i.e
it asks ARE YOU SURE(Y/N) and the user needs to enter "Y" or "N"
The above code is not setting the permission.
This was the question i had asked before:
Python code to send command through command line
As a smart programmer, use PBS
Then, the code is:
from pbs import type as echo# Isn't it echo for Windows? If not, use the correct one
script = Command("/path/to/cacls ")
print script(echo("Y"), ("E:/" + "\"" + list1[2] + " " + list1[3] + "\"" + " /p " + str).split())

Categories

Resources