Batman0730 Batman0730 - 1 year ago 74
Python Question

Stopping a python process so that context managers still call __exit__ (in windows)

How can I stop a python process in such a way that any active context managers will gracefully call their __exit__ function before closing?

I use context managers (__enter__() and __exit__()) to reliably and safely close connections to optical hardware. This has been working great, although we are now starting to execute routines that run for hours. Often we will realize shortly after starting one that we have a bug, and would rather to stop the process short.

I have been running code from PyCharm, which has allows you to "stop" a running process. This seems to instantly kill the process, whether I'm in debug or run. The __exit__ functions don't seem to get called.

Also, the computer that controls the hardware runs windows, if that somehow comes into play. ***

***Indeed in comes into play. Macosx seems to call the exit function while windows does not.

I decided to write a basic test:

from abc import *
import time

class Test(object):
__metaclass__ = ABCMeta

def __init__(self, *args, **kwargs):
print("Init called.")

def __enter__(self, *args, **kwargs):
print("enter called")

def __exit__(self, type, value, traceback):
print("Exit called")

with Test() as t:
time.sleep(100)
print("Should never get here.")


I run this code from PyCharm, and while it is in the sleep statement I press the stop button in pycharm. Here is the output from both:

Macosx:

Init called.
enter called
Exit called
Traceback (most recent call last):
File "/Applications/PyCharm CE.app/Contents/helpers/pydev/pydevd.py", line 1591, in <module>
globals = debugger.run(setup['file'], None, None, is_module)
File "/Applications/PyCharm CE.app/Contents/helpers/pydev/pydevd.py", line 1018, in run
pydev_imports.execfile(file, globals, locals) # execute the script
File "/Users/.../Library/Preferences/PyCharmCE2017.1/scratches/scratch_25.py", line 22, in <module>
time.sleep(100)
KeyboardInterrupt


Windows

Init called.
enter called

Process finished with exit code 1

Answer Source

I found a workaround on the PyCharm bug tracker:

https://youtrack.jetbrains.com/issue/PY-17252

  • In PyCharm go to help->Edit Custom Properties
  • Agree to create the idea.properties file (if it asks)
  • Add the following line: kill.windows.processes.softly=true
  • If you use Numpy or Scipy, you will also need to add the following environment variable:

    os.environ['FOR_DISABLE_CONSOLE_CTRL_HANDLER'] = "1"

  • Restart Pycharm

Now when I run my test with this applied (on Windows!) I get the following output:

Init called.
enter called
Exit called
Traceback (most recent call last):
  File "C:/Users/.../.PyCharmCE2017.1/config/scratches/scratch_3.py", line 20, in <module>
    time.sleep(100)
KeyboardInterrupt

Process finished with exit code 1
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download