22

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.

  • 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. – Erik Youngren Aug 24 '11 at 21:30
  • Not exactly, I have added a description to my question.. –  Aug 24 '11 at 22:30

11 Answers11

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.

Gringo Suave
  • 29,931
  • 6
  • 88
  • 75
  • +1. Seems kinda hacky, but comes closer to the requirements than mine, I think. – Erik Youngren Aug 25 '11 at 04:10
  • Yes, hacky but a complete solution is out of scope for a SO question I'd gather. – Gringo Suave Aug 25 '11 at 05:46
  • 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.. –  Aug 25 '11 at 22:43
  • Use subprocess to run it, then pause and resume process with http://stackoverflow.com/questions/1892356/pausing-a-process-in-windows/4229561#4229561 – Gringo Suave Aug 26 '11 at 00:24
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.

ciakval
  • 101
  • 1
  • 2
  • 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. – jaybrau Jul 21 '15 at 15:36
6

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.

Serban Razvan
  • 4,250
  • 3
  • 21
  • 22
  • 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. – Serban Razvan Aug 25 '11 at 09:22
  • 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. –  Aug 25 '11 at 22:44
  • I like this answer: simple, works. I used this in a Python 3.5 script: input("\n\tpaused: press Enter to continue\n") – Victoria Stuart Oct 25 '16 at 17:03
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)?

Erik Youngren
  • 783
  • 1
  • 6
  • 15
  • 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... –  Aug 25 '11 at 01:01
  • 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. – Erik Youngren Aug 25 '11 at 01:11
  • awesome! however, i'm not using generators and `kill -stop job_id` and `kill -cont job_id` work perfectly. – tmthyjames Mar 18 '15 at 21:06
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

Community
  • 1
  • 1
m3nda
  • 1,986
  • 3
  • 32
  • 45
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-/

jonincanada
  • 417
  • 5
  • 5
  • `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 https://www.viget.com/articles/game-programming-in-c-with-the-ncurses-library then https://pastebin.com/1VRdFdPQ and finally https://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: https://gist.github.com/reagent/9743630. – m3nda Mar 07 '17 at 04:42
  • This is very nicely written. Just in case, [here](https://web.archive.org/save/http://code.activestate.com/recipes/197140-key-press-detection-for-windows-text-only-console-/) is an archived version of it. – bballdave025 Jan 23 '20 at 23:24
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

Jim Todd
  • 1,488
  • 1
  • 11
  • 15
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.

Dhruv Arya
  • 11
  • 1
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. ;)

Prayson W. Daniel
  • 14,191
  • 4
  • 51
  • 57
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?

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
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

Jan
  • 115
  • 5