Charles-François Natali added the comment:
> Antoine Pitrou added the comment:
>
> FWIW, I think the "ideal" solution would be for keys() (*) to return a
> read-only Mapping implementation, allowing for file object lookup (using
> __getitem__) as well as iteration on SelectorKeys (using __iter__) and
> fast emptiness checking (using __len__).
Thanks, I think that's a great idea.
I'm attaching a patch updating yours with the following:
- asyncio/test_asyncio update
- selectors' documentation update
IMO, it really offers both a compact, easy to use and performant API.
(Note: the mapping doesn't really have to be recreated upon each
get_map() call and could be kept as a private member, but IMO that's
not a performance issue).
----------
Added file: http://bugs.python.org/file32360/selectors_map-1.patch
_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue19172>
_______________________________________
diff -r eb1edc9e3722 Doc/library/selectors.rst
--- a/Doc/library/selectors.rst Fri Oct 25 17:56:00 2013 +0200
+++ b/Doc/library/selectors.rst Fri Oct 25 19:47:35 2013 +0200
@@ -157,12 +157,13 @@
This must be called to make sure that any underlying resource is freed.
The selector shall not be used once it has been closed.
- .. method:: get_key(fileobj)
+ .. method:: get_map()
- Return the key associated to a registered file object.
+ Return a mapping of file objects to selector keys.
- This returns the :class:`SelectorKey` instance associated to this file
- object, or raises :exc:`KeyError` if the file object is not registered.
+ This returns a :class:`~collections.abc.Mapping` instance mapping
+ registered file objects to their associated :class:`SelectorKey`
+ instance.
.. class:: DefaultSelector()
diff -r eb1edc9e3722 Lib/asyncio/selector_events.py
--- a/Lib/asyncio/selector_events.py Fri Oct 25 17:56:00 2013 +0200
+++ b/Lib/asyncio/selector_events.py Fri Oct 25 19:47:35 2013 +0200
@@ -122,7 +122,7 @@
"""Add a reader callback."""
handle = events.make_handle(callback, args)
try:
- key = self._selector.get_key(fd)
+ key = self._selector.get_map()[fd]
except KeyError:
self._selector.register(fd, selectors.EVENT_READ,
(handle, None))
@@ -136,7 +136,7 @@
def remove_reader(self, fd):
"""Remove a reader callback."""
try:
- key = self._selector.get_key(fd)
+ key = self._selector.get_map()[fd]
except KeyError:
return False
else:
@@ -157,7 +157,7 @@
"""Add a writer callback.."""
handle = events.make_handle(callback, args)
try:
- key = self._selector.get_key(fd)
+ key = self._selector.get_map()[fd]
except KeyError:
self._selector.register(fd, selectors.EVENT_WRITE,
(None, handle))
@@ -171,7 +171,7 @@
def remove_writer(self, fd):
"""Remove a writer callback."""
try:
- key = self._selector.get_key(fd)
+ key = self._selector.get_map()[fd]
except KeyError:
return False
else:
diff -r eb1edc9e3722 Lib/selectors.py
--- a/Lib/selectors.py Fri Oct 25 17:56:00 2013 +0200
+++ b/Lib/selectors.py Fri Oct 25 19:47:35 2013 +0200
@@ -6,7 +6,7 @@
from abc import ABCMeta, abstractmethod
-from collections import namedtuple
+from collections import namedtuple, Mapping
import functools
import select
import sys
@@ -44,6 +44,25 @@
selected event mask and attached data."""
+class _SelectorMapping(Mapping):
+ """Mapping of file objects to selector keys."""
+
+ def __init__(self, selector):
+ self._fd_to_key = selector._fd_to_key
+
+ def __len__(self):
+ return len(self._fd_to_key)
+
+ def __getitem__(self, fileobj):
+ try:
+ return self._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._fd_to_key)
+
+
class BaseSelector(metaclass=ABCMeta):
"""Base selector class.
@@ -151,16 +170,9 @@
"""
self._fd_to_key.clear()
- def get_key(self, fileobj):
- """Return the key associated to a registered file object.
-
- Returns:
- SelectorKey for this file object
- """
- try:
- return self._fd_to_key[_fileobj_to_fd(fileobj)]
- 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 _SelectorMapping(self)
def __enter__(self):
return self
diff -r eb1edc9e3722 Lib/test/test_asyncio/test_selector_events.py
--- a/Lib/test/test_asyncio/test_selector_events.py Fri Oct 25 17:56:00
2013 +0200
+++ b/Lib/test/test_asyncio/test_selector_events.py Fri Oct 25 19:47:35
2013 +0200
@@ -396,7 +396,7 @@
self.assertIs(err, f.exception())
def test_add_reader(self):
- self.loop._selector.get_key.side_effect = KeyError
+ self.loop._selector.get_map.return_value = {}
cb = lambda: True
self.loop.add_reader(1, cb)
@@ -410,8 +410,8 @@
def test_add_reader_existing(self):
reader = unittest.mock.Mock()
writer = unittest.mock.Mock()
- self.loop._selector.get_key.return_value = selectors.SelectorKey(
- 1, 1, selectors.EVENT_WRITE, (reader, writer))
+ self.loop._selector.get_map.return_value = {1: selectors.SelectorKey(
+ 1, 1, selectors.EVENT_WRITE, (reader, writer))}
cb = lambda: True
self.loop.add_reader(1, cb)
@@ -426,8 +426,8 @@
def test_add_reader_existing_writer(self):
writer = unittest.mock.Mock()
- self.loop._selector.get_key.return_value = selectors.SelectorKey(
- 1, 1, selectors.EVENT_WRITE, (None, writer))
+ self.loop._selector.get_map.return_value = {1: selectors.SelectorKey(
+ 1, 1, selectors.EVENT_WRITE, (None, writer))}
cb = lambda: True
self.loop.add_reader(1, cb)
@@ -440,8 +440,8 @@
self.assertEqual(writer, w)
def test_remove_reader(self):
- self.loop._selector.get_key.return_value = selectors.SelectorKey(
- 1, 1, selectors.EVENT_READ, (None, None))
+ self.loop._selector.get_map.return_value = {1: selectors.SelectorKey(
+ 1, 1, selectors.EVENT_READ, (None, None))}
self.assertFalse(self.loop.remove_reader(1))
self.assertTrue(self.loop._selector.unregister.called)
@@ -449,9 +449,9 @@
def test_remove_reader_read_write(self):
reader = unittest.mock.Mock()
writer = unittest.mock.Mock()
- self.loop._selector.get_key.return_value = selectors.SelectorKey(
+ self.loop._selector.get_map.return_value = {1: selectors.SelectorKey(
1, 1, selectors.EVENT_READ | selectors.EVENT_WRITE,
- (reader, writer))
+ (reader, writer))}
self.assertTrue(
self.loop.remove_reader(1))
@@ -461,12 +461,12 @@
self.loop._selector.modify.call_args[0])
def test_remove_reader_unknown(self):
- self.loop._selector.get_key.side_effect = KeyError
+ self.loop._selector.get_map.return_value = {}
self.assertFalse(
self.loop.remove_reader(1))
def test_add_writer(self):
- self.loop._selector.get_key.side_effect = KeyError
+ self.loop._selector.get_map.return_value = {}
cb = lambda: True
self.loop.add_writer(1, cb)
@@ -480,8 +480,8 @@
def test_add_writer_existing(self):
reader = unittest.mock.Mock()
writer = unittest.mock.Mock()
- self.loop._selector.get_key.return_value = selectors.SelectorKey(
- 1, 1, selectors.EVENT_READ, (reader, writer))
+ self.loop._selector.get_map.return_value = {1: selectors.SelectorKey(
+ 1, 1, selectors.EVENT_READ, (reader, writer))}
cb = lambda: True
self.loop.add_writer(1, cb)
@@ -495,8 +495,8 @@
self.assertEqual(cb, w._callback)
def test_remove_writer(self):
- self.loop._selector.get_key.return_value = selectors.SelectorKey(
- 1, 1, selectors.EVENT_WRITE, (None, None))
+ self.loop._selector.get_map.return_value = {1: selectors.SelectorKey(
+ 1, 1, selectors.EVENT_WRITE, (None, None))}
self.assertFalse(self.loop.remove_writer(1))
self.assertTrue(self.loop._selector.unregister.called)
@@ -504,9 +504,9 @@
def test_remove_writer_read_write(self):
reader = unittest.mock.Mock()
writer = unittest.mock.Mock()
- self.loop._selector.get_key.return_value = selectors.SelectorKey(
+ self.loop._selector.get_map.return_value = {1: selectors.SelectorKey(
1, 1, selectors.EVENT_READ | selectors.EVENT_WRITE,
- (reader, writer))
+ (reader, writer))}
self.assertTrue(
self.loop.remove_writer(1))
@@ -516,7 +516,7 @@
self.loop._selector.modify.call_args[0])
def test_remove_writer_unknown(self):
- self.loop._selector.get_key.side_effect = KeyError
+ self.loop._selector.get_map.return_value = {}
self.assertFalse(
self.loop.remove_writer(1))
diff -r eb1edc9e3722 Lib/test/test_asyncio/test_selectors.py
--- a/Lib/test/test_asyncio/test_selectors.py Fri Oct 25 17:56:00 2013 +0200
+++ b/Lib/test/test_asyncio/test_selectors.py Fri Oct 25 19:47:35 2013 +0200
@@ -85,7 +85,7 @@
self.assertNotEqual(key.events, key2.events)
self.assertEqual(
selectors.SelectorKey(fobj, 10, selectors.EVENT_WRITE, None),
- s.get_key(fobj))
+ s.get_map()[fobj])
def test_modify_data(self):
fobj = unittest.mock.Mock()
@@ -101,7 +101,7 @@
self.assertNotEqual(key.data, key2.data)
self.assertEqual(
selectors.SelectorKey(fobj, 10, selectors.EVENT_READ, d2),
- s.get_key(fobj))
+ s.get_map()[fobj])
def test_modify_same(self):
fobj = unittest.mock.Mock()
diff -r eb1edc9e3722 Lib/test/test_selectors.py
--- a/Lib/test/test_selectors.py Fri Oct 25 17:56:00 2013 +0200
+++ b/Lib/test/test_selectors.py Fri Oct 25 19:47:35 2013 +0200
@@ -106,7 +106,7 @@
# modify events
key2 = s.modify(rd, selectors.EVENT_WRITE)
self.assertNotEqual(key.events, key2.events)
- self.assertEqual(key2, s.get_key(rd))
+ self.assertEqual(key2, s.get_map()[rd])
s.unregister(rd)
@@ -118,7 +118,7 @@
key2 = s.modify(rd, selectors.EVENT_READ, d2)
self.assertEqual(key.events, key2.events)
self.assertNotEqual(key.data, key2.data)
- self.assertEqual(key2, s.get_key(rd))
+ self.assertEqual(key2, s.get_map()[rd])
self.assertEqual(key2.data, d2)
# modify unknown file obj
@@ -136,10 +136,12 @@
s.register(wr, selectors.EVENT_WRITE)
s.close()
- self.assertRaises(KeyError, s.get_key, rd)
- self.assertRaises(KeyError, s.get_key, wr)
+ with self.assertRaises(KeyError):
+ s.get_map()[rd]
+ with self.assertRaises(KeyError):
+ s.get_map()[wr]
- def test_get_key(self):
+ def test_get_map(self):
s = self.SELECTOR()
self.addCleanup(s.close)
@@ -147,11 +149,24 @@
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.assertEqual(key, s.get_key(rd))
+ 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
- self.assertRaises(KeyError, s.get_key, 999999)
+ with self.assertRaises(KeyError):
+ keys[999999]
+
+ # Read-only mapping
+ with self.assertRaises(TypeError):
+ del keys[rd]
def test_select(self):
s = self.SELECTOR()
@@ -185,8 +200,8 @@
sel.register(rd, selectors.EVENT_READ)
sel.register(wr, selectors.EVENT_WRITE)
- self.assertRaises(KeyError, s.get_key, rd)
- self.assertRaises(KeyError, s.get_key, wr)
+ self.assertNotIn(rd, s.get_map())
+ self.assertNotIn(wr, s.get_map())
def test_fileno(self):
s = self.SELECTOR()
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com