code: def _maybe_allow_interrupt(qapp):
      """
      This manager allows to terminate a plot by sending a SIGINT. It is
      necessary because the running Qt backend prevents Python interpreter to
      run and process signals (i.e., to raise KeyboardInterrupt exception). To
      solve this one needs to somehow wake up the interpreter and make it close
      the plot window. We do this by using the signal.set_wakeup_fd() function
      which organizes a write of the signal number into a socketpair connected
      to the QSocketNotifier (since it is part of the Qt backend, it can react
      to that write event). Afterwards, the Qt handler empties the socketpair
      by a recv() command to re-arm it (we need this if a signal different from
      SIGINT was caught by set_wakeup_fd() and we shall continue waiting). If
      the SIGINT was caught indeed, after exiting the on_signal() function the
      interpreter reacts to the SIGINT according to the handle() function which
      had been set up by a signal.signal() call: it causes the qt_object to
      exit by calling its quit() method. Finally, we call the old SIGINT
      handler with the same arguments that were given to our custom handle()
      handler.
  
      We do this only if the old handler for SIGINT was not None, which means
      that a non-python handler was installed, i.e. in Julia, and not SIG_IGN
      which means we should ignore the interrupts.
      """
  
      old_sigint_handler = signal.getsignal(signal.SIGINT)
      if old_sigint_handler in (None, signal.SIG_IGN, signal.SIG_DFL):
          yield
          return
  
      handler_args = None
      wsock, rsock = socket.socketpair()
      wsock.setblocking(False)
      rsock.setblocking(False)
      old_wakeup_fd = signal.set_wakeup_fd(wsock.fileno())
      sn = QtCore.QSocketNotifier(
          rsock.fileno(), QtCore.QSocketNotifier.Type.Read
      )
  
      # We do not actually care about this value other than running some Python code to
      # ensure that the interpreter has a chance to handle the signal in Python land.  We
      # also need to drain the socket because it will be written to as part of the wakeup!
      # There are some cases where this may fire too soon / more than once on Windows so
      # we should be forgiving about reading an empty socket.
      # Clear the socket to re-arm the notifier.
      @sn.activated.connect
      def _may_clear_sock(*args):
          try:
              rsock.recv(1)
          except BlockingIOError:
              pass
  
      def handle(*args):
          nonlocal handler_args
          handler_args = args
          qapp.quit()
  
      signal.signal(signal.SIGINT, handle)
      try:
          yield
      finally:
          wsock.close()
          rsock.close()
          sn.setEnabled(False)
          signal.set_wakeup_fd(old_wakeup_fd)
          signal.signal(signal.SIGINT, old_sigint_handler)
          if handler_args is not None:
              old_sigint_handler(*handler_args)
  
file_path: catboost/contrib/python/matplotlib/py3/matplotlib/backends/qt_compat.py
imports: import operator
  import os
  import platform
  import sys
  import signal
  import socket
  import contextlib
  from packaging.version import parse
  import matplotlib
  from .None import _QT_FORCE_QT5_BINDING
label_desc: Use image node_id 3 for calling a global function with example usage: _maybe_allow_interrupt(qapp) without return types