Source code for koapy.backend.kiwoom_open_api_plus.utils.pyside2.QSignalHandler
import signal as signal_module
import socket
from signal import Signals
from types import FrameType
from typing import Iterable, Optional, overload
from koapy.compat.pyside2.QtCore import QObject, Signal
from koapy.compat.pyside2.QtNetwork import QAbstractSocket
from koapy.utils.logging.pyside2.QAbstractSocketLogging import QAbstractSocketLogging
[docs]class QSignalHandler(QAbstractSocketLogging):
[docs] signaled = Signal(Signals, FrameType)
@overload
def __init__(self, signals: Iterable[Signals], parent: Optional[QObject]):
...
@overload
def __init__(self, parent: Optional[QObject]):
...
def __init__(self, *args, **kwargs):
signals: Optional[Iterable[Signals]] = None
parent: Optional[QObject] = None
args = list(args)
kwargs = dict(kwargs)
if len(args) > 0 and not isinstance(args[0], QObject):
signals = args.pop(0)
elif "signals" in kwargs:
signals = kwargs.pop("signals")
if len(args) > 0:
parent = args[0]
elif "parent" in kwargs:
parent = kwargs["parent"]
self._signals = signals
self._parent = parent
QAbstractSocketLogging.__init__(
self, QAbstractSocket.UdpSocket, *args, **kwargs
)
self._old_wakeup_fd = None
self._old_signal_handlers = {}
self._wsock, self._rsock = socket.socketpair(socket.AF_INET, socket.SOCK_STREAM)
self.readyRead.connect(self.onReadyRead)
[docs] def onReadyRead(self):
# it is up to the library to remove any bytes from fd before calling poll or select again
# check https://docs.python.org/3.9/library/signal.html#signal.set_wakeup_fd for more details
data = self.readData(1)
# not actually using this, since file descriptor is used for wakeup purpose only
_signal = data[0]
[docs] def emitSignal(self, signal, frame):
signal = signal_module.Signals(signal)
self.signaled.emit(signal, frame)
[docs] def setWakeUpFileDescriptor(self, descriptor, warn_on_full_buffer=True):
old_wakeup_fd = signal_module.set_wakeup_fd(
descriptor, warn_on_full_buffer=warn_on_full_buffer
)
# remember first time replcement only
if self._old_wakeup_fd is None:
self._old_wakeup_fd = old_wakeup_fd
return old_wakeup_fd
[docs] def restoreWakeUpFileDescrptor(self):
if self._old_wakeup_fd is not None:
old_wakeup_fd = signal_module.set_wakeup_fd(self._old_wakeup_fd)
self._old_wakeup_fd = None
return old_wakeup_fd
[docs] def setHandler(self, signal, handler):
old_handler = signal_module.signal(signal, handler)
# remember first time replcement only
if signal not in self._old_signal_handlers:
self._old_signal_handlers[signal] = old_handler
return old_handler
[docs] def restoreHandler(self, signal, default=None):
if signal in self._old_signal_handlers:
if default is None:
default = signal_module.SIG_DFL
old_handler = self._old_signal_handlers.pop(signal, default)
old_handler = signal_module.signal(signal, old_handler)
return old_handler
[docs] def restoreAllHandlers(self):
if self._old_signal_handlers:
old_signal_handlers = dict(self._old_signal_handlers)
for signal, handler in old_signal_handlers.items():
self.restoreHandler(signal, handler)
self._old_signal_handlers = {}
[docs] def setAll(self):
self.setSocketDescriptor(self._rsock.fileno())
# setting warn_on_full_buffer=False, since we are using the wakeup fd only for wakeups
# check https://docs.python.org/3.9/library/signal.html#signal.set_wakeup_fd for more details
self.setWakeUpFileDescriptor(self._wsock.fileno(), warn_on_full_buffer=False)
if self._signals:
for signal in self._signals:
self.setHandler(signal, self.emitSignal)
[docs] def restoreAll(self):
self.restoreWakeUpFileDescrptor()
self.restoreAllHandlers()
def __del__(self):
self.restoreAll()
def __enter__(self):
self.setAll()
return self
def __exit__(self, exc_type, exc_value, traceback):
self.restoreAll()