diff -r 268259370a01 Lib/selectors.py --- a/Lib/selectors.py Mon Nov 04 13:18:19 2013 -0800 +++ b/Lib/selectors.py Tue Nov 05 01:02:59 2013 +0100 @@ -138,11 +138,14 @@ key = self._fd_to_key[_fileobj_to_fd(fileobj)] except KeyError: raise KeyError("{!r} is not registered".format(fileobj)) from None - if events != key.events or data != key.data: - # TODO: If only the data changed, use a shortcut that only - # updates the data. + if events != key.events: self.unregister(fileobj) return 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 else: return key diff -r 268259370a01 Lib/test/test_selectors.py --- a/Lib/test/test_selectors.py Mon Nov 04 13:18:19 2013 -0800 +++ b/Lib/test/test_selectors.py Tue Nov 05 01:02:59 2013 +0100 @@ -6,6 +6,7 @@ from test import support from time import sleep import unittest +from unittest.mock import Mock try: from time import monotonic as time except ImportError: @@ -48,6 +49,64 @@ class BaseSelectorTestCase(unittest.TestCase): + def test_selector_mapping_len(self): + s = self.SELECTOR() + self.addCleanup(s.close) + + rd, wr = socketpair() + self.addCleanup(rd.close) + self.addCleanup(wr.close) + + map = selectors._SelectorMapping(s) + self.assertTrue(map.__len__() == 0) + key = s.register(rd, selectors.EVENT_READ, "data") + self.assertTrue(len(map) == 1) + + def test_selector_mapping_getitem(self): + s = self.SELECTOR() + self.addCleanup(s.close) + + rd, wr = socketpair() + self.addCleanup(rd.close) + self.addCleanup(wr.close) + + map = selectors._SelectorMapping(s) + key = s.register(rd, selectors.EVENT_READ, "data") + attended = selectors.SelectorKey( + rd, rd.fileno(), selectors.EVENT_READ, "data") + self.assertEqual(attended, map.__getitem__(rd)) + + def test_selector_mapping_getitem_key_error(self): + s = self.SELECTOR() + self.addCleanup(s.close) + + rd, wr = socketpair() + self.addCleanup(rd.close) + self.addCleanup(wr.close) + + map = selectors._SelectorMapping(s) + s.register(rd, selectors.EVENT_READ, None) + self.assertRaises(KeyError, map.__getitem__, rd.fileno() + 1) + + def test_selector_mapping_iter(self): + s = self.SELECTOR() + self.addCleanup(s.close) + + rd, wr = socketpair() + self.addCleanup(rd.close) + self.addCleanup(wr.close) + + map = selectors._SelectorMapping(s) + key = s.register(rd, selectors.EVENT_READ, "data") + counter = 0 + for fileno in map.__iter__(): + self.assertEqual(rd.fileno(), fileno) + counter += 1 + self.assertEqual(1, counter) + + for idx in map: + self.assertIs(rd, map[idx].fileobj) + def test_register(self): s = self.SELECTOR() self.addCleanup(s.close) @@ -113,6 +172,7 @@ # modify data d1 = object() d2 = object() + d3 = object() key = s.register(rd, selectors.EVENT_READ, d1) key2 = s.modify(rd, selectors.EVENT_READ, d2) @@ -121,6 +181,13 @@ self.assertEqual(key2, s.get_key(rd)) self.assertEqual(key2.data, d2) + # modify data uses shortcut + s.unregister = Mock() + s.register = Mock() + s.modify(rd, selectors.EVENT_READ, d3) + self.assertFalse(s.unregister.called) + self.assertFalse(s.register.called) + # modify unknown file obj self.assertRaises(KeyError, s.modify, 999999, selectors.EVENT_READ)