Python subprocess module wait method - python

I am learning the subprocess module in python, and to my understanding, the wait method, blocks the thread from executing the rest of the code until the launched process is closed. But when I cann the wait method it still executes the rest of the code:
def startCalc():
x = subprocess.Popen('C:\\Windows\\System32\\calc.exe')
time.sleep(5)
x.wait()
print('finished waiting')
print(x.poll())
print(x.wait())
startCalc()
If I am not wrong, the "finished waiting statement, would not appear in the output until I close the calculator, but it does.
Where am I wrong?

The problem isn't with your code, but rather with the calc.exe executable. It starts the calculator and returns immediately with 0 exit status. So, from the perspective of your program, the process ran to completion successfully. As far as I know, calc.exe doesn't have a way to launch in attached mode.
Test this by opening a powershell, or cmd terminal and launching calc.exe. You get the prompt back immediately.

I am not familiar with the ".wait" function, but if you want your code to wait for the execution of the "calc.exe" process, you could replace "Popen" with "call":
x = subprocess.call('C:\\Windows\\System32\\calc.exe')

Related

Is there any way to delay a Python Script till an Application is running?

I want the Python Code to open Notepad and let the user type in it, by the time it should not execute the rest of the code. After I close notepad, it should resume the script from where it left. Is there any way to do this? Or should I try a different approach?
What have I Tried:
Here is the code so far -
with open('file.txt','w') as file: #this is to create an empty file
file.close()
pass
os.startfile('file.txt')
time.sleep() # what value should I enter for time.sleep? or is there a module to do this?
I possibly can run a while loop to check whether the notepad.exe is running or not, if it is, if it's not, it should break out of the loop and execute the rest of the code.However, the problem is how do I check if notepad.exe is running?
Running a while loop to delete the file, if it get's an error, means the program is still running, but the problem is if it does not get the error, It will delete the file.
It would be better, if when launching of the program, it takes the process ID of it, and only wait for it to terminated. So that other instances of notepad won't be affected.
From the docs:
startfile() returns as soon as the associated application is
launched. There is no option to wait for the application to close, and
no way to retrieve the application’s exit status.
If you know the path of the application to open the file with, you could use subprocess.Popen() which allows for you to wait.
p = subprocess.Popen([
'C:\\Windows\\System32\\notepad.exe',
'path\\to\\file'
])
(output, err) = p.communicate()
#This makes the wait possible
p_status = p.wait()
See:
http://docs.python.org/library/os.html#os.startfile
http://docs.python.org/library/subprocess.html#subprocess.Popen

How to end a python subprocess with no return?

