Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
b3330a0a
Commit
b3330a0a
authored
Dec 01, 2013
by
Charles-François Natali
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #19842: Refactor BaseSelector to make it an actual usable ABC.
parent
be0708f0
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
86 additions
and
47 deletions
+86
-47
Lib/asyncio/test_utils.py
Lib/asyncio/test_utils.py
+14
-0
Lib/selectors.py
Lib/selectors.py
+68
-44
Lib/test/test_telnetlib.py
Lib/test/test_telnetlib.py
+4
-3
No files found.
Lib/asyncio/test_utils.py
View file @
b3330a0a
...
@@ -142,9 +142,23 @@ def make_test_protocol(base):
...
@@ -142,9 +142,23 @@ def make_test_protocol(base):
class
TestSelector
(
selectors
.
BaseSelector
):
class
TestSelector
(
selectors
.
BaseSelector
):
def
__init__
(
self
):
self
.
keys
=
{}
def
register
(
self
,
fileobj
,
events
,
data
=
None
):
key
=
selectors
.
SelectorKey
(
fileobj
,
0
,
events
,
data
)
self
.
keys
[
fileobj
]
=
key
return
key
def
unregister
(
self
,
fileobj
):
return
self
.
keys
.
pop
(
fileobj
)
def
select
(
self
,
timeout
):
def
select
(
self
,
timeout
):
return
[]
return
[]
def
get_map
(
self
):
return
self
.
keys
class
TestLoop
(
base_events
.
BaseEventLoop
):
class
TestLoop
(
base_events
.
BaseEventLoop
):
"""Loop for unittests.
"""Loop for unittests.
...
...
Lib/selectors.py
View file @
b3330a0a
...
@@ -64,7 +64,7 @@ class _SelectorMapping(Mapping):
...
@@ -64,7 +64,7 @@ class _SelectorMapping(Mapping):
class
BaseSelector
(
metaclass
=
ABCMeta
):
class
BaseSelector
(
metaclass
=
ABCMeta
):
"""
Base selector
class.
"""
Selector abstract base
class.
A selector supports registering file objects to be monitored for specific
A selector supports registering file objects to be monitored for specific
I/O events.
I/O events.
...
@@ -78,12 +78,7 @@ class BaseSelector(metaclass=ABCMeta):
...
@@ -78,12 +78,7 @@ class BaseSelector(metaclass=ABCMeta):
performant implementation on the current platform.
performant implementation on the current platform.
"""
"""
def
__init__
(
self
):
@
abstractmethod
# 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
):
def
register
(
self
,
fileobj
,
events
,
data
=
None
):
"""Register a file object.
"""Register a file object.
...
@@ -95,18 +90,9 @@ class BaseSelector(metaclass=ABCMeta):
...
@@ -95,18 +90,9 @@ class BaseSelector(metaclass=ABCMeta):
Returns:
Returns:
SelectorKey instance
SelectorKey instance
"""
"""
if
(
not
events
)
or
(
events
&
~
(
EVENT_READ
|
EVENT_WRITE
)):
raise
NotImplementedError
raise
ValueError
(
"Invalid events: {!r}"
.
format
(
events
))
key
=
SelectorKey
(
fileobj
,
_fileobj_to_fd
(
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
return
key
@
abstractmethod
def
unregister
(
self
,
fileobj
):
def
unregister
(
self
,
fileobj
):
"""Unregister a file object.
"""Unregister a file object.
...
@@ -116,11 +102,7 @@ class BaseSelector(metaclass=ABCMeta):
...
@@ -116,11 +102,7 @@ class BaseSelector(metaclass=ABCMeta):
Returns:
Returns:
SelectorKey instance
SelectorKey instance
"""
"""
try
:
raise
NotImplementedError
key
=
self
.
_fd_to_key
.
pop
(
_fileobj_to_fd
(
fileobj
))
except
KeyError
:
raise
KeyError
(
"{!r} is not registered"
.
format
(
fileobj
))
from
None
return
key
def
modify
(
self
,
fileobj
,
events
,
data
=
None
):
def
modify
(
self
,
fileobj
,
events
,
data
=
None
):
"""Change a registered file object monitored events or attached data.
"""Change a registered file object monitored events or attached data.
...
@@ -133,19 +115,8 @@ class BaseSelector(metaclass=ABCMeta):
...
@@ -133,19 +115,8 @@ class BaseSelector(metaclass=ABCMeta):
Returns:
Returns:
SelectorKey instance
SelectorKey instance
"""
"""
# TODO: Subclasses can probably optimize this even further.
self
.
unregister
(
fileobj
)
try
:
return
self
.
register
(
fileobj
,
events
,
data
)
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
:
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
@
abstractmethod
@
abstractmethod
def
select
(
self
,
timeout
=
None
):
def
select
(
self
,
timeout
=
None
):
...
@@ -164,14 +135,14 @@ class BaseSelector(metaclass=ABCMeta):
...
@@ -164,14 +135,14 @@ class BaseSelector(metaclass=ABCMeta):
list of (key, events) for ready file objects
list of (key, events) for ready file objects
`events` is a bitwise mask of EVENT_READ|EVENT_WRITE
`events` is a bitwise mask of EVENT_READ|EVENT_WRITE
"""
"""
raise
NotImplementedError
()
raise
NotImplementedError
def
close
(
self
):
def
close
(
self
):
"""Close the selector.
"""Close the selector.
This must be called to make sure that any underlying resource is freed.
This must be called to make sure that any underlying resource is freed.
"""
"""
self
.
_fd_to_key
.
clear
()
pass
def
get_key
(
self
,
fileobj
):
def
get_key
(
self
,
fileobj
):
"""Return the key associated to a registered file object.
"""Return the key associated to a registered file object.
...
@@ -179,14 +150,16 @@ class BaseSelector(metaclass=ABCMeta):
...
@@ -179,14 +150,16 @@ class BaseSelector(metaclass=ABCMeta):
Returns:
Returns:
SelectorKey for this file object
SelectorKey for this file object
"""
"""
mapping
=
self
.
get_map
()
try
:
try
:
return
self
.
_fd_to_key
[
_fileobj_to_fd
(
fileobj
)
]
return
mapping
[
fileobj
]
except
KeyError
:
except
KeyError
:
raise
KeyError
(
"{!r} is not registered"
.
format
(
fileobj
))
from
None
raise
KeyError
(
"{!r} is not registered"
.
format
(
fileobj
))
from
None
@
abstractmethod
def
get_map
(
self
):
def
get_map
(
self
):
"""Return a mapping of file objects to selector keys."""
"""Return a mapping of file objects to selector keys."""
r
eturn
self
.
_map
r
aise
NotImplementedError
def
__enter__
(
self
):
def
__enter__
(
self
):
return
self
return
self
...
@@ -194,6 +167,57 @@ class BaseSelector(metaclass=ABCMeta):
...
@@ -194,6 +167,57 @@ class BaseSelector(metaclass=ABCMeta):
def
__exit__
(
self
,
*
args
):
def
__exit__
(
self
,
*
args
):
self
.
close
()
self
.
close
()
class
_BaseSelectorImpl
(
BaseSelector
):
"""Base selector implementation."""
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
):
if
(
not
events
)
or
(
events
&
~
(
EVENT_READ
|
EVENT_WRITE
)):
raise
ValueError
(
"Invalid events: {!r}"
.
format
(
events
))
key
=
SelectorKey
(
fileobj
,
_fileobj_to_fd
(
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
return
key
def
unregister
(
self
,
fileobj
):
try
:
key
=
self
.
_fd_to_key
.
pop
(
_fileobj_to_fd
(
fileobj
))
except
KeyError
:
raise
KeyError
(
"{!r} is not registered"
.
format
(
fileobj
))
from
None
return
key
def
modify
(
self
,
fileobj
,
events
,
data
=
None
):
# TODO: Subclasses can probably optimize this even further.
try
:
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
:
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
.
_fd_to_key
.
clear
()
def
get_map
(
self
):
return
self
.
_map
def
_key_from_fd
(
self
,
fd
):
def
_key_from_fd
(
self
,
fd
):
"""Return the key associated to a given file descriptor.
"""Return the key associated to a given file descriptor.
...
@@ -209,7 +233,7 @@ class BaseSelector(metaclass=ABCMeta):
...
@@ -209,7 +233,7 @@ class BaseSelector(metaclass=ABCMeta):
return
None
return
None
class
SelectSelector
(
BaseSelector
):
class
SelectSelector
(
_BaseSelectorImpl
):
"""Select-based selector."""
"""Select-based selector."""
def
__init__
(
self
):
def
__init__
(
self
):
...
@@ -262,7 +286,7 @@ class SelectSelector(BaseSelector):
...
@@ -262,7 +286,7 @@ class SelectSelector(BaseSelector):
if
hasattr
(
select
,
'poll'
):
if
hasattr
(
select
,
'poll'
):
class
PollSelector
(
BaseSelector
):
class
PollSelector
(
_BaseSelectorImpl
):
"""Poll-based selector."""
"""Poll-based selector."""
def
__init__
(
self
):
def
__init__
(
self
):
...
@@ -306,7 +330,7 @@ if hasattr(select, 'poll'):
...
@@ -306,7 +330,7 @@ if hasattr(select, 'poll'):
if
hasattr
(
select
,
'epoll'
):
if
hasattr
(
select
,
'epoll'
):
class
EpollSelector
(
BaseSelector
):
class
EpollSelector
(
_BaseSelectorImpl
):
"""Epoll-based selector."""
"""Epoll-based selector."""
def
__init__
(
self
):
def
__init__
(
self
):
...
@@ -358,7 +382,7 @@ if hasattr(select, 'epoll'):
...
@@ -358,7 +382,7 @@ if hasattr(select, 'epoll'):
if
hasattr
(
select
,
'kqueue'
):
if
hasattr
(
select
,
'kqueue'
):
class
KqueueSelector
(
BaseSelector
):
class
KqueueSelector
(
_BaseSelectorImpl
):
"""Kqueue-based selector."""
"""Kqueue-based selector."""
def
__init__
(
self
):
def
__init__
(
self
):
...
...
Lib/test/test_telnetlib.py
View file @
b3330a0a
...
@@ -114,7 +114,6 @@ class TelnetAlike(telnetlib.Telnet):
...
@@ -114,7 +114,6 @@ class TelnetAlike(telnetlib.Telnet):
class
MockSelector
(
selectors
.
BaseSelector
):
class
MockSelector
(
selectors
.
BaseSelector
):
def
__init__
(
self
):
def
__init__
(
self
):
super
().
__init__
()
self
.
keys
=
{}
self
.
keys
=
{}
def
register
(
self
,
fileobj
,
events
,
data
=
None
):
def
register
(
self
,
fileobj
,
events
,
data
=
None
):
...
@@ -123,8 +122,7 @@ class MockSelector(selectors.BaseSelector):
...
@@ -123,8 +122,7 @@ class MockSelector(selectors.BaseSelector):
return
key
return
key
def
unregister
(
self
,
fileobj
):
def
unregister
(
self
,
fileobj
):
key
=
self
.
keys
.
pop
(
fileobj
)
return
self
.
keys
.
pop
(
fileobj
)
return
key
def
select
(
self
,
timeout
=
None
):
def
select
(
self
,
timeout
=
None
):
block
=
False
block
=
False
...
@@ -137,6 +135,9 @@ class MockSelector(selectors.BaseSelector):
...
@@ -137,6 +135,9 @@ class MockSelector(selectors.BaseSelector):
else
:
else
:
return
[(
key
,
key
.
events
)
for
key
in
self
.
keys
.
values
()]
return
[(
key
,
key
.
events
)
for
key
in
self
.
keys
.
values
()]
def
get_map
(
self
):
return
self
.
keys
@
contextlib
.
contextmanager
@
contextlib
.
contextmanager
def
test_socket
(
reads
):
def
test_socket
(
reads
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment