23

Can I have a running python script(under Windows)being paused in the middle by user , and resume again when user decides ?

There is a main manager program which generates,loads and runs other python scripts (by calling python script.py from console).I don't have GUI and user can interact via console.I want my main program be able to respond to user pause/resume command for the running script.Should I define a thread? Whats the approach ?

Edit/Update :

Let's say I have a small python application with frontend which has various functions. I have a RUN command which runs python scripts in background .I want to implement a PAUSE feature which would pause the running python script . When the user commands RUN again then the python script should resume running . using raw_input() or print() forces user to issue command.But in this case, we don't know when user want to interrupt/pause/issue a command.So usual input/print is not usable.

2
  • This isn't very clear, but you have me intrigued. Lemme see if I can figure this out: you have a console program that manages a series of external python scripts, and you want to make a set of commands that will pause and resume a script. I think the best method would be setting up those scripts as generators, so they periodically drop back to the manager program, which can then look for a user command, and then tell the script to continue, assuming the user did not pause the script. Commented Aug 24, 2011 at 21:30
  • Not exactly, I have added a description to my question.. Commented Aug 24, 2011 at 22:30

11 Answers 11

19

If it were unix I'd recommend signal, but here is a crude version that does what you ask.

import time while True: try: time.sleep(1) # do something here print '.', except KeyboardInterrupt: print '\nPausing... (Hit ENTER to continue, type quit to exit.)' try: response = raw_input() if response == 'quit': break print 'Resuming...' except KeyboardInterrupt: print 'Resuming...' continue 

Use Ctrl+C to pause, and ENTER to resume. Ctrl+Break can probably be used as a harsh kill, but I don't have the key on this keyboard.

A more robust version could use select on a pipe/socket, or even threads.

Sign up to request clarification or add additional context in comments.

4 Comments

+1. Seems kinda hacky, but comes closer to the requirements than mine, I think.
Yes, hacky but a complete solution is out of scope for a SO question I'd gather.
if instead of time.sleep() i have a lengthy python script,I can't use this trick as everytime we resume it runs the whole script from the begining.It does not store the state on pause..
Use subprocess to run it, then pause and resume process with stackoverflow.com/questions/1892356/…
10

You can make a simple workaround by creating a PAUSEFILE. Your to-be-paused script may periodically check for existence (or content) of such file.

User's PAUSE command can create (or fill with proper content) such file.

I have used this approach in a similar situation, where I wanted to be able to pause my Python scripts and resume them later. They contain something like

if os.path.isfile(PAUSEFILE): raw_input('Remove ' + PAUSEFILE + ' and hit ENTER to continue') 

in their main loops.

It is nasty and could be broken if the code really depended on it, but for the use cases, where the pause is done by users at random, I guess it will not matter.

The PAUSE command is simply touch $PAUSEFILE.

1 Comment

This is not fancy but it's an easy way to perform the equivalent of a low-priority interrupt. I would like my script to pause only at the end of a block of code inside a loop (that runs for hours) and this is an easy way to do that.
7

I don't understand very well your approach but every time a user needs to press a enter to continue the script you should use:

input() #for python 3k raw_input() #for python 2k 

without assigning the receiving answer to a variable.

3 Comments

well, you said that users interact only using console, so the only way of taking input from then is from input and raw_input, and to a lower level stdin. If you created a gui app in tkinter for example you could take input from mouse gestures, keyboard presses etc.
yes but problem is not how to get input.Is how to link the forced inputs to pause and resume.I don't ask for inputs in my code.I want code to act upon interrupts and treat them like pause and resume.
I like this answer: simple, works. I used this in a Python 3.5 script: input("\n\tpaused: press Enter to continue\n")
6

Ok, from what I've seen in my searches on this, even with threading, sys.stdin is going to work against you, no matter how you get to it (input(), or even sys.stdin.read(), .readline(), etc.), because they block.

Instead, write your manager program as a socket server or something similar.

Write the scripts as generators, which are designed to pause execution (every time it hits a yield), and just call next() on each one in turn, repeatedly. You'll get a StopIteration exception when a script completes.

For handling the commands, write a second script that connects to the manager program's socket and sends it messages, this will be the console interface the user interacts with (later, you could even upgrade it to a GUI without altering much elsewhere).

The server picks these commands up before running the next iteration on the scripts, and if a script is paused by the user, the manager program simply doesn't call next() on that script until the user tells it to run again.

