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
+