Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add a new is_readable method to SocketType (fix #760) #1137

Merged
merged 2 commits into from
Jul 6, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/source/reference-io.rst
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,10 @@ Socket objects
left in an unknown state – possibly open, and possibly
closed. The only reasonable thing to do is to close it.

.. method:: is_readable

Check whether the socket is readable or not.

.. method:: sendfile

`Not implemented yet! <https://github.com/python-trio/trio/issues/45>`__
Expand Down
3 changes: 3 additions & 0 deletions newsfragments/760.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
We added a new ``is_readable`` method to the ``trio.socket.SocketType``
object that allows you to check whether a socket is ready to be read
or not.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The double-backticks are raw code; since we're referring to objects that have entries in the documentation, we can use single-backticks to link directly:

Trio sockets have a new method `~trio.socket.SocketType.is_readable`, that allows you
to check whether a socket is readable. This is useful for HTTP/1.1 clients.

(The tilde is a shorthand that means "make a link to trio.socket.SocketType.is_readable, but just render it as is_readable".)

12 changes: 11 additions & 1 deletion trio/_socket.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os as _os
import sys as _sys
import select
import socket as _stdlib_socket
from functools import wraps as _wraps

Expand Down Expand Up @@ -289,7 +290,7 @@ def socket(

def _sniff_sockopts_for_fileno(family, type, proto, fileno):
"""Correct SOCKOPTS for given fileno, falling back to provided values.

"""
# Wrap the raw fileno into a Python socket object
# This object might have the wrong metadata, but it lets us easily call getsockopt
Expand Down Expand Up @@ -478,6 +479,15 @@ def shutdown(self, flag):
if flag in [_stdlib_socket.SHUT_WR, _stdlib_socket.SHUT_RDWR]:
self._did_shutdown_SHUT_WR = True

def is_readable(self):
# use select.select on Windows, and select.poll everywhere else
if _sys.platform == "win32":
rready, _, _ = select.select([self._sock], [], [], 0)
return bool(rready)
p = select.poll()
p.register(self._sock, select.POLLIN)
return bool(p.poll(0))

async def wait_writable(self):
await _core.wait_writable(self._sock)

Expand Down
17 changes: 17 additions & 0 deletions trio/tests/test_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,23 @@ async def test_SocketType_simple_server(address, socket_type):
assert await client.recv(1) == b"x"


async def test_SocketTupe_is_readable():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: "SocketTupe" should be "SocketType"

listener = tsocket.socket(tsocket.AF_INET)
client = tsocket.socket(tsocket.AF_INET)
with listener, client:
await listener.bind(('127.0.0.1', 0))
listener.listen(20)
addr = listener.getsockname()[:2]
async with _core.open_nursery() as nursery:
nursery.start_soon(client.connect, addr)
server, client_addr = await listener.accept()
with server:
assert not client.is_readable()
await server.send(b"x")
assert client.is_readable()
assert await client.recv(1) == b"x"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified a lot by using socketpair, which directly returns a pair of connected sockets. Something like:

a, b = trio.socket.socketpair()
with a, b:
    assert not a.is_readable()
    await b.send(b"x")
    await _core.wait_readable(a)
    assert a.is_readable()
    assert await a.recv(1) == b"x"
    assert not a.is_readable()

I also added a call to wait_readable, just in case the operating system needs a moment to notice that writing to b makes a readable.



# On some macOS systems, getaddrinfo likes to return V4-mapped addresses even
# when we *don't* pass AI_V4MAPPED.
# https://github.com/python-trio/trio/issues/580
Expand Down