[Pkg-bitcoin-commits] [python-quamash] 64/78: Change how event loop base classes are assigned.
Jonas Smedegaard
dr at jones.dk
Tue Dec 19 01:19:56 UTC 2017
This is an automated email from the git hooks/post-receive script.
js pushed a commit to annotated tag debian/0.6.0_dfsg-1
in repository python-quamash.
commit 6517f5a9c6633476b8c4b74049a1f83d7ecacf4c
Author: Mark Harviston <Mark.T.Harviston.-ND at disney.com>
Date: Thu Jan 14 12:36:20 2016 -0800
Change how event loop base classes are assigned.
This lets you use the SelectorEventLoop on windows.
---
quamash/__init__.py | 50 +++---
quamash/_unix.py | 441 ++++++++++++++++++++++++++--------------------------
quamash/_windows.py | 3 -
3 files changed, 249 insertions(+), 245 deletions(-)
diff --git a/quamash/__init__.py b/quamash/__init__.py
index 94acfac..cb4220c 100644
--- a/quamash/__init__.py
+++ b/quamash/__init__.py
@@ -171,14 +171,6 @@ def _make_signaller(qtimpl_qtcore, *args):
return Signaller()
-if os.name == 'nt':
- from . import _windows
- _baseclass = _windows.baseclass
-else:
- from . import _unix
- _baseclass = _unix.baseclass
-
-
class _SimpleTimer(QtCore.QObject):
def __init__(self, timeout, callback):
super().__init__()
@@ -307,8 +299,9 @@ class QEventLoop(_baseclass):
super().close()
for timer in self.__timers:
- timer.stop()
-
+ if timer.isActive():
+ timer.stop()
+ del timer
self.__timers = None
self.__app = None
@@ -335,20 +328,21 @@ class QEventLoop(_baseclass):
def upon_timeout():
nonlocal timer
nonlocal handle
- if timer in self.__timers:
- self.__timers.remove(timer)
- else:
- self._logger.warn('Timer {} not among {}'.format(timer, self.__timers))
+ assert timer in self.__timers, 'Timer {} not among {}'.format(timer, self.__timers)
+ self.__timers.remove(timer)
timer = None
self._logger.debug('Callback timer fired, calling {}'.format(handle))
handle._run()
handle = None
self._logger.debug('Adding callback {} with delay {}'.format(handle, delay))
- timer = _SimpleTimer(delay * 1000, upon_timeout)
+ timer = QtCore.QTimer(self.__app)
+ timer.timeout.connect(upon_timeout)
+ timer.setSingleShot(True)
+ timer.start(delay * 1000)
self.__timers.append(timer)
- return timer
+ return _Cancellable(timer, self)
def call_soon(self, callback, *args):
"""Register a callback to be run on the next iteration of the event loop."""
@@ -510,9 +504,7 @@ class QEventLoop(_baseclass):
self.__exception_handler = handler
def default_exception_handler(self, context):
- """Handle exceptions.
-
- This is the default exception handler.
+ """Default exception handler.
This is called when an exception occurs and no exception
handler is set, and can be called by a custom exception
@@ -592,3 +584,23 @@ class QEventLoop(_baseclass):
cls._logger.error(*args, **kwds)
except:
sys.stderr.write('{!r}, {!r}\n'.format(args, kwds))
+
+from .unix import _SelectorEventLoop
+class QSelectorEventLoop(_QEventLoop, _SelectorEventLoop):
+ pass
+
+if os.name == 'nt':
+ from ._windows import _ProactorEventLoop
+ class QIOCPEventLoop(_QEventLoop, _ProactorEventLoop):
+ pass
+ QEventLoop = QIOCPEventLoop
+else:
+ QEventLoop = QSelectorEventLoop
+
+class _Cancellable:
+ def __init__(self, timer, loop):
+ self.__timer = timer
+ self.__loop = loop
+
+ def cancel(self):
+ self.__timer.stop()
diff --git a/quamash/_unix.py b/quamash/_unix.py
index b471899..913cd44 100644
--- a/quamash/_unix.py
+++ b/quamash/_unix.py
@@ -1,223 +1,218 @@
-# © 2014 Mark Harviston <mark.harviston at gmail.com>
-# © 2014 Arve Knudsen <arve.knudsen at gmail.com>
-# BSD License
-
-"""UNIX specific Quamash functionality."""
-
-import asyncio
-from asyncio import selectors
-import collections
-
-from . import QtCore, with_logger
-
-
-EVENT_READ = (1 << 0)
-EVENT_WRITE = (1 << 1)
-
-
-def _fileobj_to_fd(fileobj):
- """
- Return a file descriptor from a file object.
-
- Parameters:
- fileobj -- file object or file descriptor
-
- Returns:
- corresponding file descriptor
-
- Raises:
- ValueError if the object is invalid
-
- """
- if isinstance(fileobj, int):
- fd = fileobj
- else:
- try:
- fd = int(fileobj.fileno())
- except (AttributeError, TypeError, ValueError) as ex:
- raise ValueError("Invalid file object: {!r}".format(fileobj)) from ex
- if fd < 0:
- raise ValueError("Invalid file descriptor: {}".format(fd))
- return fd
-
-
-class _SelectorMapping(collections.Mapping):
-
- """Mapping of file objects to selector keys."""
-
- def __init__(self, selector):
- self._selector = selector
-
- def __len__(self):
- return len(self._selector._fd_to_key)
-
- def __getitem__(self, fileobj):
- try:
- fd = self._selector._fileobj_lookup(fileobj)
- return self._selector._fd_to_key[fd]
- except KeyError:
- raise KeyError("{!r} is not registered".format(fileobj)) from None
-
- def __iter__(self):
- return iter(self._selector._fd_to_key)
-
-
- at with_logger
-class _Selector(selectors.BaseSelector):
- def __init__(self, parent):
- # this maps file descriptors to keys
- self._fd_to_key = {}
- # read-only mapping returned by get_map()
- self.__map = _SelectorMapping(self)
- self.__read_notifiers = {}
- self.__write_notifiers = {}
- self.__parent = parent
-
- def select(self, *args, **kwargs):
- """Implement abstract method even though we don't need it."""
- raise NotImplementedError
-
- def _fileobj_lookup(self, fileobj):
- """Return a file descriptor from a file object.
-
- This wraps _fileobj_to_fd() to do an exhaustive search in case
- the object is invalid but we still have it in our map. This
- is used by unregister() so we can unregister an object that
- was previously registered even if it is closed. It is also
- used by _SelectorMapping.
- """
- try:
- return _fileobj_to_fd(fileobj)
- except ValueError:
- # Do an exhaustive search.
- for key in self._fd_to_key.values():
- if key.fileobj is fileobj:
- return key.fd
- # Raise ValueError after all.
- raise
-
- def register(self, fileobj, events, data=None):
- if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
- raise ValueError("Invalid events: {!r}".format(events))
-
- key = selectors.SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
-
- if key.fd in self._fd_to_key:
- raise KeyError("{!r} (FD {}) is already registered".format(fileobj, key.fd))
-
- self._fd_to_key[key.fd] = key
-
- if events & EVENT_READ:
- notifier = QtCore.QSocketNotifier(key.fd, QtCore.QSocketNotifier.Read)
- notifier.activated.connect(self.__on_read_activated)
- self.__read_notifiers[key.fd] = notifier
- if events & EVENT_WRITE:
- notifier = QtCore.QSocketNotifier(key.fd, QtCore.QSocketNotifier.Write)
- notifier.activated.connect(self.__on_write_activated)
- self.__write_notifiers[key.fd] = notifier
-
- return key
-
- def __on_read_activated(self, fd):
- self._logger.debug('File {} ready to read'.format(fd))
- key = self._key_from_fd(fd)
- if key:
- self.__parent._process_event(key, EVENT_READ & key.events)
-
- def __on_write_activated(self, fd):
- self._logger.debug('File {} ready to write'.format(fd))
- key = self._key_from_fd(fd)
- if key:
- self.__parent._process_event(key, EVENT_WRITE & key.events)
-
- def unregister(self, fileobj):
- def drop_notifier(notifiers):
- try:
- notifier = notifiers.pop(key.fd)
- except KeyError:
- pass
- else:
- notifier.activated.disconnect()
-
- try:
- key = self._fd_to_key.pop(self._fileobj_lookup(fileobj))
- except KeyError:
- raise KeyError("{!r} is not registered".format(fileobj)) from None
-
- drop_notifier(self.__read_notifiers)
- drop_notifier(self.__write_notifiers)
-
- return key
-
- def modify(self, fileobj, events, data=None):
- try:
- key = self._fd_to_key[self._fileobj_lookup(fileobj)]
- except KeyError:
- raise KeyError("{!r} is not registered".format(fileobj)) from None
- if events != key.events:
- self.unregister(fileobj)
- key = self.register(fileobj, events, data)
- elif data != key.data:
- # Use a shortcut to update the data.
- key = key._replace(data=data)
- self._fd_to_key[key.fd] = key
- return key
-
- def close(self):
- self._logger.debug('Closing')
- self._fd_to_key.clear()
- self.__read_notifiers.clear()
- self.__write_notifiers.clear()
-
- def get_map(self):
- return self.__map
-
- def _key_from_fd(self, fd):
- """
- Return the key associated to a given file descriptor.
-
- Parameters:
- fd -- file descriptor
-
- Returns:
- corresponding key, or None if not found
-
- """
- try:
- return self._fd_to_key[fd]
- except KeyError:
- return None
-
-
-class _SelectorEventLoop(asyncio.SelectorEventLoop):
- def __init__(self):
- self._signal_safe_callbacks = []
-
- selector = _Selector(self)
- asyncio.SelectorEventLoop.__init__(self, selector)
-
- def _before_run_forever(self):
- pass
-
- def _after_run_forever(self):
- pass
-
- def _process_event(self, key, mask):
- """Selector has delivered us an event."""
- self._logger.debug('Processing event with key {} and mask {}'.format(key, mask))
- fileobj, (reader, writer) = key.fileobj, key.data
- if mask & selectors.EVENT_READ and reader is not None:
- if reader._cancelled:
- self.remove_reader(fileobj)
- else:
- self._logger.debug('Invoking reader callback: {}'.format(reader))
- reader._run()
- if mask & selectors.EVENT_WRITE and writer is not None:
- if writer._cancelled:
- self.remove_writer(fileobj)
- else:
- self._logger.debug('Invoking writer callback: {}'.format(writer))
- writer._run()
-
-
-baseclass = _SelectorEventLoop
+# © 2014 Mark Harviston <mark.harviston at gmail.com>
+# © 2014 Arve Knudsen <arve.knudsen at gmail.com>
+# BSD License
+
+"""UNIX specific Quamash functionality."""
+
+import asyncio
+from asyncio import selectors
+import collections
+
+from . import QtCore, with_logger
+
+
+EVENT_READ = (1 << 0)
+EVENT_WRITE = (1 << 1)
+
+
+def _fileobj_to_fd(fileobj):
+ """
+ Return a file descriptor from a file object.
+
+ Parameters:
+ fileobj -- file object or file descriptor
+
+ Returns:
+ corresponding file descriptor
+
+ Raises:
+ ValueError if the object is invalid
+ """
+ if isinstance(fileobj, int):
+ fd = fileobj
+ else:
+ try:
+ fd = int(fileobj.fileno())
+ except (AttributeError, TypeError, ValueError) as ex:
+ raise ValueError("Invalid file object: {!r}".format(fileobj)) from ex
+ if fd < 0:
+ raise ValueError("Invalid file descriptor: {}".format(fd))
+ return fd
+
+
+class _SelectorMapping(collections.Mapping):
+
+ """Mapping of file objects to selector keys."""
+
+ def __init__(self, selector):
+ self._selector = selector
+
+ def __len__(self):
+ return len(self._selector._fd_to_key)
+
+ def __getitem__(self, fileobj):
+ try:
+ fd = self._selector._fileobj_lookup(fileobj)
+ return self._selector._fd_to_key[fd]
+ except KeyError:
+ raise KeyError("{!r} is not registered".format(fileobj)) from None
+
+ def __iter__(self):
+ return iter(self._selector._fd_to_key)
+
+
+ at with_logger
+class _Selector(selectors.BaseSelector):
+ def __init__(self, parent):
+ # this maps file descriptors to keys
+ self._fd_to_key = {}
+ # read-only mapping returned by get_map()
+ self.__map = _SelectorMapping(self)
+ self.__read_notifiers = {}
+ self.__write_notifiers = {}
+ self.__parent = parent
+
+ def select(self, *args, **kwargs):
+ """Implement abstract method even though we don't need it."""
+ raise NotImplementedError
+
+ def _fileobj_lookup(self, fileobj):
+ """Return a file descriptor from a file object.
+
+ This wraps _fileobj_to_fd() to do an exhaustive search in case
+ the object is invalid but we still have it in our map. This
+ is used by unregister() so we can unregister an object that
+ was previously registered even if it is closed. It is also
+ used by _SelectorMapping.
+ """
+ try:
+ return _fileobj_to_fd(fileobj)
+ except ValueError:
+ # Do an exhaustive search.
+ for key in self._fd_to_key.values():
+ if key.fileobj is fileobj:
+ return key.fd
+ # Raise ValueError after all.
+ raise
+
+ def register(self, fileobj, events, data=None):
+ if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
+ raise ValueError("Invalid events: {!r}".format(events))
+
+ key = selectors.SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
+
+ if key.fd in self._fd_to_key:
+ raise KeyError("{!r} (FD {}) is already registered".format(fileobj, key.fd))
+
+ self._fd_to_key[key.fd] = key
+
+ if events & EVENT_READ:
+ notifier = QtCore.QSocketNotifier(key.fd, QtCore.QSocketNotifier.Read)
+ notifier.activated.connect(self.__on_read_activated)
+ self.__read_notifiers[key.fd] = notifier
+ if events & EVENT_WRITE:
+ notifier = QtCore.QSocketNotifier(key.fd, QtCore.QSocketNotifier.Write)
+ notifier.activated.connect(self.__on_write_activated)
+ self.__write_notifiers[key.fd] = notifier
+
+ return key
+
+ def __on_read_activated(self, fd):
+ self._logger.debug('File {} ready to read'.format(fd))
+ key = self._key_from_fd(fd)
+ if key:
+ self.__parent._process_event(key, EVENT_READ & key.events)
+
+ def __on_write_activated(self, fd):
+ self._logger.debug('File {} ready to write'.format(fd))
+ key = self._key_from_fd(fd)
+ if key:
+ self.__parent._process_event(key, EVENT_WRITE & key.events)
+
+ def unregister(self, fileobj):
+ def drop_notifier(notifiers):
+ try:
+ notifier = notifiers.pop(key.fd)
+ except KeyError:
+ pass
+ else:
+ notifier.activated.disconnect()
+
+ try:
+ key = self._fd_to_key.pop(self._fileobj_lookup(fileobj))
+ except KeyError:
+ raise KeyError("{!r} is not registered".format(fileobj)) from None
+
+ drop_notifier(self.__read_notifiers)
+ drop_notifier(self.__write_notifiers)
+
+ return key
+
+ def modify(self, fileobj, events, data=None):
+ try:
+ key = self._fd_to_key[self._fileobj_lookup(fileobj)]
+ except KeyError:
+ raise KeyError("{!r} is not registered".format(fileobj)) from None
+ if events != key.events:
+ self.unregister(fileobj)
+ key = self.register(fileobj, events, data)
+ elif data != key.data:
+ # Use a shortcut to update the data.
+ key = key._replace(data=data)
+ self._fd_to_key[key.fd] = key
+ return key
+
+ def close(self):
+ self._logger.debug('Closing')
+ self._fd_to_key.clear()
+ self.__read_notifiers.clear()
+ self.__write_notifiers.clear()
+
+ def get_map(self):
+ return self.__map
+
+ def _key_from_fd(self, fd):
+ """
+ Return the key associated to a given file descriptor.
+
+ Parameters:
+ fd -- file descriptor
+
+ Returns:
+ corresponding key, or None if not found
+ """
+ try:
+ return self._fd_to_key[fd]
+ except KeyError:
+ return None
+
+
+class _SelectorEventLoop(asyncio.SelectorEventLoop):
+ def __init__(self):
+ self._signal_safe_callbacks = []
+
+ selector = _Selector(self)
+ asyncio.SelectorEventLoop.__init__(self, selector)
+
+ def _before_run_forever(self):
+ pass
+
+ def _after_run_forever(self):
+ pass
+
+ def _process_event(self, key, mask):
+ """Selector has delivered us an event."""
+ self._logger.debug('Processing event with key {} and mask {}'.format(key, mask))
+ fileobj, (reader, writer) = key.fileobj, key.data
+ if mask & selectors.EVENT_READ and reader is not None:
+ if reader._cancelled:
+ self.remove_reader(fileobj)
+ else:
+ self._logger.debug('Invoking reader callback: {}'.format(reader))
+ reader._run()
+ if mask & selectors.EVENT_WRITE and writer is not None:
+ if writer._cancelled:
+ self.remove_writer(fileobj)
+ else:
+ self._logger.debug('Invoking writer callback: {}'.format(writer))
+ writer._run()
diff --git a/quamash/_windows.py b/quamash/_windows.py
index fb586ef..a474161 100644
--- a/quamash/_windows.py
+++ b/quamash/_windows.py
@@ -52,9 +52,6 @@ class _ProactorEventLoop(asyncio.ProactorEventLoop):
self.__event_poller.stop()
-baseclass = _ProactorEventLoop
-
-
@with_logger
class _IocpProactor(windows_events.IocpProactor):
def __init__(self):
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-bitcoin/python-quamash.git
More information about the Pkg-bitcoin-commits
mailing list