0

I have a Python script containing multiple loops, and when I execute it, it continues running indefinitely until I manually stop it (usually by interrupting the kernel in Jupyter). Although I generally don't need to stop it, there are times when I do. To simplify, let's consider the following code:

while True:
    print("hello")
    countdown(2)
    print("hello2")
    countdown(2)
    print("hello3")
    #if F2 has been pressed, yield and error to stop the script

I would like to achieve the following behavior in my Python script: If I press F2 while the print("hello") part is executing, the script should stop after printing print("hello3"). Similarly, if I press F2 while the print("hello2") part is executing, the script should also stop after printing print("hello3"). Essentially, I want the code to halt at the designated point, regardless of where I press F2. Additionally, I don't want the script to prompt me for input at each loop iteration, asking whether to stop the script or not. This is because I typically don't need to interrupt it in that manner.

I have no idea how to implement it

Danial
  • 13
  • 2
  • In consoles, ctrl+c sends interruption signal (SIGINT). For jupyter, it seems `II` while in command mode should do that - https://stackoverflow.com/a/38229513/11516012 so `II`, if I understood it correctly – h4z3 Jun 14 '23 at 09:41

3 Answers3

2

You can create a listener that waits for keypresses using the pynput library. If the listener then detects a keypress it check wether it the F2 key and if so it sets a global stop flag.

At the end of the loop we check if the stop flag is set and exit if it is. Here's some sample code for that:

from time import sleep
from pynput import keyboard
from pynput.keyboard import Key


def on_press(key):
    global stop_flag
    if key == Key.f2:
        stop_flag = True


listener = keyboard.Listener(on_press=on_press)
listener.start()

stop_flag = False

while True:
    print("hello")
    sleep(2)
    print("hello2")
    sleep(2)
    print("hello3")
    if stop_flag:
        break
ShadowCrafter_01
  • 533
  • 4
  • 19
  • wow, exactly what I wanted. thanks a lot – Danial Jun 14 '23 at 10:30
  • @Danial no problem, although here on Stack Overflow we rather upvote an answer instead of saying thanks in the comments – ShadowCrafter_01 Jun 14 '23 at 10:31
  • yeah, but I got this: 'Thanks for the feedback! You need at least 15 reputation to cast a vote, but your feedback has been recorded.'. that's why I wrote to thank you buddy – Danial Jun 14 '23 at 10:39
0

I upvoted @ShadowCrafter_01 suggestion, because I like it very much.

Mine is kinda similar, but instead of relying on a third-party library I use the threading library of python.

However in this acse I actually would rather recommend to use the third party library, but anyway here is my approach:

import threading

import time


class PressKeyClass(object):
    continue_while: int = None

    def __init__(self): self.continue_while = True

    def func1(self):
        input("")
        print("detected key event")
        self.continue_while = False


def main():
    print("script start")

    bf: PressKeyClass = PressKeyClass()

    t1 = threading.Thread(target = bf.func1)

    t1.start()
    count: int = 0
    while bf.continue_while:
        print(f"count: {count} [pressing any key will abort this counting while-loop]")
        count += 1
        time.sleep(1)
    t1.join()

    print("script finished")


if __name__ == "__main__": main()

the bottom line is; such a functionality that python does things while also keeping track of other stuff (such as events (e.g. on-click events / key events)) require some sort parallelism. pynput automatizes this for (and therefore hides this from) you, whereas my approach is very explicit about (for didactic reasons maybe).

EDIT Now I realize, that because I use the input method => "any key" means [Return]

Tom
  • 54
  • 8
-1

Try this, it will take keyboard input from the user

pip install keyboard

import keyboard

while True:
    # do something
    if keyboard.is_pressed("q"):
        print("q pressed, ending loop")
        break
ShadowCrafter_01
  • 533
  • 4
  • 19
Niti Shah
  • 1
  • 1