Commit 2fc52c0e authored by Jason Madden's avatar Jason Madden

Cleanup socket documentation.

- De-dup wait_read, etc, from socket2 and socket3 and call them out as gevent extensions.
- Doc create_connection on socket2 and socket3 since its a standard interface.
- Docstrings for gethostbyname, etc.
parent 387d76fa
=====
DNS
=====
=======================
Name Resolution (DNS)
=======================
gevent includes support for a pluggable hostname resolution system.
Pluggable resolvers are (generally) intended to be cooperative.
......
......@@ -27,10 +27,27 @@ Python 2 and Python 3, respectively.
Python 3 interface <gevent._socket3>
Python 2 interface <gevent._socket2>
Shared Functions
================
These functions are identical and shared by all implementations.
.. autofunction:: gevent.socket.create_connection
Gevent Extensions
=================
Beyond the basic standard library interface, ``gevent.socket``
provides some extensions. These are identical and shared by all
versions of Python.
Waiting
-------
These functions are used to block the current greenlet until an open
file (socket) is ready to perform I/O operations. These are low-level
functions not commonly used by many programs.
.. note:: These use the underlying libev ``io`` watchers, which means
that they share the same implementation limits. For example,
on some platforms they can be used with more than just
sockets, while on others the applicability is more limited.
.. autofunction:: gevent.socket.wait_read
.. autofunction:: gevent.socket.wait_write
.. autofunction:: gevent.socket.wait_readwrite
.. autofunction:: gevent.socket.wait
.. autofunction:: gevent.socket.cancel_wait
......@@ -7,7 +7,7 @@ from gevent import _socketcommon
from gevent.hub import PYPY
for key in _socketcommon.__dict__:
if key.startswith('__') or key in _socketcommon.__py3_imports__:
if key.startswith('__') or key in _socketcommon.__py3_imports__ or key in _socketcommon.__extensions__:
continue
globals()[key] = getattr(_socketcommon, key)
......
......@@ -11,7 +11,7 @@ from io import BlockingIOError
from os import dup
for key in _socketcommon.__dict__:
if key.startswith('__'):
if key.startswith('__') or key in _socketcommon.__extensions__:
continue
globals()[key] = getattr(_socketcommon, key)
......
......@@ -18,7 +18,8 @@ __dns__ = ['getaddrinfo',
_implements += __dns__
# non-standard functions that this module provides:
__extensions__ = ['wait_read',
__extensions__ = ['cancel_wait',
'wait_read',
'wait_write',
'wait_readwrite']
......@@ -109,17 +110,39 @@ for name in __socket__.__all__:
del name, value
def wait(io, timeout=None, timeout_exc=timeout('timed out')):
"""Block the current greenlet until *io* is ready.
class _NONE(object):
If *timeout* is non-negative, then *timeout_exc* is raised after *timeout* second has passed.
By default *timeout_exc* is ``socket.timeout('timed out')``.
def __repr__(self):
return "<default value>"
If :func:`cancel_wait` is called, raise ``socket.error(EBADF, 'File descriptor was closed in another greenlet')``.
_NONE = _NONE()
def wait(io, timeout=None, timeout_exc=_NONE):
"""
Block the current greenlet until *io* is ready.
If *timeout* is non-negative, then *timeout_exc* is raised after
*timeout* second has passed. By default *timeout_exc* is
``socket.timeout('timed out')``.
If :func:`cancel_wait` is called on *io* by another greenlet,
raise an exception in this blocking greenlet
(``socket.error(EBADF, 'File descriptor was closed in another
greenlet')`` by default).
:param io: A libev watcher, most commonly an IO watcher obtained from
:meth:`gevent.core.loop.io`
:keyword timeout_exc: The exception to raise if the timeout expires.
By default, a :class:`socket.timeout` exception is raised.
If you pass a value for this keyword, it is interpreted as for
:class:`gevent.timeout.Timeout`.
"""
assert io.callback is None, 'This socket is already used by another greenlet: %r' % (io.callback, )
if timeout is not None:
timeout_exc = timeout_exc if timeout_exc is not _NONE else timeout('timed out')
timeout = Timeout.start_new(timeout, timeout_exc)
try:
return get_hub().wait(io)
finally:
......@@ -128,47 +151,58 @@ def wait(io, timeout=None, timeout_exc=timeout('timed out')):
# rename "io" to "watcher" because wait() works with any watcher
def wait_read(fileno, timeout=None, timeout_exc=timeout('timed out')):
"""Block the current greenlet until *fileno* is ready to read.
def wait_read(fileno, timeout=None, timeout_exc=_NONE):
"""
Block the current greenlet until *fileno* is ready to read.
If *timeout* is non-negative, then *timeout_exc* is raised after *timeout* second has passed.
By default *timeout_exc* is ``socket.timeout('timed out')``.
For the meaning of the other parameters and possible exceptions,
see :func:`wait`.
If :func:`cancel_wait` is called, raise ``socket.error(EBADF, 'File descriptor was closed in another greenlet')``.
"""
.. seealso: :func:`cancel_wait`
"""
io = get_hub().loop.io(fileno, 1)
return wait(io, timeout, timeout_exc)
def wait_write(fileno, timeout=None, timeout_exc=timeout('timed out'), event=None):
"""Block the current greenlet until *fileno* is ready to write.
def wait_write(fileno, timeout=None, timeout_exc=_NONE, event=_NONE):
"""
Block the current greenlet until *fileno* is ready to write.
For the meaning of the other parameters and possible exceptions,
see :func:`wait`.
If *timeout* is non-negative, then *timeout_exc* is raised after *timeout* second has passed.
By default *timeout_exc* is ``socket.timeout('timed out')``.
:keyword event: Ignored. Applications should not pass this parameter.
In the future, it may become an error.
If :func:`cancel_wait` is called, raise ``socket.error(EBADF, 'File descriptor was closed in another greenlet')``.
.. seealso: :func:`cancel_wait`
"""
io = get_hub().loop.io(fileno, 2)
return wait(io, timeout, timeout_exc)
def wait_readwrite(fileno, timeout=None, timeout_exc=timeout('timed out'), event=None):
"""Block the current greenlet until *fileno* is ready to read or write.
def wait_readwrite(fileno, timeout=None, timeout_exc=_NONE, event=_NONE):
"""
Block the current greenlet until *fileno* is ready to read or
write.
For the meaning of the other parameters and possible exceptions,
see :func:`wait`.
If *timeout* is non-negative, then *timeout_exc* is raised after *timeout* second has passed.
By default *timeout_exc* is ``socket.timeout('timed out')``.
:keyword event: Ignored. Applications should not pass this parameter.
In the future, it may become an error.
If :func:`cancel_wait` is called, raise ``socket.error(EBADF, 'File descriptor was closed in another greenlet')``.
.. seealso: :func:`cancel_wait`
"""
io = get_hub().loop.io(fileno, 3)
return wait(io, timeout, timeout_exc)
#: The exception raised by default on a call to :func:`cancel_wait`
cancel_wait_ex = error(EBADF, 'File descriptor was closed in another greenlet')
def cancel_wait(watcher):
get_hub().cancel_wait(watcher, cancel_wait_ex)
def cancel_wait(watcher, error=cancel_wait_ex):
"""See :meth:`gevent.hub.Hub.cancel_wait`"""
get_hub().cancel_wait(watcher, error)
class BlockingResolver(object):
......@@ -188,22 +222,69 @@ class BlockingResolver(object):
def gethostbyname(hostname):
"""
gethostbyname(host) -> address
Return the IP address (a string of the form '255.255.255.255') for a host.
.. seealso:: :doc:`dns`
"""
return get_hub().resolver.gethostbyname(hostname)
def gethostbyname_ex(hostname):
"""
gethostbyname_ex(host) -> (name, aliaslist, addresslist)
Return the true host name, a list of aliases, and a list of IP addresses,
for a host. The host argument is a string giving a host name or IP number.
Resolve host and port into list of address info entries.
.. seealso:: :doc:`dns`
"""
return get_hub().resolver.gethostbyname_ex(hostname)
def getaddrinfo(host, port, family=0, socktype=0, proto=0, flags=0):
"""
Resolve host and port into list of address info entries.
Translate the host/port argument into a sequence of 5-tuples that contain
all the necessary arguments for creating a socket connected to that service.
host is a domain name, a string representation of an IPv4/v6 address or
None. port is a string service name such as 'http', a numeric port number or
None. By passing None as the value of host and port, you can pass NULL to
the underlying C API.
The family, type and proto arguments can be optionally specified in order to
narrow the list of addresses returned. Passing zero as a value for each of
these arguments selects the full range of results.
.. seealso:: :doc:`dns`
"""
return get_hub().resolver.getaddrinfo(host, port, family, socktype, proto, flags)
def gethostbyaddr(ip_address):
"""
gethostbyaddr(host) -> (name, aliaslist, addresslist)
Return the true host name, a list of aliases, and a list of IP addresses,
for a host. The host argument is a string giving a host name or IP number.
.. seealso:: :doc:`dns`
"""
return get_hub().resolver.gethostbyaddr(ip_address)
def getnameinfo(sockaddr, flags):
"""
getnameinfo(sockaddr, flags) -> (host, port)
Get host and port for a sockaddr.
.. seealso:: :doc:`dns`
"""
return get_hub().resolver.getnameinfo(sockaddr, flags)
......
......@@ -26,6 +26,19 @@ for key in _source.__dict__:
continue
globals()[key] = getattr(_source, key)
# The _socket2 and _socket3 don't import things defined in
# __extensions__, to help avoid confusing reference cycles in the
# documentation and to prevent importing from the wrong place, but we
# *do* need to expose them here. (NOTE: This may lead to some sphinx
# warnings like:
# WARNING: missing attribute mentioned in :members: or __all__:
# module gevent._socket2, attribute cancel_wait
# These can be ignored.)
from gevent import _socketcommon
for key in _socketcommon.__extensions__:
globals()[key] = getattr(_socketcommon, key)
del key
try:
_GLOBAL_DEFAULT_TIMEOUT = __socket__._GLOBAL_DEFAULT_TIMEOUT
......@@ -73,3 +86,8 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=N
raise err
else:
raise error("getaddrinfo returns an empty list")
# This is promised to be in the __all__ of the _source, but, for circularity reasons,
# we implement it in this module. Mostly for documentation purposes, put it
# in the _source too.
_source.create_connection = create_connection
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment