Skip to content

Commit

Permalink
Merge pull request python-trio#246 from njsmith/hide-SocketType
Browse files Browse the repository at this point in the history
Hide the trio.socket.SocketType class
  • Loading branch information
njsmith committed Jul 25, 2017
2 parents d303f06 + d662056 commit a1ad278
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 111 deletions.
7 changes: 4 additions & 3 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
import os
import sys
sys.path.insert(0, os.path.abspath('.'))

# Warn about all references to unknown targets
nitpicky = True
Expand Down Expand Up @@ -51,6 +51,7 @@ def setup(app):
'sphinx.ext.coverage',
'sphinx.ext.napoleon',
'sphinxcontrib_trio',
'local_customization',
]

intersphinx_mapping = {
Expand Down
25 changes: 25 additions & 0 deletions docs/source/local_customization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from docutils.parsers.rst import directives
from sphinx import addnodes
from sphinx.domains.python import PyClasslike
from sphinx.ext.autodoc import (
FunctionDocumenter, MethodDocumenter, ClassLevelDocumenter, Options,
)

"""
.. interface:: The nursery interface
.. attribute:: blahblah
"""

class Interface(PyClasslike):
def handle_signature(self, sig, signode):
signode += addnodes.desc_name(sig, sig)
return sig, ""

def get_index_text(self, modname, name_cls):
return "{} (interface in {})".format(name_cls[0], modname)

def setup(app):
app.add_directive_to_domain("py", "interface", Interface)
18 changes: 7 additions & 11 deletions docs/source/reference-core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ kind of issue looks like in real life, consider this function::
async def recv_exactly(sock, nbytes):
data = bytearray()
while nbytes > 0:
# SocketType.recv() reads up to 'nbytes' bytes each time
# recv() reads up to 'nbytes' bytes each time
chunk += await sock.recv(nbytes)
if not chunk:
raise RuntimeError("socket unexpected closed")
Expand Down Expand Up @@ -420,8 +420,8 @@ Of course, if you really want to make another blocking call in your
cleanup handler, trio will let you; it's trying to prevent you from
accidentally shooting yourself in the foot. Intentional foot-shooting
is no problem (or at least – it's not trio's problem). To do this,
create a new scope, and set its :attr:`shield` attribute to
:data:`True`::
create a new scope, and set its :attr:`~The cancel scope interface.shield`
attribute to :data:`True`::

with trio.move_on_after(TIMEOUT):
conn = make_connection()
Expand Down Expand Up @@ -504,9 +504,9 @@ The primitive operation for creating a new cancellation scope is:
.. autofunction:: open_cancel_scope
:with: cancel_scope

Cancel scope objects provide the following interface:
Cancel scope objects provide the following interface:

.. currentmodule:: None
.. interface:: The cancel scope interface

.. attribute:: deadline

Expand Down Expand Up @@ -575,8 +575,6 @@ The primitive operation for creating a new cancellation scope is:
exception, and (2) this scope is the one that was responsible
for triggering this :exc:`~trio.Cancelled` exception.

.. currentmodule:: trio

Trio also provides several convenience functions for the common
situation of just wanting to impose a timeout on some code:

Expand Down Expand Up @@ -885,9 +883,9 @@ The nursery API
.. autofunction:: open_nursery
:async-with: nursery

Nursery objects provide the following interface:
Nursery objects provide the following interface:

.. currentmodule:: None
.. interface:: The nursery interface

.. method:: spawn(async_fn, *args, name=None)

Expand Down Expand Up @@ -970,8 +968,6 @@ The nursery API
nursery.reap(task)
return task.result.unwrap()

.. currentmodule:: trio


Task object API
+++++++++++++++
Expand Down
110 changes: 91 additions & 19 deletions docs/source/reference-io.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ I/O in Trio

.. note::

Please excuse our dust! `geocities-construction-worker.gif
<http://www.textfiles.com/underconstruction/>`__
Please excuse our dust! `[insert geocities construction worker gif
here] <http://www.textfiles.com/underconstruction/>`__

You're looking at the documentation for trio's development branch,
which is currently about half-way through implementing a proper
Expand Down Expand Up @@ -162,11 +162,11 @@ create a :class:`SSLStream`:
:members:


Low-level sockets and networking
--------------------------------

.. module:: trio.socket

Low-level networking with :mod:`trio.socket`
---------------------------------------------

The :mod:`trio.socket` module provides trio's basic low-level
networking API. If you're doing ordinary things with stream-oriented
connections over IPv4/IPv6/Unix domain sockets, then you probably want
Expand All @@ -176,22 +176,35 @@ get direct access to all the quirky bits of your system's networking
API, then you're in the right place.


:mod:`trio.socket`: top-level exports
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Top-level exports
~~~~~~~~~~~~~~~~~

Generally, the API exposed by :mod:`trio.socket` mirrors that of the
standard library :mod:`socket` module. Most constants (like
``SOL_SOCKET``) and simple utilities (like :func:`~socket.inet_aton`)
are simply re-exported unchanged. But there are also some differences,
which are described here.

All functions that return socket objects (e.g. :func:`socket.socket`,
:func:`socket.socketpair`, ...) are modified to return trio socket
objects instead. In addition, there is a new function to directly
convert a standard library socket into a trio socket:
.. function:: socket(...)
socketpair(...)
fromfd(...)
fromshare(...)

Trio provides analogues to all the standard library functions that
return socket objects; their interface is identical, except that
they're modified to return trio socket objects instead.

In addition, there is a new function to directly convert a standard
library socket into a trio socket:

.. autofunction:: from_stdlib_socket

Unlike :func:`socket.socket`, :func:`trio.socket.socket` is a
function, not a class; if you want to check whether an object is a
trio socket, use:

.. autofunction:: is_trio_socket

For name lookup, Trio provides the standard functions, but with some
changes:

Expand Down Expand Up @@ -237,7 +250,7 @@ broken features:
Socket objects
~~~~~~~~~~~~~~

.. class:: SocketType()
.. interface:: The trio socket object interface

Trio socket objects are overall very similar to the :ref:`standard
library socket objects <python:socket-objects>`, with a few
Expand Down Expand Up @@ -279,9 +292,27 @@ Socket objects
this can be easily accomplished by calling either
:meth:`resolve_local_address` or :meth:`resolve_remote_address`.

.. automethod:: resolve_local_address
.. method:: resolve_local_address(address)

Resolve the given address into a numeric address suitable for
passing to :meth:`bind`.

This performs the same address resolution that the standard library
:meth:`~socket.socket.bind` call would do, taking into account the
current socket's settings (e.g. if this is an IPv6 socket then it
returns IPv6 addresses). In particular, a hostname of ``None`` is
mapped to the wildcard address.

