diff --git a/Doc/library/selectors.rst b/Doc/library/selectors.rst index 98377c890f0..4c322bd75a2 100644 --- a/Doc/library/selectors.rst +++ b/Doc/library/selectors.rst @@ -98,6 +98,10 @@ below: :class:`BaseSelector` and its concrete implementations support the :term:`context manager` protocol. + .. attribute:: resolution + + Resolution of the selector in seconds. + .. method:: register(fileobj, events, data=None) Register a file object for selection, monitoring it for I/O events. diff --git a/Lib/selectors.py b/Lib/selectors.py index cd8b29e4cc2..b1b530afcb4 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -5,7 +5,7 @@ This module allows high-level and efficient I/O multiplexing, built upon the """ -from abc import ABCMeta, abstractmethod +from abc import ABCMeta, abstractmethod, abstractproperty from collections import namedtuple, Mapping import functools import select @@ -82,6 +82,11 @@ class BaseSelector(metaclass=ABCMeta): performant implementation on the current platform. """ + @abstractproperty + def resolution(self): + """Resolution of the selector in seconds""" + return None + @abstractmethod def register(self, fileobj, events, data=None): """Register a file object. @@ -283,6 +288,10 @@ class SelectSelector(_BaseSelectorImpl): self._readers = set() self._writers = set() + @property + def resolution(self): + return 1e-6 + def register(self, fileobj, events, data=None): key = super().register(fileobj, events, data) if events & EVENT_READ: @@ -335,6 +344,10 @@ if hasattr(select, 'poll'): super().__init__() self._poll = select.poll() + @property + def resolution(self): + return 1e-3 + def register(self, fileobj, events, data=None): key = super().register(fileobj, events, data) poll_events = 0 @@ -385,6 +398,10 @@ if hasattr(select, 'epoll'): super().__init__() self._epoll = select.epoll() + @property + def resolution(self): + return 1e-3 + def fileno(self): return self._epoll.fileno() @@ -445,6 +462,10 @@ if hasattr(select, 'kqueue'): super().__init__() self._kqueue = select.kqueue() + @property + def resolution(self): + return 1e-9 + def fileno(self): return self._kqueue.fileno() diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py index 529290460f4..f7e84b7e99c 100644 --- a/Lib/test/test_selectors.py +++ b/Lib/test/test_selectors.py @@ -363,6 +363,11 @@ class BaseSelectorTestCase(unittest.TestCase): self.assertFalse(s.select(2)) self.assertLess(time() - t, 2.5) + def test_resolution(self): + s = self.SELECTOR() + self.assertIsInstance(s.resolution, (int, float)) + self.assertGreater(s.resolution, 0.0) + class ScalableSelectorMixIn: diff --git a/Misc/NEWS b/Misc/NEWS index c298260c5bb..2b1200e1aa0 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,8 @@ Core and Builtins Library ------- +- Issue #20311: selectors: Add a resolution attribute to BaseSelector. + - Issue #20189: unittest.mock now no longer assumes that any object for which it could get an inspect.Signature is a callable written in Python. Fix courtesy of Michael Foord.