Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Gwenaël Samain
cython
Commits
4b8cedab
Commit
4b8cedab
authored
Jul 29, 2017
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
solve most of the issues with failing async-gen tests, some asyncio tests are still failing
parent
dcf0a543
Changes
7
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1265 additions
and
56 deletions
+1265
-56
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+17
-3
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+14
-8
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/ParseTreeTransforms.py
+3
-2
Cython/Utility/AsyncGen.c
Cython/Utility/AsyncGen.c
+18
-14
Cython/Utility/Coroutine.c
Cython/Utility/Coroutine.c
+108
-25
Cython/Utility/ModuleSetupCode.c
Cython/Utility/ModuleSetupCode.c
+6
-4
tests/run/test_asyncgen.py
tests/run/test_asyncgen.py
+1099
-0
No files found.
Cython/Compiler/ExprNodes.py
View file @
4b8cedab
...
@@ -9484,12 +9484,15 @@ class YieldExprNode(ExprNode):
...
@@ -9484,12 +9484,15 @@ class YieldExprNode(ExprNode):
if
type
.
is_pyobject
:
if
type
.
is_pyobject
:
code
.
putln
(
'%s->%s = 0;'
%
(
Naming
.
cur_scope_cname
,
save_cname
))
code
.
putln
(
'%s->%s = 0;'
%
(
Naming
.
cur_scope_cname
,
save_cname
))
code
.
put_xgotref
(
cname
)
code
.
put_xgotref
(
cname
)
code
.
putln
(
code
.
error_goto_if_null
(
Naming
.
sent_value_cname
,
self
.
pos
)
)
self
.
generate_sent_value_handling_code
(
code
,
Naming
.
sent_value_cname
)
if
self
.
result_is_used
:
if
self
.
result_is_used
:
self
.
allocate_temp_result
(
code
)
self
.
allocate_temp_result
(
code
)
code
.
put
(
'%s = %s; '
%
(
self
.
result
(),
Naming
.
sent_value_cname
))
code
.
put
(
'%s = %s; '
%
(
self
.
result
(),
Naming
.
sent_value_cname
))
code
.
put_incref
(
self
.
result
(),
py_object_type
)
code
.
put_incref
(
self
.
result
(),
py_object_type
)
def
generate_sent_value_handling_code
(
self
,
code
,
value_cname
):
code
.
putln
(
code
.
error_goto_if_null
(
value_cname
,
self
.
pos
))
class
_YieldDelegationExprNode
(
YieldExprNode
):
class
_YieldDelegationExprNode
(
YieldExprNode
):
def
yield_from_func
(
self
,
code
):
def
yield_from_func
(
self
,
code
):
...
@@ -9582,8 +9585,7 @@ class AwaitIterNextExprNode(AwaitExprNode):
...
@@ -9582,8 +9585,7 @@ class AwaitIterNextExprNode(AwaitExprNode):
#
#
# Breaks out of loop on StopAsyncIteration exception.
# Breaks out of loop on StopAsyncIteration exception.
def
fetch_iteration_result
(
self
,
code
):
def
_generate_break
(
self
,
code
):
assert
code
.
break_label
,
"AwaitIterNextExprNode outside of 'async for' loop"
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"StopAsyncIteration"
,
"Coroutine.c"
))
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"StopAsyncIteration"
,
"Coroutine.c"
))
code
.
putln
(
"PyObject* exc_type = PyErr_Occurred();"
)
code
.
putln
(
"PyObject* exc_type = PyErr_Occurred();"
)
code
.
putln
(
"if (exc_type && likely(exc_type == __Pyx_PyExc_StopAsyncIteration ||"
code
.
putln
(
"if (exc_type && likely(exc_type == __Pyx_PyExc_StopAsyncIteration ||"
...
@@ -9591,8 +9593,20 @@ class AwaitIterNextExprNode(AwaitExprNode):
...
@@ -9591,8 +9593,20 @@ class AwaitIterNextExprNode(AwaitExprNode):
code
.
putln
(
"PyErr_Clear();"
)
code
.
putln
(
"PyErr_Clear();"
)
code
.
putln
(
"break;"
)
code
.
putln
(
"break;"
)
code
.
putln
(
"}"
)
code
.
putln
(
"}"
)
def
fetch_iteration_result
(
self
,
code
):
assert
code
.
break_label
,
"AwaitIterNextExprNode outside of 'async for' loop"
self
.
_generate_break
(
code
)
super
(
AwaitIterNextExprNode
,
self
).
fetch_iteration_result
(
code
)
super
(
AwaitIterNextExprNode
,
self
).
fetch_iteration_result
(
code
)
def
generate_sent_value_handling_code
(
self
,
code
,
value_cname
):
assert
code
.
break_label
,
"AwaitIterNextExprNode outside of 'async for' loop"
code
.
putln
(
"if (unlikely(!%s)) {"
%
value_cname
)
self
.
_generate_break
(
code
)
# all non-break exceptions are errors, as in parent class
code
.
putln
(
code
.
error_goto
(
self
.
pos
))
code
.
putln
(
"}"
)
class
GlobalsExprNode
(
AtomicExprNode
):
class
GlobalsExprNode
(
AtomicExprNode
):
type
=
dict_type
type
=
dict_type
...
...
Cython/Compiler/Nodes.py
View file @
4b8cedab
...
@@ -4025,19 +4025,19 @@ class AsyncGenNode(AsyncDefNode):
...
@@ -4025,19 +4025,19 @@ class AsyncGenNode(AsyncDefNode):
is_asyncgen
=
True
is_asyncgen
=
True
class
GeneratorBodyDefNode
(
DefNode
):
class
GeneratorBodyDefNode
(
DefNode
):
# Main code body of a generator implemented as a DefNode.
# Main code body of a generator implemented as a DefNode.
#
#
is_generator_body
=
True
is_generator_body
=
True
is_inlined
=
False
is_inlined
=
False
is_async_gen
=
False
inlined_comprehension_type
=
None
# container type for inlined comprehensions
inlined_comprehension_type
=
None
# container type for inlined comprehensions
def
__init__
(
self
,
pos
=
None
,
name
=
None
,
body
=
None
):
def
__init__
(
self
,
pos
=
None
,
name
=
None
,
body
=
None
,
is_async_gen
=
False
):
super
(
GeneratorBodyDefNode
,
self
).
__init__
(
super
(
GeneratorBodyDefNode
,
self
).
__init__
(
pos
=
pos
,
body
=
body
,
name
=
name
,
doc
=
None
,
pos
=
pos
,
body
=
body
,
name
=
name
,
is_async_gen
=
is_async_gen
,
args
=
[],
star_arg
=
None
,
starstar_arg
=
None
)
doc
=
None
,
args
=
[],
star_arg
=
None
,
starstar_arg
=
None
)
def
declare_generator_body
(
self
,
env
):
def
declare_generator_body
(
self
,
env
):
prefix
=
env
.
next_id
(
env
.
scope_prefix
)
prefix
=
env
.
next_id
(
env
.
scope_prefix
)
...
@@ -4134,9 +4134,10 @@ class GeneratorBodyDefNode(DefNode):
...
@@ -4134,9 +4134,10 @@ class GeneratorBodyDefNode(DefNode):
# on normal generator termination, we do not take the exception propagation
# on normal generator termination, we do not take the exception propagation
# path: no traceback info is required and not creating it is much faster
# path: no traceback info is required and not creating it is much faster
if
not
self
.
is_inlined
and
not
self
.
body
.
is_terminator
:
if
not
self
.
is_inlined
and
not
self
.
body
.
is_terminator
:
code
.
putln
(
'PyErr_SetNone(PyExc_StopIteration);'
)
code
.
putln
(
'PyErr_SetNone(%s);'
%
(
'__Pyx_PyExc_StopAsyncIteration'
if
self
.
is_async_gen
else
'PyExc_StopIteration'
))
# ----- Error cleanup
# ----- Error cleanup
if
code
.
error_label
in
code
.
labels_used
:
if
code
.
label_used
(
code
.
error_label
)
:
if
not
self
.
body
.
is_terminator
:
if
not
self
.
body
.
is_terminator
:
code
.
put_goto
(
code
.
return_label
)
code
.
put_goto
(
code
.
return_label
)
code
.
put_label
(
code
.
error_label
)
code
.
put_label
(
code
.
error_label
)
...
@@ -4145,8 +4146,7 @@ class GeneratorBodyDefNode(DefNode):
...
@@ -4145,8 +4146,7 @@ class GeneratorBodyDefNode(DefNode):
if
Future
.
generator_stop
in
env
.
global_scope
().
context
.
future_directives
:
if
Future
.
generator_stop
in
env
.
global_scope
().
context
.
future_directives
:
# PEP 479: turn accidental StopIteration exceptions into a RuntimeError
# PEP 479: turn accidental StopIteration exceptions into a RuntimeError
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"pep479"
,
"Coroutine.c"
))
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"pep479"
,
"Coroutine.c"
))
code
.
putln
(
"if (unlikely(PyErr_ExceptionMatches(PyExc_StopIteration))) "
code
.
putln
(
"__Pyx_Generator_Replace_StopIteration(%d);"
%
bool
(
self
.
is_async_gen
))
"__Pyx_Generator_Replace_StopIteration();"
)
for
cname
,
type
in
code
.
funcstate
.
all_managed_temps
():
for
cname
,
type
in
code
.
funcstate
.
all_managed_temps
():
code
.
put_xdecref
(
cname
,
type
)
code
.
put_xdecref
(
cname
,
type
)
code
.
put_add_traceback
(
self
.
entry
.
qualified_name
)
code
.
put_add_traceback
(
self
.
entry
.
qualified_name
)
...
@@ -5583,10 +5583,12 @@ class ReturnStatNode(StatNode):
...
@@ -5583,10 +5583,12 @@ class ReturnStatNode(StatNode):
# value ExprNode or None
# value ExprNode or None
# return_type PyrexType
# return_type PyrexType
# in_generator return inside of generator => raise StopIteration
# in_generator return inside of generator => raise StopIteration
# in_async_gen return inside of async generator
child_attrs
=
[
"value"
]
child_attrs
=
[
"value"
]
is_terminator
=
True
is_terminator
=
True
in_generator
=
False
in_generator
=
False
in_async_gen
=
False
# Whether we are in a parallel section
# Whether we are in a parallel section
in_parallel
=
False
in_parallel
=
False
...
@@ -5598,6 +5600,8 @@ class ReturnStatNode(StatNode):
...
@@ -5598,6 +5600,8 @@ class ReturnStatNode(StatNode):
error
(
self
.
pos
,
"Return not inside a function body"
)
error
(
self
.
pos
,
"Return not inside a function body"
)
return
self
return
self
if
self
.
value
:
if
self
.
value
:
if
self
.
in_async_gen
:
error
(
self
.
pos
,
"Return with value in async generator"
)
self
.
value
=
self
.
value
.
analyse_types
(
env
)
self
.
value
=
self
.
value
.
analyse_types
(
env
)
if
return_type
.
is_void
or
return_type
.
is_returncode
:
if
return_type
.
is_void
or
return_type
.
is_returncode
:
error
(
self
.
value
.
pos
,
"Return with value in void function"
)
error
(
self
.
value
.
pos
,
"Return with value in void function"
)
...
@@ -5654,6 +5658,8 @@ class ReturnStatNode(StatNode):
...
@@ -5654,6 +5658,8 @@ class ReturnStatNode(StatNode):
else
:
else
:
if
self
.
return_type
.
is_pyobject
:
if
self
.
return_type
.
is_pyobject
:
if
self
.
in_generator
:
if
self
.
in_generator
:
if
self
.
in_async_gen
:
code
.
put
(
"PyErr_SetNone(__Pyx_PyExc_StopAsyncIteration); "
)
code
.
putln
(
"%s = NULL;"
%
Naming
.
retval_cname
)
code
.
putln
(
"%s = NULL;"
%
Naming
.
retval_cname
)
else
:
else
:
code
.
put_init_to_py_none
(
Naming
.
retval_cname
,
self
.
return_type
)
code
.
put_init_to_py_none
(
Naming
.
retval_cname
,
self
.
return_type
)
...
...
Cython/Compiler/ParseTreeTransforms.py
View file @
4b8cedab
...
@@ -2518,7 +2518,7 @@ class MarkClosureVisitor(CythonTransform):
...
@@ -2518,7 +2518,7 @@ class MarkClosureVisitor(CythonTransform):
if
node
.
is_async_def
:
if
node
.
is_async_def
:
coroutine_type
=
Nodes
.
AsyncGenNode
if
collector
.
has_yield
else
Nodes
.
AsyncDefNode
coroutine_type
=
Nodes
.
AsyncGenNode
if
collector
.
has_yield
else
Nodes
.
AsyncDefNode
if
collector
.
has_yield
:
if
collector
.
has_yield
:
for
yield_expr
in
collector
.
yields
:
for
yield_expr
in
collector
.
yields
+
collector
.
returns
:
yield_expr
.
in_async_gen
=
True
yield_expr
.
in_async_gen
=
True
elif
collector
.
has_await
:
elif
collector
.
has_await
:
found
=
next
(
y
for
y
in
collector
.
yields
if
y
.
is_await
)
found
=
next
(
y
for
y
in
collector
.
yields
if
y
.
is_await
)
...
@@ -2535,7 +2535,8 @@ class MarkClosureVisitor(CythonTransform):
...
@@ -2535,7 +2535,8 @@ class MarkClosureVisitor(CythonTransform):
retnode
.
in_generator
=
True
retnode
.
in_generator
=
True
gbody
=
Nodes
.
GeneratorBodyDefNode
(
gbody
=
Nodes
.
GeneratorBodyDefNode
(
pos
=
node
.
pos
,
name
=
node
.
name
,
body
=
node
.
body
)
pos
=
node
.
pos
,
name
=
node
.
name
,
body
=
node
.
body
,
is_async_gen
=
node
.
is_async_def
and
collector
.
has_yield
)
coroutine
=
coroutine_type
(
coroutine
=
coroutine_type
(
pos
=
node
.
pos
,
name
=
node
.
name
,
args
=
node
.
args
,
pos
=
node
.
pos
,
name
=
node
.
name
,
args
=
node
.
args
,
star_arg
=
node
.
star_arg
,
starstar_arg
=
node
.
starstar_arg
,
star_arg
=
node
.
star_arg
,
starstar_arg
=
node
.
starstar_arg
,
...
...
Cython/Utility/AsyncGen.c
View file @
4b8cedab
// This is copied from genobject.c in CPython 3.6.
// This is copied from genobject.c in CPython 3.6.
// Try to keep it in sync.
// Try to keep it in sync by doing this from time to time:
// sed -e 's|__pyx_||ig' Cython/Utility/AsyncGen.c | diff -udw - cpython/Objects/genobject.c | less
//////////////////// AsyncGenerator.proto ////////////////////
//////////////////// AsyncGenerator.proto ////////////////////
//@requires: Coroutine.c::Coroutine
//@requires: Coroutine.c::Coroutine
...
@@ -12,14 +13,20 @@ typedef struct {
...
@@ -12,14 +13,20 @@ typedef struct {
int
ag_closed
;
int
ag_closed
;
}
__pyx_PyAsyncGenObject
;
}
__pyx_PyAsyncGenObject
;
typedef
struct
__pyx_PyAsyncGenASend_struct
__pyx_PyAsyncGenASend
;
static
PyTypeObject
*
__pyx__PyAsyncGenWrappedValueType
=
0
;
static
PyTypeObject
*
__pyx__PyAsyncGenWrappedValueType
=
0
;
static
PyTypeObject
*
__pyx__PyAsyncGenASendType
=
0
;
static
PyTypeObject
*
__pyx__PyAsyncGenASendType
=
0
;
static
PyTypeObject
*
__pyx__PyAsyncGenAThrowType
=
0
;
static
PyTypeObject
*
__pyx__PyAsyncGenAThrowType
=
0
;
static
PyTypeObject
*
__pyx_AsyncGenType
=
0
;
static
PyTypeObject
*
__pyx_AsyncGenType
=
0
;
#define __Pyx_AsyncGen_CheckExact(obj) (Py_TYPE(obj) == __pyx_AsyncGenType)
#define __Pyx_AsyncGen_CheckExact(obj) (Py_TYPE(obj) == __pyx_AsyncGenType)
#define __pyx_PyAsyncGenASend_CheckExact(o) \
(Py_TYPE(o) == __pyx__PyAsyncGenASendType)
static
PyObject
*
__Pyx_async_gen_anext
(
PyObject
*
o
);
static
PyObject
*
__Pyx_async_gen_anext
(
__pyx_PyAsyncGenObject
*
o
);
static
PyObject
*
__Pyx_async_gen_asend_iternext
(
__pyx_PyAsyncGenASend
*
o
);
static
PyObject
*
__Pyx_async_gen_asend_send
(
__pyx_PyAsyncGenASend
*
o
,
PyObject
*
arg
);
static
PyObject
*
__Pyx__PyAsyncGenValueWrapperNew
(
PyObject
*
val
);
static
PyObject
*
__Pyx__PyAsyncGenValueWrapperNew
(
PyObject
*
val
);
...
@@ -120,7 +127,7 @@ typedef enum {
...
@@ -120,7 +127,7 @@ typedef enum {
__PYX_AWAITABLE_STATE_CLOSED
,
/* closed */
__PYX_AWAITABLE_STATE_CLOSED
,
/* closed */
}
__pyx_AwaitableState
;
}
__pyx_AwaitableState
;
typedef
struct
{
struct
__pyx_PyAsyncGenASend_
struct
{
PyObject_HEAD
PyObject_HEAD
__pyx_PyAsyncGenObject
*
ags_gen
;
__pyx_PyAsyncGenObject
*
ags_gen
;
...
@@ -128,7 +135,7 @@ typedef struct {
...
@@ -128,7 +135,7 @@ typedef struct {
PyObject
*
ags_sendval
;
PyObject
*
ags_sendval
;
__pyx_AwaitableState
ags_state
;
__pyx_AwaitableState
ags_state
;
}
__pyx_PyAsyncGenASend
;
};
typedef
struct
{
typedef
struct
{
...
@@ -167,9 +174,6 @@ static int __Pyx_ag_asend_freelist_free = 0;
...
@@ -167,9 +174,6 @@ static int __Pyx_ag_asend_freelist_free = 0;
#define __pyx__PyAsyncGenWrappedValue_CheckExact(o) \
#define __pyx__PyAsyncGenWrappedValue_CheckExact(o) \
(Py_TYPE(o) == __pyx__PyAsyncGenWrappedValueType)
(Py_TYPE(o) == __pyx__PyAsyncGenWrappedValueType)
#define __pyx_PyAsyncGenASend_CheckExact(o) \
(Py_TYPE(o) == __pyx__PyAsyncGenASendType)
static
int
static
int
__Pyx_async_gen_traverse
(
__pyx_PyAsyncGenObject
*
gen
,
visitproc
visit
,
void
*
arg
)
__Pyx_async_gen_traverse
(
__pyx_PyAsyncGenObject
*
gen
,
visitproc
visit
,
void
*
arg
)
...
@@ -303,7 +307,7 @@ static PyMethodDef __Pyx_async_gen_methods[] = {
...
@@ -303,7 +307,7 @@ static PyMethodDef __Pyx_async_gen_methods[] = {
};
};
static
PyAsyncMethods
__Pyx_async_gen_as_async
=
{
static
__Pyx_PyAsyncMethodsStruct
__Pyx_async_gen_as_async
=
{
0
,
/* am_await */
0
,
/* am_await */
PyObject_SelfIter
,
/* am_aiter */
PyObject_SelfIter
,
/* am_aiter */
(
unaryfunc
)
__Pyx_async_gen_anext
/* am_anext */
(
unaryfunc
)
__Pyx_async_gen_anext
/* am_anext */
...
@@ -475,12 +479,12 @@ __Pyx_async_gen_asend_send(__pyx_PyAsyncGenASend *o, PyObject *arg)
...
@@ -475,12 +479,12 @@ __Pyx_async_gen_asend_send(__pyx_PyAsyncGenASend *o, PyObject *arg)
if
(
o
->
ags_state
==
__PYX_AWAITABLE_STATE_INIT
)
{
if
(
o
->
ags_state
==
__PYX_AWAITABLE_STATE_INIT
)
{
if
(
arg
==
NULL
||
arg
==
Py_None
)
{
if
(
arg
==
NULL
||
arg
==
Py_None
)
{
arg
=
o
->
ags_sendval
;
arg
=
o
->
ags_sendval
?
o
->
ags_sendval
:
Py_None
;
}
}
o
->
ags_state
=
__PYX_AWAITABLE_STATE_ITER
;
o
->
ags_state
=
__PYX_AWAITABLE_STATE_ITER
;
}
}
result
=
__Pyx_Coroutine_SendEx
((
__pyx_CoroutineObject
*
)
o
->
ags_gen
,
arg
);
result
=
__Pyx_Coroutine_SendEx
((
__pyx_CoroutineObject
*
)
o
->
ags_gen
,
arg
,
0
);
result
=
__Pyx_async_gen_unwrap_value
(
o
->
ags_gen
,
result
);
result
=
__Pyx_async_gen_unwrap_value
(
o
->
ags_gen
,
result
);
if
(
result
==
NULL
)
{
if
(
result
==
NULL
)
{
...
@@ -494,7 +498,7 @@ __Pyx_async_gen_asend_send(__pyx_PyAsyncGenASend *o, PyObject *arg)
...
@@ -494,7 +498,7 @@ __Pyx_async_gen_asend_send(__pyx_PyAsyncGenASend *o, PyObject *arg)
static
PyObject
*
static
PyObject
*
__Pyx_async_gen_asend_iternext
(
__pyx_PyAsyncGenASend
*
o
)
__Pyx_async_gen_asend_iternext
(
__pyx_PyAsyncGenASend
*
o
)
{
{
return
__Pyx_async_gen_asend_send
(
o
,
NULL
);
return
__Pyx_async_gen_asend_send
(
o
,
Py_None
);
}
}
...
@@ -535,7 +539,7 @@ static PyMethodDef __Pyx_async_gen_asend_methods[] = {
...
@@ -535,7 +539,7 @@ static PyMethodDef __Pyx_async_gen_asend_methods[] = {
};
};
static
PyAsyncMethods
__Pyx_async_gen_asend_as_async
=
{
static
__Pyx_PyAsyncMethodsStruct
__Pyx_async_gen_asend_as_async
=
{
PyObject_SelfIter
,
/* am_await */
PyObject_SelfIter
,
/* am_await */
0
,
/* am_aiter */
0
,
/* am_aiter */
0
/* am_anext */
0
/* am_anext */
...
@@ -824,7 +828,7 @@ __Pyx_async_gen_athrow_send(__pyx_PyAsyncGenAThrow *o, PyObject *arg)
...
@@ -824,7 +828,7 @@ __Pyx_async_gen_athrow_send(__pyx_PyAsyncGenAThrow *o, PyObject *arg)
assert
(
o
->
agt_state
==
__PYX_AWAITABLE_STATE_ITER
);
assert
(
o
->
agt_state
==
__PYX_AWAITABLE_STATE_ITER
);
retval
=
__Pyx_Coroutine_SendEx
((
__pyx_CoroutineObject
*
)
gen
,
arg
);
retval
=
__Pyx_Coroutine_SendEx
((
__pyx_CoroutineObject
*
)
gen
,
arg
,
0
);
if
(
o
->
agt_args
)
{
if
(
o
->
agt_args
)
{
return
__Pyx_async_gen_unwrap_value
(
o
->
agt_gen
,
retval
);
return
__Pyx_async_gen_unwrap_value
(
o
->
agt_gen
,
retval
);
}
else
{
}
else
{
...
@@ -921,7 +925,7 @@ static PyMethodDef __Pyx_async_gen_athrow_methods[] = {
...
@@ -921,7 +925,7 @@ static PyMethodDef __Pyx_async_gen_athrow_methods[] = {
};
};
static
PyAsyncMethods
__Pyx_async_gen_athrow_as_async
=
{
static
__Pyx_PyAsyncMethodsStruct
__Pyx_async_gen_athrow_as_async
=
{
PyObject_SelfIter
,
/* am_await */
PyObject_SelfIter
,
/* am_await */
0
,
/* am_aiter */
0
,
/* am_aiter */
0
/* am_anext */
0
/* am_anext */
...
...
Cython/Utility/Coroutine.c
View file @
4b8cedab
...
@@ -85,6 +85,16 @@ static CYTHON_INLINE PyObject* __Pyx__Coroutine_Yield_From(__pyx_CoroutineObject
...
@@ -85,6 +85,16 @@ static CYTHON_INLINE PyObject* __Pyx__Coroutine_Yield_From(__pyx_CoroutineObject
gen
->
yieldfrom
=
source
;
gen
->
yieldfrom
=
source
;
return
retval
;
return
retval
;
}
}
#ifdef __Pyx_AsyncGen_USED
// inlined "__pyx_PyAsyncGenASend" handling to avoid the series of generic calls below
}
else
if
(
__pyx_PyAsyncGenASend_CheckExact
(
source
))
{
retval
=
__Pyx_async_gen_asend_iternext
((
__pyx_PyAsyncGenASend
*
)
source
);
if
(
retval
)
{
Py_INCREF
(
source
);
gen
->
yieldfrom
=
source
;
return
retval
;
}
#endif
}
else
{
}
else
{
PyObject
*
source_gen
=
__Pyx__Coroutine_GetAwaitableIter
(
source
);
PyObject
*
source_gen
=
__Pyx__Coroutine_GetAwaitableIter
(
source
);
if
(
unlikely
(
!
source_gen
))
if
(
unlikely
(
!
source_gen
))
...
@@ -292,7 +302,7 @@ static CYTHON_INLINE PyObject *__Pyx_Coroutine_GetAsyncIter(PyObject *obj) {
...
@@ -292,7 +302,7 @@ static CYTHON_INLINE PyObject *__Pyx_Coroutine_GetAsyncIter(PyObject *obj) {
static
CYTHON_INLINE
PyObject
*
__Pyx_Coroutine_AsyncIterNext
(
PyObject
*
obj
)
{
static
CYTHON_INLINE
PyObject
*
__Pyx_Coroutine_AsyncIterNext
(
PyObject
*
obj
)
{
#ifdef __Pyx_AsyncGen_USED
#ifdef __Pyx_AsyncGen_USED
if
(
__Pyx_AsyncGen_CheckExact
(
obj
))
{
if
(
__Pyx_AsyncGen_CheckExact
(
obj
))
{
return
__Pyx_async_gen_anext
(
obj
);
return
__Pyx_async_gen_anext
(
(
__pyx_PyAsyncGenObject
*
)
obj
);
}
}
#endif
#endif
#if CYTHON_USE_ASYNC_SLOTS
#if CYTHON_USE_ASYNC_SLOTS
...
@@ -320,22 +330,41 @@ static CYTHON_INLINE PyObject *__Pyx_Coroutine_AsyncIterNext(PyObject *obj) {
...
@@ -320,22 +330,41 @@ static CYTHON_INLINE PyObject *__Pyx_Coroutine_AsyncIterNext(PyObject *obj) {
//////////////////// pep479.proto ////////////////////
//////////////////// pep479.proto ////////////////////
static
void
__Pyx_Generator_Replace_StopIteration
(
void
);
/*proto*/
static
void
__Pyx_Generator_Replace_StopIteration
(
int
in_async_gen
);
/*proto*/
//////////////////// pep479 ////////////////////
//////////////////// pep479 ////////////////////
//@requires: Exceptions.c::GetException
//@requires: Exceptions.c::GetException
static
void
__Pyx_Generator_Replace_StopIteration
(
void
)
{
static
void
__Pyx_Generator_Replace_StopIteration
(
CYTHON_UNUSED
int
in_async_gen
)
{
PyObject
*
exc
,
*
val
,
*
tb
;
PyObject
*
exc
,
*
val
,
*
tb
,
*
cur_exc
;
// Chain exceptions by moving StopIteration to exc_info before creating the RuntimeError.
// In Py2.x, no chaining happens, but the exception still stays visible in exc_info.
__Pyx_PyThreadState_declare
__Pyx_PyThreadState_declare
#ifdef __Pyx_StopAsyncIteration_USED
int
is_async_stopiteration
=
0
;
#endif
cur_exc
=
PyErr_Occurred
();
if
(
likely
(
!
PyErr_GivenExceptionMatches
(
cur_exc
,
PyExc_StopIteration
)))
{
#ifdef __Pyx_StopAsyncIteration_USED
if
(
in_async_gen
&&
unlikely
(
PyErr_GivenExceptionMatches
(
cur_exc
,
__Pyx_PyExc_StopAsyncIteration
)))
{
is_async_stopiteration
=
1
;
}
else
#endif
return
;
}
__Pyx_PyThreadState_assign
__Pyx_PyThreadState_assign
// Chain exceptions by moving Stop(Async)Iteration to exc_info before creating the RuntimeError.
// In Py2.x, no chaining happens, but the exception still stays visible in exc_info.
__Pyx_GetException
(
&
exc
,
&
val
,
&
tb
);
__Pyx_GetException
(
&
exc
,
&
val
,
&
tb
);
Py_XDECREF
(
exc
);
Py_XDECREF
(
exc
);
Py_XDECREF
(
val
);
Py_XDECREF
(
val
);
Py_XDECREF
(
tb
);
Py_XDECREF
(
tb
);
PyErr_SetString
(
PyExc_RuntimeError
,
"generator raised StopIteration"
);
PyErr_SetString
(
PyExc_RuntimeError
,
#ifdef __Pyx_StopAsyncIteration_USED
is_async_stopiteration
?
"async generator raised StopAsyncIteration"
:
in_async_gen
?
"async generator raised StopIteration"
:
#endif
"generator raised StopIteration"
);
}
}
...
@@ -567,7 +596,7 @@ int __Pyx_Coroutine_CheckRunning(__pyx_CoroutineObject *gen) {
...
@@ -567,7 +596,7 @@ int __Pyx_Coroutine_CheckRunning(__pyx_CoroutineObject *gen) {
}
}
static
CYTHON_INLINE
static
CYTHON_INLINE
PyObject
*
__Pyx_Coroutine_SendEx
(
__pyx_CoroutineObject
*
self
,
PyObject
*
value
)
{
PyObject
*
__Pyx_Coroutine_SendEx
(
__pyx_CoroutineObject
*
self
,
PyObject
*
value
,
int
closing
)
{
PyObject
*
retval
;
PyObject
*
retval
;
__Pyx_PyThreadState_declare
__Pyx_PyThreadState_declare
...
@@ -594,12 +623,22 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
...
@@ -594,12 +623,22 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
}
}
if
(
unlikely
(
self
->
resume_label
==
-
1
))
{
if
(
unlikely
(
self
->
resume_label
==
-
1
))
{
if
(
!
closing
&&
__Pyx_Coroutine_CheckExact
((
PyObject
*
)
self
))
{
// `self` is an exhausted coroutine: raise an error,
// except when called from gen_close(), which should
// always be a silent method.
PyErr_SetString
(
PyExc_RuntimeError
,
"cannot reuse already awaited coroutine"
);
}
else
if
(
value
)
{
// `gen` is an exhausted generator:
// only set exception if called from send().
#ifdef __Pyx_AsyncGen_USED
#ifdef __Pyx_AsyncGen_USED
if
(
__Pyx_AsyncGen_CheckExact
((
PyObject
*
)
self
))
if
(
__Pyx_AsyncGen_CheckExact
((
PyObject
*
)
self
))
PyErr_SetNone
(
__Pyx_PyExc_StopAsyncIteration
);
PyErr_SetNone
(
__Pyx_PyExc_StopAsyncIteration
);
else
else
#endif
#endif
PyErr_SetNone
(
PyExc_StopIteration
);
PyErr_SetNone
(
PyExc_StopIteration
);
}
return
NULL
;
return
NULL
;
}
}
...
@@ -652,9 +691,14 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
...
@@ -652,9 +691,14 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
}
}
static
CYTHON_INLINE
static
CYTHON_INLINE
PyObject
*
__Pyx_Coroutine_MethodReturn
(
PyObject
*
retval
)
{
PyObject
*
__Pyx_Coroutine_MethodReturn
(
PyObject
*
gen
,
PyObject
*
retval
)
{
if
(
unlikely
(
!
retval
&&
!
PyErr_Occurred
()))
{
if
(
unlikely
(
!
retval
&&
!
PyErr_Occurred
()))
{
// method call must not terminate with NULL without setting an exception
// method call must not terminate with NULL without setting an exception
#ifdef __Pyx_AsyncGen_USED
if
(
__Pyx_AsyncGen_CheckExact
(
gen
))
{
PyErr_SetNone
(
__Pyx_PyExc_StopAsyncIteration
);
}
else
#endif
PyErr_SetNone
(
PyExc_StopIteration
);
PyErr_SetNone
(
PyExc_StopIteration
);
}
}
return
retval
;
return
retval
;
...
@@ -667,7 +711,7 @@ PyObject *__Pyx_Coroutine_FinishDelegation(__pyx_CoroutineObject *gen) {
...
@@ -667,7 +711,7 @@ PyObject *__Pyx_Coroutine_FinishDelegation(__pyx_CoroutineObject *gen) {
__Pyx_Coroutine_Undelegate
(
gen
);
__Pyx_Coroutine_Undelegate
(
gen
);
__Pyx_PyGen_FetchStopIterationValue
(
&
val
);
__Pyx_PyGen_FetchStopIterationValue
(
&
val
);
// val == NULL on failure => pass on exception
// val == NULL on failure => pass on exception
ret
=
__Pyx_Coroutine_SendEx
(
gen
,
val
);
ret
=
__Pyx_Coroutine_SendEx
(
gen
,
val
,
0
);
Py_XDECREF
(
val
);
Py_XDECREF
(
val
);
return
ret
;
return
ret
;
}
}
...
@@ -693,6 +737,11 @@ static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) {
...
@@ -693,6 +737,11 @@ static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) {
ret
=
__Pyx_Coroutine_Send
(
yf
,
value
);
ret
=
__Pyx_Coroutine_Send
(
yf
,
value
);
}
else
}
else
#endif
#endif
#ifdef __Pyx_AsyncGen_USED
if
(
__pyx_PyAsyncGenASend_CheckExact
(
yf
))
{
ret
=
__Pyx_async_gen_asend_send
((
__pyx_PyAsyncGenASend
*
)
yf
,
value
);
}
else
#endif
{
{
if
(
value
==
Py_None
)
if
(
value
==
Py_None
)
ret
=
Py_TYPE
(
yf
)
->
tp_iternext
(
yf
);
ret
=
Py_TYPE
(
yf
)
->
tp_iternext
(
yf
);
...
@@ -706,9 +755,9 @@ static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) {
...
@@ -706,9 +755,9 @@ static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) {
}
}
retval
=
__Pyx_Coroutine_FinishDelegation
(
gen
);
retval
=
__Pyx_Coroutine_FinishDelegation
(
gen
);
}
else
{
}
else
{
retval
=
__Pyx_Coroutine_SendEx
(
gen
,
value
);
retval
=
__Pyx_Coroutine_SendEx
(
gen
,
value
,
0
);
}
}
return
__Pyx_Coroutine_MethodReturn
(
retval
);
return
__Pyx_Coroutine_MethodReturn
(
self
,
retval
);
}
}
// This helper function is used by gen_close and gen_throw to
// This helper function is used by gen_close and gen_throw to
...
@@ -776,7 +825,7 @@ static PyObject *__Pyx_Generator_Next(PyObject *self) {
...
@@ -776,7 +825,7 @@ static PyObject *__Pyx_Generator_Next(PyObject *self) {
}
}
return
__Pyx_Coroutine_FinishDelegation
(
gen
);
return
__Pyx_Coroutine_FinishDelegation
(
gen
);
}
}
return
__Pyx_Coroutine_SendEx
(
gen
,
Py_None
);
return
__Pyx_Coroutine_SendEx
(
gen
,
Py_None
,
0
);
}
}
static
PyObject
*
__Pyx_Coroutine_Close
(
PyObject
*
self
)
{
static
PyObject
*
__Pyx_Coroutine_Close
(
PyObject
*
self
)
{
...
@@ -796,7 +845,7 @@ static PyObject *__Pyx_Coroutine_Close(PyObject *self) {
...
@@ -796,7 +845,7 @@ static PyObject *__Pyx_Coroutine_Close(PyObject *self) {
}
}
if
(
err
==
0
)
if
(
err
==
0
)
PyErr_SetNone
(
PyExc_GeneratorExit
);
PyErr_SetNone
(
PyExc_GeneratorExit
);
retval
=
__Pyx_Coroutine_SendEx
(
gen
,
NULL
);
retval
=
__Pyx_Coroutine_SendEx
(
gen
,
NULL
,
1
);
if
(
retval
)
{
if
(
retval
)
{
const
char
*
msg
;
const
char
*
msg
;
Py_DECREF
(
retval
);
Py_DECREF
(
retval
);
...
@@ -841,12 +890,15 @@ static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject
...
@@ -841,12 +890,15 @@ static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject
if
(
yf
)
{
if
(
yf
)
{
PyObject
*
ret
;
PyObject
*
ret
;
Py_INCREF
(
yf
);
Py_INCREF
(
yf
);
if
(
PyErr_GivenExceptionMatches
(
typ
,
PyExc_GeneratorExit
))
{
if
(
PyErr_GivenExceptionMatches
(
typ
,
PyExc_GeneratorExit
)
&&
close_on_genexit
)
{
// Asynchronous generators *should not* be closed right away.
// We have to allow some awaits to work it through, hence the
// `close_on_genexit` parameter here.
int
err
=
__Pyx_Coroutine_CloseIter
(
gen
,
yf
);
int
err
=
__Pyx_Coroutine_CloseIter
(
gen
,
yf
);
Py_DECREF
(
yf
);
Py_DECREF
(
yf
);
__Pyx_Coroutine_Undelegate
(
gen
);
__Pyx_Coroutine_Undelegate
(
gen
);
if
(
err
<
0
)
if
(
err
<
0
)
return
__Pyx_Coroutine_MethodReturn
(
__Pyx_Coroutine_SendEx
(
gen
,
NULL
));
return
__Pyx_Coroutine_MethodReturn
(
self
,
__Pyx_Coroutine_SendEx
(
gen
,
NULL
,
0
));
goto
throw_here
;
goto
throw_here
;
}
}
gen
->
is_running
=
1
;
gen
->
is_running
=
1
;
...
@@ -888,11 +940,11 @@ static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject
...
@@ -888,11 +940,11 @@ static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject
if
(
!
ret
)
{
if
(
!
ret
)
{
ret
=
__Pyx_Coroutine_FinishDelegation
(
gen
);
ret
=
__Pyx_Coroutine_FinishDelegation
(
gen
);
}
}
return
__Pyx_Coroutine_MethodReturn
(
ret
);
return
__Pyx_Coroutine_MethodReturn
(
self
,
ret
);
}
}
throw_here:
throw_here:
__Pyx_Raise
(
typ
,
val
,
tb
,
NULL
);
__Pyx_Raise
(
typ
,
val
,
tb
,
NULL
);
return
__Pyx_Coroutine_MethodReturn
(
__Pyx_Coroutine_SendEx
(
gen
,
NULL
));
return
__Pyx_Coroutine_MethodReturn
(
self
,
__Pyx_Coroutine_SendEx
(
gen
,
NULL
,
0
));
}
}
static
PyObject
*
__Pyx_Coroutine_Throw
(
PyObject
*
self
,
PyObject
*
args
)
{
static
PyObject
*
__Pyx_Coroutine_Throw
(
PyObject
*
self
,
PyObject
*
args
)
{
...
@@ -958,6 +1010,14 @@ static void __Pyx_Coroutine_dealloc(PyObject *self) {
...
@@ -958,6 +1010,14 @@ static void __Pyx_Coroutine_dealloc(PyObject *self) {
PyObject_GC_UnTrack
(
self
);
PyObject_GC_UnTrack
(
self
);
}
}
#ifdef __Pyx_AsyncGen_USED
if
(
__Pyx_AsyncGen_CheckExact
(
self
))
{
/* We have to handle this case for asynchronous generators
right here, because this code has to be between UNTRACK
and GC_Del. */
Py_CLEAR
(((
__pyx_PyAsyncGenObject
*
)
self
)
->
ag_finalizer
);
}
#endif
__Pyx_Coroutine_clear
(
self
);
__Pyx_Coroutine_clear
(
self
);
PyObject_GC_Del
(
gen
);
PyObject_GC_Del
(
gen
);
}
}
...
@@ -977,8 +1037,31 @@ static void __Pyx_Coroutine_del(PyObject *self) {
...
@@ -977,8 +1037,31 @@ static void __Pyx_Coroutine_del(PyObject *self) {
self
->
ob_refcnt
=
1
;
self
->
ob_refcnt
=
1
;
#endif
#endif
// Save the current exception, if any.
__Pyx_PyThreadState_assign
__Pyx_PyThreadState_assign
#ifdef __Pyx_AsyncGen_USED
if
(
__Pyx_AsyncGen_CheckExact
(
self
))
{
__pyx_PyAsyncGenObject
*
agen
=
(
__pyx_PyAsyncGenObject
*
)
self
;
PyObject
*
finalizer
=
agen
->
ag_finalizer
;
if
(
finalizer
&&
!
agen
->
ag_closed
)
{
/* Save the current exception, if any. */
__Pyx_ErrFetch
(
&
error_type
,
&
error_value
,
&
error_traceback
);
res
=
__Pyx_PyObject_CallOneArg
(
finalizer
,
self
);
if
(
res
==
NULL
)
{
PyErr_WriteUnraisable
(
self
);
}
else
{
Py_DECREF
(
res
);
}
/* Restore the saved exception. */
__Pyx_ErrRestore
(
error_type
,
error_value
,
error_traceback
);
return
;
}
}
#endif
// Save the current exception, if any.
__Pyx_ErrFetch
(
&
error_type
,
&
error_value
,
&
error_traceback
);
__Pyx_ErrFetch
(
&
error_type
,
&
error_value
,
&
error_traceback
);
res
=
__Pyx_Coroutine_Close
(
self
);
res
=
__Pyx_Coroutine_Close
(
self
);
...
...
Cython/Utility/ModuleSetupCode.c
View file @
4b8cedab
...
@@ -387,15 +387,17 @@
...
@@ -387,15 +387,17 @@
#define __Pyx_PyAsyncMethodsStruct PyAsyncMethods
#define __Pyx_PyAsyncMethodsStruct PyAsyncMethods
#define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async)
#define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async)
#else
#else
#define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved))
#endif
#else
#define __Pyx_PyType_AsAsync(obj) NULL
#endif
#ifndef __Pyx_PyAsyncMethodsStruct
typedef
struct
{
typedef
struct
{
unaryfunc
am_await
;
unaryfunc
am_await
;
unaryfunc
am_aiter
;
unaryfunc
am_aiter
;
unaryfunc
am_anext
;
unaryfunc
am_anext
;
}
__Pyx_PyAsyncMethodsStruct
;
}
__Pyx_PyAsyncMethodsStruct
;
#define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved))
#endif
#else
#define __Pyx_PyType_AsAsync(obj) NULL
#endif
#endif
// restrict
// restrict
...
...
tests/run/test_asyncgen.py
0 → 100644
View file @
4b8cedab
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment