Fold in some api function documentation from Donovan's preliminary guide.
Fix reStructuredText syntax on a couple others.
This commit is contained in:
163
eventlet/api.py
163
eventlet/api.py
@@ -55,17 +55,18 @@ __all__ = [
|
|||||||
|
|
||||||
|
|
||||||
class TimeoutError(Exception):
|
class TimeoutError(Exception):
|
||||||
|
"""Exception raised if an asynchronous operation times out"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
_threadlocal = tls.local()
|
_threadlocal = tls.local()
|
||||||
|
|
||||||
def tcp_listener(address):
|
def tcp_listener(address):
|
||||||
"""
|
"""
|
||||||
Listen on the given (ip, port) address with a TCP socket.
|
Listen on the given (ip, port) *address* with a TCP socket.
|
||||||
Returns a socket object which one should call accept() on to
|
Returns a socket object on which one should call ``accept()`` to
|
||||||
accept a connection on the newly bound socket.
|
accept a connection on the newly bound socket.
|
||||||
|
|
||||||
Generally, the returned socket will be passed to tcp_server,
|
Generally, the returned socket will be passed to ``tcp_server()``,
|
||||||
which accepts connections forever and spawns greenlets for
|
which accepts connections forever and spawns greenlets for
|
||||||
each incoming connection.
|
each incoming connection.
|
||||||
"""
|
"""
|
||||||
@@ -75,13 +76,16 @@ def tcp_listener(address):
|
|||||||
return socket
|
return socket
|
||||||
|
|
||||||
def ssl_listener(address, certificate, private_key):
|
def ssl_listener(address, certificate, private_key):
|
||||||
"""Listen on the given (ip, port) address with a TCP socket that
|
"""Listen on the given (ip, port) *address* with a TCP socket that
|
||||||
can do SSL.
|
can do SSL.
|
||||||
|
|
||||||
Returns a socket object which one should call accept() on to
|
*certificate* and *private_key* should be the filenames of the appropriate
|
||||||
|
certificate and private key files to use with the SSL socket.
|
||||||
|
|
||||||
|
Returns a socket object on which one should call ``accept()`` to
|
||||||
accept a connection on the newly bound socket.
|
accept a connection on the newly bound socket.
|
||||||
|
|
||||||
Generally, the returned socket will be passed to tcp_server,
|
Generally, the returned socket will be passed to ``tcp_server()``,
|
||||||
which accepts connections forever and spawns greenlets for
|
which accepts connections forever and spawns greenlets for
|
||||||
each incoming connection.
|
each incoming connection.
|
||||||
"""
|
"""
|
||||||
@@ -103,20 +107,17 @@ def connect_tcp(address):
|
|||||||
def tcp_server(listensocket, server, *args, **kw):
|
def tcp_server(listensocket, server, *args, **kw):
|
||||||
"""
|
"""
|
||||||
Given a socket, accept connections forever, spawning greenlets
|
Given a socket, accept connections forever, spawning greenlets
|
||||||
and executing "server" for each new incoming connection.
|
and executing *server* for each new incoming connection.
|
||||||
When listensocket is closed, the tcp_server greenlet will end.
|
When *listensocket* is closed, the ``tcp_server()`` greenlet will end.
|
||||||
|
|
||||||
listensocket:
|
listensocket
|
||||||
The socket to accept connections from.
|
The socket from which to accept connections.
|
||||||
|
server
|
||||||
server:
|
|
||||||
The callable to call when a new connection is made.
|
The callable to call when a new connection is made.
|
||||||
|
\*args
|
||||||
*args:
|
The positional arguments to pass to *server*.
|
||||||
The arguments to pass to the call to server.
|
\*\*kw
|
||||||
|
The keyword arguments to pass to *server*.
|
||||||
**kw:
|
|
||||||
The keyword arguments to pass to the call to server.
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
@@ -129,7 +130,19 @@ def tcp_server(listensocket, server, *args, **kw):
|
|||||||
finally:
|
finally:
|
||||||
listensocket.close()
|
listensocket.close()
|
||||||
|
|
||||||
def trampoline(fd, read=None, write=None, timeout=None):
|
def trampoline(fd, read=False, write=False, timeout=None):
|
||||||
|
"""Suspend the current coroutine until the given socket object or file
|
||||||
|
descriptor is ready to *read*, ready to *write*, or the specified
|
||||||
|
*timeout* elapses, depending on arguments specified.
|
||||||
|
|
||||||
|
To wait for *fd* to be ready to read, pass *read* ``=True``; ready to
|
||||||
|
write, pass *write* ``=True``. To specify a timeout, pass the *timeout*
|
||||||
|
argument in seconds.
|
||||||
|
|
||||||
|
If the specified *timeout* elapses before the socket is ready to read or
|
||||||
|
write, ``TimeoutError`` will be raised instead of ``trampoline()``
|
||||||
|
returning normally.
|
||||||
|
"""
|
||||||
t = None
|
t = None
|
||||||
hub = get_hub()
|
hub = get_hub()
|
||||||
self = greenlet.getcurrent()
|
self = greenlet.getcurrent()
|
||||||
@@ -164,21 +177,43 @@ def _spawn(g):
|
|||||||
greenlib.switch(g)
|
greenlib.switch(g)
|
||||||
|
|
||||||
|
|
||||||
def spawn(cb, *args, **kw):
|
def spawn(function, *args, **kwds):
|
||||||
|
"""Create a new coroutine, or cooperative thread of control, within which
|
||||||
|
to execute *function*.
|
||||||
|
|
||||||
|
The *function* will be called with the given *args* and keyword arguments
|
||||||
|
*kwds* and will remain in control unless it cooperatively yields by
|
||||||
|
calling a socket method or ``sleep()``.
|
||||||
|
|
||||||
|
``spawn()`` returns control to the caller immediately, and *function* will
|
||||||
|
be called in a future main loop iteration.
|
||||||
|
|
||||||
|
An uncaught exception in *function* or any child will terminate the new
|
||||||
|
coroutine with a log message.
|
||||||
|
"""
|
||||||
# killable
|
# killable
|
||||||
t = None
|
t = None
|
||||||
g = greenlib.tracked_greenlet()
|
g = greenlib.tracked_greenlet()
|
||||||
t = get_hub().schedule_call(0, _spawn, g)
|
t = get_hub().schedule_call(0, _spawn, g)
|
||||||
greenlib.switch(g, (_spawn_startup, cb, args, kw, t.cancel))
|
greenlib.switch(g, (_spawn_startup, function, args, kwds, t.cancel))
|
||||||
return g
|
return g
|
||||||
|
|
||||||
kill = greenlib.kill
|
kill = greenlib.kill
|
||||||
|
|
||||||
def call_after(seconds, cb, *args, **kw):
|
def call_after(seconds, function, *args, **kwds):
|
||||||
|
"""Schedule *function* to be called after *seconds* have elapsed.
|
||||||
|
|
||||||
|
*seconds* may be specified as an integer, or a float if fractional seconds
|
||||||
|
are desired. The *function* will be called with the given *args* and
|
||||||
|
keyword arguments *kwds*, and will be executed within the main loop's
|
||||||
|
coroutine.
|
||||||
|
|
||||||
|
Its return value is discarded. Any uncaught exception will be logged.
|
||||||
|
"""
|
||||||
# cancellable
|
# cancellable
|
||||||
def startup():
|
def startup():
|
||||||
g = greenlib.tracked_greenlet()
|
g = greenlib.tracked_greenlet()
|
||||||
greenlib.switch(g, (_spawn_startup, cb, args, kw))
|
greenlib.switch(g, (_spawn_startup, function, args, kwds))
|
||||||
greenlib.switch(g)
|
greenlib.switch(g)
|
||||||
return get_hub().schedule_call(seconds, startup)
|
return get_hub().schedule_call(seconds, startup)
|
||||||
|
|
||||||
@@ -188,14 +223,14 @@ def with_timeout(seconds, func, *args, **kwds):
|
|||||||
function fails to return before the timeout, cancel it and return a flag
|
function fails to return before the timeout, cancel it and return a flag
|
||||||
value.
|
value.
|
||||||
|
|
||||||
*seconds*
|
seconds
|
||||||
(int or float) seconds before timeout occurs
|
(int or float) seconds before timeout occurs
|
||||||
*func*
|
func
|
||||||
the callable to execute with a timeout; must be one of the functions
|
the callable to execute with a timeout; must be one of the functions
|
||||||
that implicitly or explicitly yields
|
that implicitly or explicitly yields
|
||||||
*\*args*, *\*\*kwds*
|
\*args, \*\*kwds
|
||||||
(positional, keyword) arguments to pass to *func*
|
(positional, keyword) arguments to pass to *func*
|
||||||
*timeout_value=*
|
timeout_value=
|
||||||
value to return if timeout occurs (default None)
|
value to return if timeout occurs (default None)
|
||||||
|
|
||||||
**Returns**:
|
**Returns**:
|
||||||
@@ -209,9 +244,10 @@ def with_timeout(seconds, func, *args, **kwds):
|
|||||||
**Example**::
|
**Example**::
|
||||||
|
|
||||||
data = with_timeout(30, httpc.get, 'http://www.google.com/', timeout_value="")
|
data = with_timeout(30, httpc.get, 'http://www.google.com/', timeout_value="")
|
||||||
# Here data is either the result of the get() call, or the empty string if
|
|
||||||
# it took too long to return. Any exception raised by the get() call is
|
Here *data* is either the result of the ``get()`` call, or the empty string if
|
||||||
# passed through to the caller.
|
it took too long to return. Any exception raised by the ``get()`` call is
|
||||||
|
passed through to the caller.
|
||||||
"""
|
"""
|
||||||
# Recognize a specific keyword argument, while also allowing pass-through
|
# Recognize a specific keyword argument, while also allowing pass-through
|
||||||
# of any other keyword arguments accepted by func. Use pop() so we don't
|
# of any other keyword arguments accepted by func. Use pop() so we don't
|
||||||
@@ -226,11 +262,36 @@ def with_timeout(seconds, func, *args, **kwds):
|
|||||||
finally:
|
finally:
|
||||||
timeout.cancel()
|
timeout.cancel()
|
||||||
|
|
||||||
def exc_after(seconds, exc):
|
def exc_after(seconds, exception_object):
|
||||||
return call_after(seconds, switch, getcurrent(), None, exc)
|
"""Schedule *exception_object* to be raised into the current coroutine
|
||||||
|
after *seconds* have elapsed.
|
||||||
|
|
||||||
|
This only works if the current coroutine is yielding, and is generally
|
||||||
|
used to set timeouts after which a network operation or series of
|
||||||
|
operations will be canceled.
|
||||||
|
|
||||||
|
Returns a timer object with a ``cancel()`` method which should be used to
|
||||||
|
prevent the exception if the operation completes successfully.
|
||||||
|
|
||||||
|
See also ``with_timeout()`` that encapsulates the idiom below.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
def read_with_timeout():
|
||||||
|
timer = api.exc_after(30, RuntimeError())
|
||||||
|
try:
|
||||||
|
httpc.get('http://www.google.com/')
|
||||||
|
except RuntimeError:
|
||||||
|
print "Timed out!"
|
||||||
|
else:
|
||||||
|
timer.cancel()
|
||||||
|
"""
|
||||||
|
return call_after(seconds, switch, getcurrent(), None, exception_object)
|
||||||
|
|
||||||
|
|
||||||
def get_default_hub():
|
def get_default_hub():
|
||||||
|
"""
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
import eventlet.hubs.libevent
|
import eventlet.hubs.libevent
|
||||||
return eventlet.hubs.libevent
|
return eventlet.hubs.libevent
|
||||||
@@ -247,6 +308,8 @@ def get_default_hub():
|
|||||||
|
|
||||||
|
|
||||||
def use_hub(mod=None):
|
def use_hub(mod=None):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
if mod is None:
|
if mod is None:
|
||||||
mod = get_default_hub()
|
mod = get_default_hub()
|
||||||
if hasattr(_threadlocal, 'hub'):
|
if hasattr(_threadlocal, 'hub'):
|
||||||
@@ -257,6 +320,8 @@ def use_hub(mod=None):
|
|||||||
_threadlocal.Hub = mod
|
_threadlocal.Hub = mod
|
||||||
|
|
||||||
def get_hub():
|
def get_hub():
|
||||||
|
"""
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
hub = _threadlocal.hub
|
hub = _threadlocal.hub
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@@ -268,9 +333,19 @@ def get_hub():
|
|||||||
return hub
|
return hub
|
||||||
|
|
||||||
|
|
||||||
def sleep(timeout=0):
|
def sleep(seconds=0):
|
||||||
|
"""Yield control to another eligible coroutine until at least *seconds* have
|
||||||
|
elapsed.
|
||||||
|
|
||||||
|
*seconds* may be specified as an integer, or a float if fractional seconds
|
||||||
|
are desired. Calling sleep with *seconds* of 0 is the canonical way of
|
||||||
|
expressing a cooperative yield. For example, if one is looping over a
|
||||||
|
large list performing an expensive calculation without calling any socket
|
||||||
|
methods, it's a good idea to call ``sleep(0)`` occasionally; otherwise
|
||||||
|
nothing else will run.
|
||||||
|
"""
|
||||||
hub = get_hub()
|
hub = get_hub()
|
||||||
hub.schedule_call(timeout, greenlib.switch, greenlet.getcurrent())
|
hub.schedule_call(seconds, greenlib.switch, greenlet.getcurrent())
|
||||||
hub.switch()
|
hub.switch()
|
||||||
|
|
||||||
|
|
||||||
@@ -280,6 +355,8 @@ GreenletExit = greenlet.GreenletExit
|
|||||||
|
|
||||||
|
|
||||||
class Spew(object):
|
class Spew(object):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
def __init__(self, trace_names=None):
|
def __init__(self, trace_names=None):
|
||||||
self.trace_names = trace_names
|
self.trace_names = trace_names
|
||||||
|
|
||||||
@@ -317,19 +394,27 @@ class Spew(object):
|
|||||||
|
|
||||||
|
|
||||||
def spew(trace_names=None):
|
def spew(trace_names=None):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
sys.settrace(Spew(trace_names))
|
sys.settrace(Spew(trace_names))
|
||||||
|
|
||||||
|
|
||||||
def unspew():
|
def unspew():
|
||||||
|
"""
|
||||||
|
"""
|
||||||
sys.settrace(None)
|
sys.settrace(None)
|
||||||
|
|
||||||
|
|
||||||
def named(name):
|
def named(name):
|
||||||
"""Return an object given its name. The name uses a module-like
|
"""Return an object given its name.
|
||||||
syntax, eg:
|
|
||||||
os.path.join
|
The name uses a module-like syntax, eg::
|
||||||
or
|
|
||||||
mulib.mu.Resource
|
os.path.join
|
||||||
|
|
||||||
|
or::
|
||||||
|
|
||||||
|
mulib.mu.Resource
|
||||||
"""
|
"""
|
||||||
toimport = name
|
toimport = name
|
||||||
obj = None
|
obj = None
|
||||||
|
Reference in New Issue
Block a user