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

Documentation.

parent 2d5644e4
......@@ -27,12 +27,12 @@ PyPy Notes
PyPy has been tested on OS X and 64-bit Linux from version 2.5.0
through 2.5.1, 2.6.0, 2.6.1, and pre-release versions of 2.7.0.
- Version 2.6.1 is required for the most robust signal handling. Prior
to 2.6.1 and its inclusion of `cffi 1.3.0`_, signals could be
delivered incorrectly or fail to be delivered during a blocking
operation. (PyPy 2.5.0 includes CFFI 0.8.6 while 2.6.0 has 1.1.0;
the necessary feature was added in `1.2.0`_ which is not itself
directly present in any PyPy release.)
- Version 2.6.1 or above is required for the most robust signal
handling. Prior to 2.6.1 and its inclusion of `cffi 1.3.0`_, signals
could be delivered incorrectly or fail to be delivered during a
blocking operation. (PyPy 2.5.0 includes CFFI 0.8.6 while 2.6.0 has
1.1.0; the necessary feature was added in `1.2.0`_ which is not
itself directly present in any PyPy release.)
- Overall performance seems to be quite acceptable with newer versions
of PyPy. The benchmarks distributed with gevent typically perform as
well or better on PyPy than on CPython. Things that are known or
......@@ -47,18 +47,20 @@ through 2.5.1, 2.6.0, 2.6.1, and pre-release versions of 2.7.0.
Improved subprocess support
===========================
In gevent 1.0, support and monkey patching for the ``subprocess``
In gevent 1.0, support and monkey patching for the :mod:`subprocess`
module was added. Monkey patching was off by default.
In 1.1, monkey patching subprocess is on by default due to
In 1.1, monkey patching ``subprocess`` is on by default due to
improvements in handling child processes and requirements by
downstream libraries, notably `gunicorn`_.
- :func:`gevent.os.fork`, which is monkey patched by default (and
should be used to fork a gevent-aware process that expects to use
gevent in the child process) has been improved and cooperates with
:func:`gevent.os.waitpid` (again monkey patched by default).
- fork-watchers will be called, even in multi-threaded programs.
:func:`gevent.os.waitpid` (again monkey patched by default) and
:func:`gevent.signal.signal` (which is monkey patched only for the
:data:`signal.SIGCHLD` case). The latter two patches are new in 1.1.
- Fork-watchers will be called, even in multi-threaded programs.
- The default threadpool and threaded resolver work in child
processes.
- File descriptors are no longer leaked if
......
......@@ -63,7 +63,7 @@ def get_original(mod_name, item_name):
If the object has not been patched, then that object will still be retrieved.
:param item_name: A string or sequenc of strings naming the attribute(s) on the module
:param item_name: A string or sequence of strings naming the attribute(s) on the module
``mod_name`` to return.
:return: The original value if a string was given for ``item_name`` or a sequence
of original values if a sequence was passed.
......
......@@ -149,16 +149,18 @@ if hasattr(os, 'fork'):
.. note::
The PID returned by this function may not be
waitable with either :func:`os.waitpid` or :func:`waitpid`
if libev child watchers are in use. For example, the
The PID returned by this function may not be waitable with
either :func:`os.waitpid` or :func:`waitpid` and it may
not generate SIGCHLD signals if libev child watchers are
or ever have been in use. For example, the
:mod:`gevent.subprocess` module uses libev child watchers
(which parts of gevent use libev child watchers is subject to change
at any time). Most applications should use :func:`fork_and_watch`,
which is monkey-patched as the default replacement for :func:`os.fork`
and implements the ``fork`` function of this module by default, unless
the environment variable ``GEVENT_NOWAITPID`` is defined before this
module is imported.
(which parts of gevent use libev child watchers is subject
to change at any time). Most applications should use
:func:`fork_and_watch`, which is monkey-patched as the
default replacement for :func:`os.fork` and implements the
``fork`` function of this module by default, unless the
environment variable ``GEVENT_NOWAITPID`` is defined
before this module is imported.
.. versionadded:: 1.1b2
"""
......@@ -295,11 +297,13 @@ if hasattr(os, 'fork'):
:keyword loop: The loop to start the watcher in. Defaults to the
loop of the current hub.
:keyword fork: The fork function. Defaults to :func:`the one defined in this
module <gevent_fork>` (which automatically calls :func:`gevent.hub.reinit`).
module <gevent.os.fork_gevent>` (which automatically calls :func:`gevent.hub.reinit`).
Pass the builtin :func:`os.fork` function if you do not need to
initialize gevent in the child process.
.. versionadded:: 1.1a3
.. seealso::
:func:`gevent.monkey.get_original` To access the builtin :func:`os.fork`.
"""
pid = fork()
if pid:
......@@ -318,7 +322,7 @@ if hasattr(os, 'fork'):
def fork(*args, **kwargs):
"""
Forks a child process and starts a child watcher for it in the
parent process.
parent process so that ``waitpid`` and SIGCHLD work as expected.
This implementation of ``fork`` is a wrapper for :func:`fork_and_watch`
when the environment variable ``GEVENT_NOWAITPID`` is *not* defined.
......@@ -333,7 +337,7 @@ if hasattr(os, 'fork'):
def fork():
"""
Forks a child process, initializes gevent in the child,
but *does not* prepare the parent to wait for the child.
but *does not* prepare the parent to wait for the child or receive SIGCHLD.
This implementation of ``fork`` is a wrapper for :func:`fork_gevent`
when the environment variable ``GEVENT_NOWAITPID`` *is* defined.
......
"""
Cooperative implementation of special cases of :func:`signal.signal`.
This module is designed to work with libev's child watchers, as used by
default in :func:`gevent.os.fork` Note that each SIGCHLD handler will be run
in a new greenlet when the signal is delivered (just like :class:`gevent.hub.signal`)
This module is designed to work with libev's child watchers, as used
by default in :func:`gevent.os.fork` Note that each ``SIGCHLD`` handler
will be run in a new greenlet when the signal is delivered (just like
:class:`gevent.hub.signal`)
The implementations in this module are only monkey patched if
:func:`gevent.os.waitpid` is being used (the default) and if
:const:`signal.SIGCHLD` is available; see :func:`gevent.os.fork` for
information on configuring this not to be the case for advanced uses.
.. versionadded:: 1.1b4
"""
......@@ -25,6 +31,10 @@ _signal_getsignal = _signal.getsignal
def getsignal(signalnum):
"""
Exactly the same as :func:`signal.signal` except where
:const:`signal.SIGCHLD` is concerned.
"""
if signalnum != _signal.SIGCHLD:
return _signal_getsignal(signalnum)
......@@ -36,6 +46,22 @@ def getsignal(signalnum):
def signal(signalnum, handler):
"""
Exactly the same as :func:`signal.signal` except where
:const:`signal.SIGCHLD` is concerned.
.. note::
A :const:`signal.SIGCHLD` handler installed with this function
will only be triggered for children that are forked using
:func:`gevent.os.fork` (:func:`gevent.os.fork_and_watch`);
children forked before monkey patching, or otherwise by the raw
:func:`os.fork`, will not trigger the handler installed by this
function. (It's unlikely that a SIGCHLD handler installed with
the builtin :func:`signal.signal` would be triggered either;
libev typically overwrites such a handler at the C level. At
the very least, it's full of race conditions.)
"""
if signalnum != _signal.SIGCHLD:
return _signal_signal(signalnum, handler)
......@@ -43,6 +69,7 @@ def signal(signalnum, handler):
# greenlet, just like threads
if handler != _signal.SIG_IGN and handler != _signal.SIG_DFL and not callable(handler):
# exact same error message raised by the stdlib
raise TypeError("signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object")
old_handler = getsignal(signalnum)
......@@ -65,7 +92,8 @@ def _on_child_hook():
import gevent.os
if 'waitpid' in gevent.os.__implements__ and hasattr(_signal, 'SIGCHLD'):
# Tightly coupled here to gevent.os and its waitpid implementation
# Tightly coupled here to gevent.os and its waitpid implementation; only use these
# if necessary.
gevent.os._on_child_hook = _on_child_hook
__implements__.append("signal")
__implements__.append("getsignal")
......
......@@ -323,7 +323,7 @@ class ThreadResult(object):
def wrap_errors(errors, function, args, kwargs):
"""
.. deprecated:: 1.1a2
Only used by ThreadPool.apply_e.
Previously used by ThreadPool.apply_e.
"""
try:
return True, function(*args, **kwargs)
......
# Copyright (c) 2009 Denis Bilenko. See LICENSE for details.
__all__ = ['wrap_errors']
"""
Low-level utilities.
"""
from __future__ import absolute_import
import functools
__all__ = ['wrap_errors']
class wrap_errors(object):
"""Helper to make function return an exception, rather than raise it.
"""
Helper to make function return an exception, rather than raise it.
Because every exception that is unhandled by greenlet will be logged,
it is desirable to prevent non-error exceptions from leaving a greenlet.
This can done with simple ``try``/``except`` construct::
This can done with a simple ``try/except`` construct::
def wrapped_func(*args, **kwargs):
try:
return func(*args, **kwargs)
except (A, B, C) as ex:
except (TypeError, ValueError, AttributeError) as ex:
return ex
:class:`wrap_errors` provides a shortcut to write that in one line::
This class provides a shortcut to write that in one line::
wrapped_func = wrap_errors((A, B, C), func)
wrapped_func = wrap_errors((TypeError, ValueError, AttributeError), func)
It also preserves ``__str__`` and ``__repr__`` of the original function.
"""
# QQQ could also support using wrap_errors as a decorator
def __init__(self, errors, func):
"""Make a new function from `func', such that it catches `errors' (an
Exception subclass, or a tuple of Exception subclasses) and return
it as a value.
"""
self.errors = errors
self.func = func
Calling this makes a new function from *func*, such that it catches *errors* (an
:exc:`BaseException` subclass, or a tuple of :exc:`BaseException` subclasses) and
return it as a value.
"""
self.__errors = errors
self.__func = func
# Set __doc__, __wrapped__, etc, especially useful on Python 3.
functools.update_wrapper(self, func)
def __call__(self, *args, **kwargs):
func = self.func
func = self.__func
try:
return func(*args, **kwargs)
except self.errors as ex:
except self.__errors as ex:
return ex
def __str__(self):
return str(self.func)
return str(self.__func)
def __repr__(self):
return repr(self.func)
return repr(self.__func)
def __getattr__(self, item):
return getattr(self.func, item)
def __getattr__(self, name):
return getattr(self.__func, name)
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