summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2016-05-16 10:40:38 +0200
committerStefan Behnel <stefan_ml@behnel.de>2016-07-15 08:13:23 +0200
commit31a4969fed691f27805e37122fb3f7b85dfe8d9d (patch)
treeac08fa429b56492974f16d7768d86833e0b1528d
parent93c2d0846b99d84128ae47c0b406213e05505848 (diff)
downloadcython-31a4969fed691f27805e37122fb3f7b85dfe8d9d.tar.gz
add "__module__" attribute to coroutines and generators
-rw-r--r--Cython/Compiler/Nodes.py5
-rw-r--r--Cython/Utility/Coroutine.c22
-rw-r--r--tests/run/test_coroutines_pep492.pyx9
3 files changed, 26 insertions, 10 deletions
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index f0cab52b5..7e5db033e 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -3969,12 +3969,13 @@ class GeneratorDefNode(DefNode):
body_cname = self.gbody.entry.func_cname
name = code.intern_identifier(self.name)
qualname = code.intern_identifier(self.qualname)
+ module_name = code.intern_identifier(self.module_name)
code.putln('{')
code.putln('__pyx_CoroutineObject *gen = __Pyx_%s_New('
- '(__pyx_coroutine_body_t) %s, (PyObject *) %s, %s, %s); %s' % (
+ '(__pyx_coroutine_body_t) %s, (PyObject *) %s, %s, %s, %s); %s' % (
'Coroutine' if self.is_coroutine else 'Generator',
- body_cname, Naming.cur_scope_cname, name, qualname,
+ body_cname, Naming.cur_scope_cname, name, qualname, module_name,
code.error_goto_if_null('gen', self.pos)))
code.put_decref(Naming.cur_scope_cname, py_object_type)
if self.requires_classobj:
diff --git a/Cython/Utility/Coroutine.c b/Cython/Utility/Coroutine.c
index d8ea87783..717cc458e 100644
--- a/Cython/Utility/Coroutine.c
+++ b/Cython/Utility/Coroutine.c
@@ -341,13 +341,15 @@ typedef struct {
PyObject *yieldfrom;
PyObject *gi_name;
PyObject *gi_qualname;
+ PyObject *gi_modulename;
int resume_label;
// using T_BOOL for property below requires char value
char is_running;
} __pyx_CoroutineObject;
-static __pyx_CoroutineObject *__Pyx__Coroutine_New(PyTypeObject *type, __pyx_coroutine_body_t body,
- PyObject *closure, PyObject *name, PyObject *qualname); /*proto*/
+static __pyx_CoroutineObject *__Pyx__Coroutine_New(
+ PyTypeObject *type, __pyx_coroutine_body_t body, PyObject *closure,
+ PyObject *name, PyObject *qualname, PyObject *module_name); /*proto*/
static int __Pyx_Coroutine_clear(PyObject *self); /*proto*/
#if 1 || PY_VERSION_HEX < 0x030300B0
@@ -364,8 +366,8 @@ static PyTypeObject *__pyx_CoroutineType = 0;
static PyTypeObject *__pyx_CoroutineAwaitType = 0;
#define __Pyx_Coroutine_CheckExact(obj) (Py_TYPE(obj) == __pyx_CoroutineType)
-#define __Pyx_Coroutine_New(body, closure, name, qualname) \
- __Pyx__Coroutine_New(__pyx_CoroutineType, body, closure, name, qualname)
+#define __Pyx_Coroutine_New(body, closure, name, qualname, module_name) \
+ __Pyx__Coroutine_New(__pyx_CoroutineType, body, closure, name, qualname, module_name)
static int __pyx_Coroutine_init(void); /*proto*/
static PyObject *__Pyx__Coroutine_await(PyObject *coroutine); /*proto*/
@@ -377,8 +379,8 @@ static PyObject *__Pyx__Coroutine_await(PyObject *coroutine); /*proto*/
static PyTypeObject *__pyx_GeneratorType = 0;
#define __Pyx_Generator_CheckExact(obj) (Py_TYPE(obj) == __pyx_GeneratorType)
-#define __Pyx_Generator_New(body, closure, name, qualname) \
- __Pyx__Coroutine_New(__pyx_GeneratorType, body, closure, name, qualname)
+#define __Pyx_Generator_New(body, closure, name, qualname, module_name) \
+ __Pyx__Coroutine_New(__pyx_GeneratorType, body, closure, name, qualname, module_name)
static PyObject *__Pyx_Generator_Next(PyObject *self);
static int __pyx_Generator_init(void); /*proto*/
@@ -998,8 +1000,9 @@ __Pyx_Coroutine_set_qualname(__pyx_CoroutineObject *self, PyObject *value)
return 0;
}
-static __pyx_CoroutineObject *__Pyx__Coroutine_New(PyTypeObject* type, __pyx_coroutine_body_t body,
- PyObject *closure, PyObject *name, PyObject *qualname) {
+static __pyx_CoroutineObject *__Pyx__Coroutine_New(
+ PyTypeObject* type, __pyx_coroutine_body_t body, PyObject *closure,
+ PyObject *name, PyObject *qualname, PyObject *module_name) {
__pyx_CoroutineObject *gen = PyObject_GC_New(__pyx_CoroutineObject, type);
if (gen == NULL)
@@ -1020,6 +1023,8 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_New(PyTypeObject* type, __pyx_cor
gen->gi_qualname = qualname;
Py_XINCREF(name);
gen->gi_name = name;
+ Py_XINCREF(module_name);
+ gen->gi_modulename = module_name;
PyObject_GC_Track(gen);
return gen;
@@ -1260,6 +1265,7 @@ static PyMemberDef __pyx_Coroutine_memberlist[] = {
{(char *) "cr_running", T_BOOL, offsetof(__pyx_CoroutineObject, is_running), READONLY, NULL},
{(char*) "cr_await", T_OBJECT, offsetof(__pyx_CoroutineObject, yieldfrom), READONLY,
(char*) PyDoc_STR("object being awaited, or None")},
+ {(char *) "__module__", T_OBJECT, offsetof(__pyx_CoroutineObject, gi_modulename), PY_WRITE_RESTRICTED, 0},
{0, 0, 0, 0, 0}
};
diff --git a/tests/run/test_coroutines_pep492.pyx b/tests/run/test_coroutines_pep492.pyx
index 07b6f8011..032c6820d 100644
--- a/tests/run/test_coroutines_pep492.pyx
+++ b/tests/run/test_coroutines_pep492.pyx
@@ -488,6 +488,15 @@ class CoroutineTest(unittest.TestCase):
def gen(): yield
self.assertFalse(hasattr(gen, '__await__'))
+ def test_func_attributes(self):
+ async def foo():
+ return 10
+
+ f = foo()
+ self.assertEqual(f.__name__, 'foo')
+ self.assertEqual(f.__qualname__, 'CoroutineTest.test_func_attributes.<locals>.foo')
+ self.assertEqual(f.__module__, 'test_coroutines_pep492')
+
def test_func_1(self):
async def foo():
return 10