diff -r c0434ef75177 Lib/test/test_types.py --- a/Lib/test/test_types.py Fri May 29 16:19:34 2015 -0400 +++ b/Lib/test/test_types.py Fri May 29 17:08:26 2015 -0400 @@ -1256,9 +1256,6 @@ def gen(): yield - self.assertFalse(isinstance(gen(), collections.abc.Coroutine)) - self.assertFalse(isinstance(gen(), collections.abc.Awaitable)) - self.assertIs(types.coroutine(gen), gen) self.assertTrue(gen.__code__.co_flags & inspect.CO_ITERABLE_COROUTINE) diff -r c0434ef75177 Lib/types.py --- a/Lib/types.py Fri May 29 16:19:34 2015 -0400 +++ b/Lib/types.py Fri May 29 17:08:26 2015 -0400 @@ -160,70 +160,32 @@ import functools as _functools import collections.abc as _collections_abc +import _types def coroutine(func): """Convert regular generator function to a coroutine.""" - # We don't want to import 'dis' or 'inspect' just for - # these constants. - CO_GENERATOR = 0x20 - CO_ITERABLE_COROUTINE = 0x100 - if not callable(func): raise TypeError('types.coroutine() expects a callable') - if (isinstance(func, FunctionType) and - isinstance(getattr(func, '__code__', None), CodeType) and - (func.__code__.co_flags & CO_GENERATOR)): - - # TODO: Implement this in C. - co = func.__code__ - func.__code__ = CodeType( - co.co_argcount, co.co_kwonlyargcount, co.co_nlocals, - co.co_stacksize, - co.co_flags | CO_ITERABLE_COROUTINE, - co.co_code, - co.co_consts, co.co_names, co.co_varnames, co.co_filename, - co.co_name, co.co_firstlineno, co.co_lnotab, co.co_freevars, - co.co_cellvars) - return func + try: + return _types._coroutine(func) + except TypeError: + pass # The following code is primarily to support functions that # return generator-like objects (for instance generators # compiled with Cython). - class GeneratorWrapper: - def __init__(self, gen): - self.__wrapped__ = gen - self.send = gen.send - self.throw = gen.throw - self.close = gen.close - self.__name__ = getattr(gen, '__name__', None) - self.__qualname__ = getattr(gen, '__qualname__', None) - @property - def gi_code(self): - return self.__wrapped__.gi_code - @property - def gi_frame(self): - return self.__wrapped__.gi_frame - @property - def gi_running(self): - return self.__wrapped__.gi_running - def __next__(self): - return next(self.__wrapped__) - def __iter__(self): - return self.__wrapped__ - __await__ = __iter__ - @_functools.wraps(func) def wrapped(*args, **kwargs): coro = func(*args, **kwargs) if coro.__class__ is GeneratorType: - return GeneratorWrapper(coro) + return _types._GeneratorWrapper(coro) # slow checks if not isinstance(coro, _collections_abc.Coroutine): if isinstance(coro, _collections_abc.Generator): - return GeneratorWrapper(coro) + return _types._GeneratorWrapper(coro) raise TypeError( 'callable wrapped with types.coroutine() returned ' 'non-coroutine: {!r}'.format(coro)) diff -r c0434ef75177 Modules/Setup.dist --- a/Modules/Setup.dist Fri May 29 16:19:34 2015 -0400 +++ b/Modules/Setup.dist Fri May 29 17:08:26 2015 -0400 @@ -119,6 +119,7 @@ atexit atexitmodule.c # Register functions to be run at interpreter-shutdown _stat _stat.c # stat.h interface time timemodule.c # -lm # time operations and variables +_types _typesmodule.c # Types module speedups # access to ISO C locale support _locale _localemodule.c # -lintl diff -r c0434ef75177 Modules/_typesmodule.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Modules/_typesmodule.c Fri May 29 17:08:26 2015 -0400 @@ -0,0 +1,272 @@ +/* Helpers for types module. */ + +#include "Python.h" + +static PyObject * +types_coroutine(PyObject *self, PyObject *func) +{ + PyCodeObject *func_code; + + if (!PyFunction_Check(func)) { + PyErr_Format(PyExc_TypeError, + "callable expected, got %.50s", + Py_TYPE(func)->tp_name); + return NULL; + } + + func_code = (PyCodeObject *)PyFunction_GET_CODE(func); + + if (!(func_code->co_flags & CO_GENERATOR)) { + PyErr_SetString(PyExc_TypeError, + "generator function expected"); + return NULL; + } + + func_code->co_flags |= CO_ITERABLE_COROUTINE; + + Py_INCREF(func); + return func; +} + +PyDoc_STRVAR(types_coroutine_doc, +"_coroutine(func) -> None\n\ +\n\ +Applies CO_ITERABLE_COROUTINE to generator functions code object.\n\ +This is an internal helper for types.coroutine(), do not use this \n\ +function directly.\n"); + +typedef struct { + PyObject_HEAD + PyObject *gw_wrapped; +} PyGenWrapper; + +static PyObject * +PyGenWrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *gen; + PyGenWrapper *gw; + + if (!PyArg_UnpackTuple(args, "GeneratorWrapper", 1, 1, &gen)) + return NULL; + + gw = (PyGenWrapper *)type->tp_alloc(type, 0); + if (gw == NULL) { + return NULL; + } + + Py_INCREF(gen); + gw->gw_wrapped = gen; + + return (PyObject *)gw; +} + +static void +PyGenWrapper_dealloc(PyObject *gw) +{ + Py_CLEAR(((PyGenWrapper*)gw)->gw_wrapped); + Py_TYPE(gw)->tp_free(gw); +} + +static PyObject * +PyGenWrapper_await(PyGenWrapper *gw) +{ + PyObject *wrapped = gw->gw_wrapped; + + if (PyGen_CheckExact(wrapped)) { + Py_INCREF(wrapped); + return wrapped; + } + + return PyObject_GetIter(gw->gw_wrapped); +} + +static PyObject * +PyGenWrapper_iter(PyGenWrapper *gw) +{ + return PyGenWrapper_await(gw); +} + +static PyObject * +PyGenWrapper_iternext(PyGenWrapper *gw) +{ + iternextfunc next = NULL; + PyObject *wrapped = gw->gw_wrapped; + PyTypeObject *type = Py_TYPE(wrapped); + + next = type->tp_iternext; + if (next != NULL) { + return (*next)(wrapped); + } + + PyErr_Format(PyExc_TypeError, + "%.50s is not an iterator", + type->tp_name); + return NULL; +} + +static PyObject * +PyGenWrapper_send(PyGenWrapper *gw, PyObject *arg) +{ + _Py_IDENTIFIER(send); + return _PyObject_CallMethodIdObjArgs(gw->gw_wrapped, &PyId_send, + arg, NULL); +} + +static PyObject * +PyGenWrapper_throw(PyGenWrapper *gw, PyObject *args) +{ + _Py_IDENTIFIER(throw); + PyObject *typ; + PyObject *tb = NULL; + PyObject *val = NULL; + + if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb)) + return NULL; + + return _PyObject_CallMethodIdObjArgs(gw->gw_wrapped, &PyId_throw, + typ, val, tb, NULL); +} + +static PyObject * +PyGenWrapper_close(PyGenWrapper *gw, PyObject *arg) +{ + _Py_IDENTIFIER(close); + return _PyObject_CallMethodId(gw->gw_wrapped, &PyId_close, NULL); +} + +static PyObject * +PyGenWrapper_get_name(PyGenWrapper *gw) +{ + _Py_IDENTIFIER(__name__); + return _PyObject_GetAttrId(gw->gw_wrapped, &PyId___name__); +} + +static PyObject * +PyGenWrapper_get_qualname(PyGenWrapper *gw) +{ + _Py_IDENTIFIER(__qualname__); + return _PyObject_GetAttrId(gw->gw_wrapped, &PyId___qualname__); +} + +static PyObject * +PyGenWrapper_get_gi_running(PyGenWrapper *gw) +{ + _Py_IDENTIFIER(gi_running); + return _PyObject_GetAttrId(gw->gw_wrapped, &PyId_gi_running); +} + +static PyObject * +PyGenWrapper_get_gi_frame(PyGenWrapper *gw) +{ + _Py_IDENTIFIER(gi_frame); + return _PyObject_GetAttrId(gw->gw_wrapped, &PyId_gi_frame); +} + +static PyObject * +PyGenWrapper_get_gi_code(PyGenWrapper *gw) +{ + _Py_IDENTIFIER(gi_code); + return _PyObject_GetAttrId(gw->gw_wrapped, &PyId_gi_code); +} + +static PyAsyncMethods GeneratorWrapperType_as_async = { + (unaryfunc)PyGenWrapper_await, /* am_await */ + 0, /* am_aiter */ + 0 /* am_anext */ +}; + +static PyMethodDef GeneratorWrapperType_methods[] = { + {"send", (PyCFunction)PyGenWrapper_send, METH_O, NULL}, + {"throw", (PyCFunction)PyGenWrapper_throw, METH_VARARGS, NULL}, + {"close", (PyCFunction)PyGenWrapper_close, METH_NOARGS, NULL}, + {NULL, NULL} /* Sentinel */ +}; + +static PyGetSetDef GeneratorWrapperType_getsetlist[] = { + {"__name__", (getter)PyGenWrapper_get_name, NULL, NULL}, + {"__qualname__", (getter)PyGenWrapper_get_qualname, NULL, NULL}, + {"gi_running", (getter)PyGenWrapper_get_gi_running, NULL, NULL}, + {"gi_code", (getter)PyGenWrapper_get_gi_code, NULL, NULL}, + {"gi_frame", (getter)PyGenWrapper_get_gi_frame, NULL, NULL}, + {NULL} /* Sentinel */ +}; + +static PyTypeObject GeneratorWrapperType = { + PyVarObject_HEAD_INIT(NULL, 0) + "GeneratorWrapper", + sizeof(PyGenWrapper), /* tp_basicsize */ + 0, /* tp_itemsize */ + PyGenWrapper_dealloc, /* destructor tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + &GeneratorWrapperType_as_async, /* tp_as_async */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "Wrapper around generator objects with __await__ metod", + 0, /* traverseproc tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)PyGenWrapper_iter, /* tp_iter */ + (iternextfunc)PyGenWrapper_iternext,/* tp_iternext */ + GeneratorWrapperType_methods, /* tp_methods */ + 0, /* tp_members */ + GeneratorWrapperType_getsetlist, /* tp_getset */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + PyGenWrapper_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + + +static PyMethodDef types_methods[] = { + {"_coroutine", types_coroutine, METH_O, types_coroutine_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(module_doc, "Helpers for types module.\n"); + +static struct PyModuleDef _typesmodule = { + PyModuleDef_HEAD_INIT, + "_types", + module_doc, + -1, + types_methods, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC +PyInit__types(void) +{ + PyObject *m; + + m = PyModule_Create(&_typesmodule); + if (m == NULL) + return NULL; + + if (PyType_Ready(&GeneratorWrapperType) < 0) + return NULL; + Py_INCREF(&GeneratorWrapperType); + PyModule_AddObject(m, "_GeneratorWrapper", + (PyObject *)&GeneratorWrapperType); + + return m; +} diff -r c0434ef75177 PC/config.c --- a/PC/config.c Fri May 29 16:19:34 2015 -0400 +++ b/PC/config.c Fri May 29 17:08:26 2015 -0400 @@ -38,6 +38,7 @@ extern PyObject* PyInit__collections(void); extern PyObject* PyInit__heapq(void); extern PyObject* PyInit__bisect(void); +extern PyObject* PyInit__types(void); extern PyObject* PyInit__symtable(void); extern PyObject* PyInit_mmap(void); extern PyObject* PyInit__csv(void); @@ -117,6 +118,7 @@ {"itertools", PyInit_itertools}, {"_collections", PyInit__collections}, {"_symtable", PyInit__symtable}, + {"_types", PyInit__types}, {"mmap", PyInit_mmap}, {"_csv", PyInit__csv}, {"_sre", PyInit__sre}, diff -r c0434ef75177 PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj Fri May 29 16:19:34 2015 -0400 +++ b/PCbuild/pythoncore.vcxproj Fri May 29 17:08:26 2015 -0400 @@ -227,6 +227,7 @@ + @@ -415,4 +416,4 @@ - \ No newline at end of file + diff -r c0434ef75177 PCbuild/pythoncore.vcxproj.filters --- a/PCbuild/pythoncore.vcxproj.filters Fri May 29 16:19:34 2015 -0400 +++ b/PCbuild/pythoncore.vcxproj.filters Fri May 29 17:08:26 2015 -0400 @@ -473,6 +473,9 @@ Modules + + Modules + Modules @@ -974,4 +977,4 @@ Resource Files - \ No newline at end of file +