]> granicus.if.org Git - python/commitdiff
Issue #19172: Add a get_map() method to selectors.
authorCharles-François Natali <cf.natali@gmail.com>
Wed, 30 Oct 2013 19:31:04 +0000 (20:31 +0100)
committerCharles-François Natali <cf.natali@gmail.com>
Wed, 30 Oct 2013 19:31:04 +0000 (20:31 +0100)
Doc/library/selectors.rst
Lib/selectors.py
Lib/test/test_selectors.py

index ece5e7d81c97fe909d413c5a9d52f1b8635eb7b5..e3ebd25b02047125a7b1c41891f47ee27a8f9371 100644 (file)
@@ -164,6 +164,14 @@ below:
       This returns the :class:`SelectorKey` instance associated to this file
       object, or raises :exc:`KeyError` if the file object is not registered.
 
+   .. method:: get_map()
+
+      Return a mapping of file objects to selector keys.
+
+      This returns a :class:`~collections.abc.Mapping` instance mapping
+      registered file objects to their associated :class:`SelectorKey`
+      instance.
+
 
 .. class:: DefaultSelector()
 
index fe027f09b07a58db02ba56efee1d4b609efd12d4..3e6c2adcb58a29fc69c5f0b1cba13bda6a50d849 100644 (file)
@@ -6,7 +6,7 @@ This module allows high-level and efficient I/O multiplexing, built upon the
 
 
 from abc import ABCMeta, abstractmethod
-from collections import namedtuple
+from collections import namedtuple, Mapping
 import functools
 import select
 import sys
@@ -44,6 +44,25 @@ SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data'])
 selected event mask and attached data."""
 
 
+class _SelectorMapping(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:
+            return self._selector._fd_to_key[_fileobj_to_fd(fileobj)]
+        except KeyError:
+            raise KeyError("{!r} is not registered".format(fileobj)) from None
+
+    def __iter__(self):
+        return iter(self._selector._fd_to_key)
+
+
 class BaseSelector(metaclass=ABCMeta):
     """Base selector class.
 
@@ -62,6 +81,8 @@ class BaseSelector(metaclass=ABCMeta):
     def __init__(self):
         # this maps file descriptors to keys
         self._fd_to_key = {}
+        # read-only mapping returned by get_map()
+        self._map = _SelectorMapping(self)
 
     def register(self, fileobj, events, data=None):
         """Register a file object.
@@ -162,6 +183,10 @@ class BaseSelector(metaclass=ABCMeta):
         except KeyError:
             raise KeyError("{!r} is not registered".format(fileobj)) from None
 
+    def get_map(self):
+        """Return a mapping of file objects to selector keys."""
+        return self._map
+
     def __enter__(self):
         return self
 
index a2ffd62eb9641650d36a3b2c8eebb86805115191..fd0481d83f51f2de9ae7b4c16cab2fd8a90a0d16 100644 (file)
@@ -153,6 +153,33 @@ class BaseSelectorTestCase(unittest.TestCase):
         # unknown file obj
         self.assertRaises(KeyError, s.get_key, 999999)
 
+    def test_get_map(self):
+        s = self.SELECTOR()
+        self.addCleanup(s.close)
+
+        rd, wr = socketpair()
+        self.addCleanup(rd.close)
+        self.addCleanup(wr.close)
+
+        keys = s.get_map()
+        self.assertFalse(keys)
+        self.assertEqual(len(keys), 0)
+        self.assertEqual(list(keys), [])
+        key = s.register(rd, selectors.EVENT_READ, "data")
+        self.assertIn(rd, keys)
+        self.assertEqual(key, keys[rd])
+        self.assertEqual(len(keys), 1)
+        self.assertEqual(list(keys), [rd.fileno()])
+        self.assertEqual(list(keys.values()), [key])
+
+        # unknown file obj
+        with self.assertRaises(KeyError):
+            keys[999999]
+
+        # Read-only mapping
+        with self.assertRaises(TypeError):
+            del keys[rd]
+
     def test_select(self):
         s = self.SELECTOR()
         self.addCleanup(s.close)