This makes grpc.early_adopter much more independent of RPC
Framework and cleaner at the cost of reexporting most of the
interfaces and writing several delegation classes.
These will be used in generated code in circumstances in which we
don't necessarily want to be asking calling code to have a thread
pool readily available.
This provides for now what should be a nicer interface for code
generation than that of the Face layer. In terms of abstraction
it's conceptually very similar so the two should probably be
merged as soon as is reasonable.
Successful operations were leaking the thread used for expiration
monitoring. This change ensures that the ExpirationManager for the
operation always has its abort() method called when the
TerminationManager for the operation judges the operation to have
terminated.
- Use METH_O and METH_NOARGS where appropriate, modifying the C functions
appropriately. METH_O is for functions that take a single PyObject, and
it's passed directly instead of 'args'. METH_NOARGS is for functions
that take no arguments, and they get called with just one argument
('self'.)
- In PyArg_ParseTuple*() calls, specify the callable's name for more
descriptive exception messages.
- For tp_init functions (which always take keyword arguments) introduce
keyword argument parsing (using the C local variables as keywords,
although I don't know if they're the best names to use.) This is mostly
as a way to show how keyword arguments are done in C. An alternative
method is to use _PyArg_NoKeywords(kwds) (see
https://hg.python.org/cpython/file/70a55b2dee71/Python/getargs.c#l1820,
but unfortunately it's not part of the official API,) or check manually
that the dict is empty.
- Check the return value of Python API functions that can return an error
indicator (NULL or -1.) PyFloat_AsDouble is also one of these, but we
don't check the return type (we would have to compare the result to 1.0
with ==, which is not a thing you should do) so just call PyErr_Occurred
unconditionally.
- Change Py_BuildValue() calls with just "O" formats into PyTuple_Pack
calls. It requires less runtime checking.
- Replace Py_BuildValue()/PyObject_CallObject pairs with
PyObject_CallFunctionObjArgs (since all of them have just PyObject*
arguments.) If the Py_BuildValue formats had included other types,
PyObject_CallFunction() would have been easier, but no need in these
cases.
- Replace Py_BuildValue("f", ...) with PyFloat_FromDouble(...). Less
runtime checking and parsing necessary, and more obvious in what it does.
- In the PyType structs, replace "PyObject_HEAD_INIT(NULL) 0" with
"PyVarObject_HEAD_INIT(NULL, 0)". Anything with an ob_size struct member
is a PyVarObject, although the distinction isn't all that import; it's
just a more convenient macro.
- Assign tp_new in the PyType structs directly, like all other struct
members, rather than right before the PyType_Ready() call.
- Remove PyErr_SetString() calls in places that already have a (meaningful)
exception set.
- Add a PyErr_Format() for an error return that wasn't setting an exception
(PyObject_TypeCheck() doesn't set an exception.)
- Remove NULL assignments to struct members in the error paths of the
tp_init functions. PyObject structs are always zeroed after allocation,
guaranteed. (If there's a way for them to already contain an object
you'd use Py_CLEAR() to clear them, but that can't happen in these
cases.)
- Remove a few unnecessary parentheses.
The source code is moved from src/python to
src/python/src. A setup.py is added at
src/python. The build_python.sh and
run_python.sh scripts are updated to build
and run the Python tests by building a
package and installing it in the developer's
Python 2.7 virtual environment.