Understanding signal handlers with context manager and program flow in python

Viewed 20

I have the following code:

import os
import signal
import time

class mre:
    
    def __init__(self) -> None:
        self.fd = None

    def write_file(self):
        with open("mre.log","w") as f:
            self.fd = f
            print("writing to file")
            while True:
                time.sleep(0.1)
                f.write("hello")

    def signal_handler(self, sig, frame):
        #delete the file
        try:
            #self.fd.close()
            os.remove("mre.log")
            print("file closed")
        except Exception as err:
            print("exception raised")
            raise err

    def main(self):
        signal.signal(signal.SIGINT, self.signal_handler)
        self.write_file()

if __name__ == "__main__":
    temp = mre()
    temp.main()
    

Question 1:

I am unable to understand the program flow. When I run the program (Linux OS) and hit Ctrl+C, signal_handler() is called, and the file is removed, but the program is not terminated until I hit Ctrl+C again.

Here is the output (yt is a virtualenv):

(yt) LAPTOP-28TNND21% echo $0
/usr/bin/zsh
(yt) LAPTOP-28TNND21% python --version
Python 3.8.10
(yt) LAPTOP-28TNND21% python mre.py
writing to file
^Cfile closed
^Cexception raised
Traceback (most recent call last):
File "mre.py", line 34, in <module>
    temp.main()
File "mre.py", line 30, in main
    self.write_file()
File "mre.py", line 15, in write_file
    time.sleep(0.1)
File "mre.py", line 26, in signal_handler
    raise err
File "mre.py", line 22, in signal_handler
    os.remove("mre.log")
FileNotFoundError: [Errno 2] No such file or directory: 'mre.log'
(yt) LAPTOP-28TNND21% 

To understand the problem better, I commented the line os.remove("mre.log") in my code. Now every time I hit Ctrl+C, signal_handler is called, and I don't know what happens to control flow and the situation is an infinite loop that never stops until I kill the process.

Here is the output:

(yt) LAPTOP-28TNND21% echo $0         
/usr/bin/zsh
(yt) LAPTOP-28TNND21% python --version
Python 3.8.10
(yt) LAPTOP-28TNND21% python mre.py   
writing to file
^Cfile closed
^Cfile closed
^Cfile closed
^Cfile closed
^Cfile closed
^Cfile closed
^Cfile closed
^Cfile closed
^Cfile closed
^Cfile closed
^Cfile closed

I would like to understand the program flow or control flow.

Question 2:

I did run the same program on Windows as well and I get a completely different error. Here is the error (using PowerShell as terminal):

(venv) PS D:\Downloads\testing-main\src> $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      22621  436     


(venv) PS D:\Downloads\testing-main\src> python --version
Python 3.9.1
(venv) PS D:\Downloads\testing-main\src> python mre.py
writing to file
exception raised
Traceback (most recent call last):
File "D:\Downloads\testing-main\src\mre.py", line 34, in <module>
    temp.main()
File "D:\Downloads\testing-main\src\mre.py", line 30, in main
    self.write_file()
File "D:\Downloads\testing-main\src\mre.py", line 15, in write_file
    time.sleep(0.1)
File "D:\Downloads\testing-main\src\mre.py", line 26, in signal_handler
    raise err
File "D:\Downloads\testing-main\src\mre.py", line 22, in signal_handler
    os.remove("mre.log")
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'mre.log'
(venv) PS D:\Downloads\testing-main\src>

When the signal_handler is called, the program would have exited the with block, which means that the file should be closed. But based on the error, it is not closed. I would like to know why is the file not closed?

My Assumption:

Since, the file is not closed I assume that with block is not exited meaning that, when the signal_handler is called and finishes execution, the program control returns to with block, which I don't completely understand.

0 Answers
Related