I'm working on a BCP wrapper method in Python, but have run into an issue invoking the command with subprocess.
As far as I can tell, the BCP command doesn't return any value or indication that it has completed outside of what it prints to the terminal window, which causes subprocess.call or subprocess.run to hang while they wait for a return.
subprocess.Popen allows a manual .terminate() method, but I'm having issues getting the table to write afterwards.
The bcp command works from the command line with no issues, it loads data from a source csv according to a .fmt file and writes an error log file. My script is able to dismount the file from log path, so I would consider the command itself irrelevant and the question to be around the behavior of the subprocess module.
This is what I'm trying at the moment:
process = subprocess.Popen(bcp_command)
try:
path = Path(log_path)
sleep_counter = 0
while path.is_file() == False and sleep_counter < 16:
sleep(1)
sleep_counter +=1
finally:
process.terminate()
self.datacommand = datacommand
My idea was to check that the error log file has been written by the bcp command as a way to tell that the process had finished, however while my script no longer freezes with this, and the files are apparently being successfully written and dismounted later on in the script. The script terminates in less than the 15 seconds that the sleep loop would use to end it as well.
When the process froze my Spyder shell (and Idle, so it's not the IDE), I could force terminate it by closing the console itself and it would write to the server at least.
However it seems like by using the .terminate() the command isn't actually writing anything to the server.
I checked if a dumb 15 second time-out (it takes about 2 seconds to do the BCP with this data) would work as well, in case it was writing an error log before the load finished.
Still resulted in an empty table on SQL server.
How can I get subprocess to execute a command without hanging?
Well, it seems to be a more general issue about calling helper functions with Popen
as seen here:
https://github.com/dropbox/pyannotate/issues/67
I was able to fix the hanging issue by changing it to:
subprocess.Popen(bcp_command, close_fds = True)

Python freezes running exe file

I'm doing a simple python gui and on button click it will run a simple command:
os.system("C:/cygwin64/bin/bash.exe")
When I look in the console it ran correctly and but my guy freezes and is not responding.
If I run the the command in the console without python it works perfectly and I start cygwin terminal.
If you know what is cygwin is there a better way to start it in the same terminal?
os.system blocks the current thread, you can use os.popen in order to do that in another thread, and it also gives you few methods to detach/read/write etc' that process.
for example,
import os
a = os.popen("python -c 'while True: print(1)'")
will create a new process that will be terminated as soon as you terminate your script.
you can do
for i in a:
print(i)
for example, and it will block the thread as os.system does.
you can a.detach() it whenever you want to terminate the process.
However, os.system
import os
os.system("python -c 'while True: print(1)'")
it will output the 1s forever until you terminate the script.
You can use function Popen in package subprocess. It has many possible arguments that allow you to pipe input to and/or pipe output from the program you are running. But if you just want to execute bash.exe while allowing your original Python program to continue running and eventually wait for the completion of bash.exe, then:
import subprocess
# pass a list of command-line arguments:
p = subprocess.Popen(["C:/cygwin64/bin/bash.exe"])
... # continue executing
# wait for the subprocess (bash.exe) to end:
exit_code = p.wait()

using quit(), exit(), ETC. says "The program is still running, do you want to kill it?"

While making an HTML help tool in Python, I wanted to exit the program smoothly, like clicking the X button on Google Chrome. But, I encountered an issue. It asks me if I want to kill the program, instead of doing it automatically.
I tried using quit(), exit() and sys.exit(). All do the same thing. How can I get the program to exit smoothly?
As it was suggested in the comments, your problem should only be noticed inside Python's IDLE, but should run just fine when executed inside a terminal. However, this code should also kill your program in IDLE:
import os, signal
from time import sleep
print("I will sleep for 3 secs and shut down!")
sleep(3)
os.kill(os.getpid(), signal.SIGTERM)
This sends a signal to your application to terminate.
Or alternatively you could call os' _exit function.
From the docs:
Exit the process with status n, without calling cleanup handlers, flushing stdio buffers, etc.
I know it's late but I took a different way.
It might be a dirty way of doing it. I don't like the accepted
answer because you have to hardcode those lines in every script.
I just comment out the lines, so that the dialog never shows on screen.
You can find the file /usr/lib/python3.9/idlelib/pyshell.py
aprx: line 1007
def close(self):
"Extend EditorWindow.close()"
#if self.executing:
#response = messagebox.askokcancel(
#"Kill?",
#"Your program is still running!\n Do you want to kill it?",
#default="ok",
#parent=self.text)
#if response is False:
#return "cancel"
self.stop_readline()
self.canceled = True
self.closing = True
return EditorWindow.close(self)
That way it will never ask you this silly question "Your program is still running!\n Do you want to kill it?"

Subprocess.check_call and throbber not working

So I have this part of code which does a simple thing : it launches a script and while the script is processing, a throbber is set on.
def go(self):
if ui.chk.isChecked():
self.startThrobber()
script = subprocess.check_call(r'"C:\Program Files\FME\fme.exe"', shell=False)
if script == 0:
self.stopThrobber() # opens a QMessageBox and stops throbber
else:
QMessageBox.information(self.popup(), "Errpr", "Error !")
After trying different methods (QThread, subprocess.Popen ...) this is the closest i got to make it work.
The only thing that doesn't work is that the throbber doesn't start right before the subprocess is executed, it starts after and thus it never stops.
So why is the throbber not ending when stopThrobber() is executed ?
And why is startThrobber not being executed before the subprocess (i'm pretty sure it's a subprocess thing, but i'm pretty new to all this, never heard about thread until yesterday)
EDIT :
The single quote was just a typing error, sorry. Still doesn't fix the problem.
Any call to a subprocess, from your main thread, that is blocking (waits for return) is going to stop your throbber from working properly. My answer to your other SO question on this topic outlines an approach that does not cause the subprocess call to block the main thread. I should point out that solution is not the only way to create a non-blocking call to a subprocess (for instance see here. You could create a QTimer to poll the subprocess poll() method periodically so that you can check the returncode to see if the subprocess has finished.)
The key theme is that you need your methods that run in the main thread to return quickly in order to keep the GUI responsive and allow your throbber to run/animate. So choose a way to launch the subprocess that meets this requirement.
Your single quotes denoting the raw string enclose the 'shell' argument.
def go(self):
if ui.chk.isChecked():
self.startThrobber()
script = subprocess.check_call(r"C:\Program Files\FME\fme.exe", shell=False)
if script == 0:
self.stopThrobber() # opens a QMessageBox and stops throbber
else:
QMessageBox.information(self.popup(), "Errpr", "Error !")
So I've tried another thing (unsuccessfully..)
When I click on a button, it executes startThrobber() and sends a signal to the following function :
def go(self):
self.startThrobber()
script = subprocess.Popen(r'"C:\Program Files\FME\fme.exe" ', shell=False)
while script.poll() == None:
time.sleep(1)
else:
p.stopThrobber()
But still doesn't working.. startThrobber is executed but nothing appears on the GUI... I thougth that the point of subprocess was to allow to do multiple tasks simultaneously so why isn't the throbber appearing ?
UPDATE : if i erase the while loop, startThrobber works : it appears while the subprocess is turning. So why when there is the while loop it doesn't work ?!

Categories