.. automethod:: resolve_remote_address
.. method:: resolve_remote_address(address)

Resolve the given address into a numeric address suitable for
passing to :meth:`connect` or similar.

This performs the same address resolution that the standard library
:meth:`~socket.socket.connect` call would do, taking into account the
current socket's settings (e.g. if this is an IPv6 socket then it
returns IPv6 addresses). In particular, a hostname of ``None`` is
mapped to the localhost address.

**Modern defaults:** And finally, we took the opportunity to update
the defaults for several socket options that were stuck in the
Expand Down Expand Up @@ -326,14 +357,54 @@ Socket objects
See `issue #72 <https://github.com/python-trio/trio/issues/72>`__ for
discussion of these defaults.

The following methods are similar, but not identical, to the
equivalents in :func:`socket.socket`:
The following methods are similar to the equivalents in
:func:`socket.socket`, but have some trio-specific quirks:

.. method:: bind

.. automethod:: bind
Bind this socket to the given address.

.. automethod:: connect
Unlike the stdlib :meth:`~socket.socket.bind`, this method
requires a pre-resolved address. See
:meth:`resolve_local_address`.

.. automethod:: sendall
.. method:: connect
:async:

Connect the socket to a remote address.

Similar to :meth:`socket.socket.connect`, except async and
requiring a pre-resolved address. See
:meth:`resolve_remote_address`.

.. warning::

Due to limitations of the underlying operating system APIs, it is
not always possible to properly cancel a connection attempt once it
has begun. If :meth:`connect` is cancelled, and is unable to
abort the connection attempt, then it will:

1. forcibly close the socket to prevent accidental re-use
2. raise :exc:`~trio.Cancelled`.

tl;dr: if :meth:`connect` is cancelled then the socket is
left in an unknown state – possibly open, and possibly
closed. The only reasonable thing to do is to close it.

.. method:: sendall(data, flags=0)
:async:

Send the data to the socket, blocking until all of it has been
accepted by the operating system.

``flags`` are passed on to ``send``.

Most low-level operations in trio provide a guarantee: if they raise
:exc:`trio.Cancelled`, this means that they had no effect, so the
system remains in a known state. This is **not true** for
:meth:`sendall`. If this operation raises :exc:`trio.Cancelled` (or
any other exception for that matter), then it may have sent some, all,
or none of the requested data, and there is no way to know which.

.. method:: sendfile

Expand Down Expand Up @@ -374,6 +445,7 @@ Socket objects
* :meth:`~socket.socket.set_inheritable`
* :meth:`~socket.socket.get_inheritable`


Asynchronous disk I/O
---------------------

Expand Down
10 changes: 5 additions & 5 deletions trio/_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ class SocketStream(HalfCloseableStream):
interface based on a raw network socket.
Args:
sock (trio.socket.SocketType): The trio socket object to wrap. Must have
type ``SOCK_STREAM``, and be connected.
sock: The trio socket object to wrap. Must have type ``SOCK_STREAM``,
and be connected.
By default, :class:`SocketStream` enables ``TCP_NODELAY``, and (on
platforms where it's supported) enables ``TCP_NOTSENT_LOWAT`` with a
Expand All @@ -50,12 +50,12 @@ class SocketStream(HalfCloseableStream):
.. attribute:: socket
The :class:`trio.socket.SocketType` object that this stream wraps.
The Trio socket object that this stream wraps.
"""
def __init__(self, sock):
if not isinstance(sock, tsocket.SocketType):
raise TypeError("SocketStream requires trio.socket.SocketType")
if not tsocket.is_trio_socket(sock):
raise TypeError("SocketStream requires trio socket object")
if sock._real_type != tsocket.SOCK_STREAM:
raise ValueError("SocketStream requires a SOCK_STREAM socket")
try:
Expand Down
Loading

0 comments on commit a1ad278

Please sign in to comment.