Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make my code stopable? (Not killing/interrupting)

Tags:

python

I'm asking this question in a more broad spectrum because I'm not facing this specific issue right now, but I'm wondering how to do it in the future.

If I have a long running python script, that is supposed to do something all the time (could be a infine loop, if that helps). The code is started by running python main.py command on a terminal.

The code doesn't have an ending, so there will be no sys.exit().

I don't want to use KeyboardInterrupt and I don't want to kill the task. Because those options are abrupt, and you can't predict precisely at what point you are stoping the code.

Is there a way to 'softly' terminate the code when I eventually decide to fo it? For example using another command, preparing a class or running another script?

What would be the best practice for this?

PS.: Please, bear in mind that I'm a novice coder.

EDIT: I'm adding some generic code, in order to make my question clearer.

import time,csv

import GenericAPI

class GenericDataCollector:
    def __init__(self):
        self.generic_api = GenericAPI()

    def collect_data(self):
        while True: #Maybe this could be a var that is changed from outside of the class?
            data = self.generic_api.fetch_data() #Returns a JSON with some data
            self.write_on_csv(data)
            time.sleep(1)

    def write_on_csv(self, data):
        with open('file.csv','wt') as f:
            writer = csv.writer(f)
            writer.writerow(data)

def run():
    obj = GenericDataCollector()
    obj.collect_data()

if __name__ == "__main__":
    run()

In this particular case, the class is collecting data from some generic API (that comes in JSON) and writing it in a csv file, in a infinite loop. How could I code a way (method?) to stop it (when called uppon, so unexpected), without abruptly interrupting (Ctrl+C or killing task).

like image 278
Justcurious Avatar asked Jul 11 '19 02:07

Justcurious


People also ask

How do you stop an infinite loop in Jupyter notebook?

Every now and then you will run code that either runs forever (infinite loop) or has errors you identified and want to stop. To stop code from running you must interrupt the kernel. Interrupting the kernel stops the code from running but doesn't remove the variable you have stored in memory.

How do I disable kernel?

To shut down a kernel, go to the associated notebook and click on menu File -> Close and Halt. Alternatively, the Notebook Dashboard has a tab named Running that shows all the running notebooks (i.e. kernels) and allows shutting them down (by clicking on a Shutdown button).

How do you stop a cell execution in Jupyter?

Stopping a process or restarting a Jupyter Notebook To interrupt a cell execution, you can click the ■ “stop” button in the ribbon above the notebook, or select “Interrupt Kernel” from the Kernel menue.


2 Answers

I would recommend use the signal module. This allows you to handle signal interrupts (SIGINT) and clean up the program before your exit. Take the following code for example:

import signal

running = True

def handle(a, b):
    global running
    running = False

# catch the SIGINT signal and call handle() when the process
# receives it
signal.signal(signal.SIGINT, handle)

# your code here
while running:
    pass

You can still exit with a Ctrl+C, but what you put in the while loop will not be cut off half way.

like image 90
Calder White Avatar answered Oct 06 '22 10:10

Calder White


Based on @Calder White, how about this (not tested):

import signal
import time,csv
import GenericAPI

class GenericDataCollector:
   def __init__(self):
     self.generic_api = GenericAPI()
     self.cont = True

   def collect_data(self):
     while self.cont:
       signal.signal(signal.SIGINT, self.handle)
       data = self.generic_api.fetch_data() #Returns a JSON with some data
       self.write_on_csv(data)
       time.sleep(1)

   def handle(self):
     self.cont = False

   def write_on_csv(self, data):
     with open('file.csv','wt') as f:
       writer = csv.writer(f)
       writer.writerow(data)

def run():
  obj = GenericDataCollector()
  obj.collect_data()

if __name__ == "__main__":
  run()
like image 1
bJust Avatar answered Oct 06 '22 09:10

bJust