I haven't tested this, but I think it'll work better than making threads or subprocesses for the external scripts, and then trying to pause (and later kill) them.


This is really out of my depth, but perhaps running the scripts in the background and using kill -stop and kill -cont to pause and continue will work (assuming Linux)?

3 Comments

logic seems fine,I'm not sure if this is feasible and fast enough.My scripts call custom library functions which I cant make them generators ,and they are very lengthy functions...
Hmm. Then you are likely stuck with threads. Generators are the only code objects that Python can suspend execution of, leaving you with subprocesses, assuming you can pause them.
awesome! however, i'm not using generators and kill -stop job_id and kill -cont job_id work perfectly.
2

I found so hacky those responses, while being interesting too.

The best approach is the https://stackoverflow.com/a/7184165/2480481 doing it using KeyboardInterrupt exception.

As i noticed nobody mention "using a debugger", i'll do it.

Install pdb, Python debugger with pip install pdb. Follow that to make your script pausable https://stackoverflow.com/a/39478157/2480481 by Ctrl+c instead of exit it.

The main benefit of using a debugger (pdb) is that you can inspect the variables, values, etc. This is far way more powerfull than just pause/continue it.

Also, you can add Ipython interface with pdb attached to debug your app when crashes. Look at: https://stackoverflow.com/a/14881323/2480481

Comments

1

If you're launching your python script from the windows command window, you can use msvcrt.kbhit() as a non-blocking key press check as implemented here: http://code.activestate.com/recipes/197140-key-press-detection-for-windows-text-only-console-/

2 Comments

kbhit() is "only" present on windows. If you install it on Linux, it will crash loading termios from _kbhit. It's more usable if you use timeout (0) and getch() functions togheter to detect a keypress. I may be wrong but is what i see when playing few things. Look viget.com/articles/… then pastebin.com/1VRdFdPQ and finally pastebin.com/xyfm7LNa which is what i did finally to make it work. U can see all togheter where i found a related question to that tutorial: gist.github.com/reagent/9743630.
This is very nicely written. Just in case, here is an archived version of it.
1

You can use Pdb module in python. Eventhough it's a debugger, in your case it helps you pass and continue wherever you have a breakpoint in the code.

Also when you resume you can get a glimpse of where it is paused and what are the values of the variables etc. Which will be very helpful.

python debugger - pdb

Comments

1

I was searching for this for so long. Hence decided to solve it myself. Below code works just fine for me.

Before starting the loop, simply print an instruction line for users.

Here's my code -

import time start = 0 run = True while run == True: try : # Loop Code Snippet for i in range(start,100): time.sleep(2) print(i) start = i+1 except : print("""~~~~~~~Code interupted~~~~~~~ \n Press 1 to resume \n Press 2 to quit""") res = input() if res == "1" : print("1") # pass and resume code pass if res == "2" : print("2") #Save output and quit code run = False pass #Safety pass if case user press invalid input 

This code can be interrupted by using conventional way of "Ctrl + C ".

How this works - When code is interrupted, "keyboard interrupt" error is raised. Due to which error handler "Try:Except" will go to Except block ( where user can provide an input to either resume, save current output or quit code )

For resume functionality, loop's current position is saved and is fed back into as start for loop.

There are many improvement points here, look forward to suggestions.

Comments

0

Have you tried the obvious and print a prompt then read a line from stdin? That will pause your whole script.

What you asked in your original question isn't very clear, so if this doesn't do what you want, can you explain why?

Comments

0

In Windows, you can suspend/resume running Python scripts . Type resmon on CMD or via Run command (Windows+R). Locate your Python script process and right-click>Suspend Process. This will unlock CPU usage but not RAM. ;)

Comments

0

in Linux terminal:

sudo pkill -STOP python3 sudo pkill -CONT python3 

if you want to do it from within python, then create config.ini with text

[control] pausescript = False 

and then in python script:

from configparser import ConfigParser config = ConfigParser() config.read("config.ini") 

and somewhere in the script where it loops:

 pauseScript = True while pauseScript: config.read("config.ini") pauseScript = config.getboolean('control', 'pausescript') if pauseScript: print("Script paused. Resume by change config setting to False. ",end="\r") time.sleep(0.3) 

then you control the script by putting True or False in the config.ini file

Comments