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
Kirill Smelkov
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):
if
type
.
is_pyobject
:
code
.
putln
(
'%s->%s = 0;'
%
(
Naming
.
cur_scope_cname
,
save_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
:
self
.
allocate_temp_result
(
code
)
code
.
put
(
'%s = %s; '
%
(
self
.
result
(),
Naming
.
sent_value_cname
))
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
):
def
yield_from_func
(
self
,
code
):
...
...
@@ -9582,8 +9585,7 @@ class AwaitIterNextExprNode(AwaitExprNode):
#
# Breaks out of loop on StopAsyncIteration exception.
def
fetch_iteration_result
(
self
,
code
):
assert
code
.
break_label
,
"AwaitIterNextExprNode outside of 'async for' loop"
def
_generate_break
(
self
,
code
):
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"StopAsyncIteration"
,
"Coroutine.c"
))
code
.
putln
(
"PyObject* exc_type = PyErr_Occurred();"
)
code
.
putln
(
"if (exc_type && likely(exc_type == __Pyx_PyExc_StopAsyncIteration ||"
...
...
@@ -9591,8 +9593,20 @@ class AwaitIterNextExprNode(AwaitExprNode):
code
.
putln
(
"PyErr_Clear();"
)
code
.
putln
(
"break;"
)
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
)
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
):
type
=
dict_type
...
...
Cython/Compiler/Nodes.py
View file @
4b8cedab
...
...
@@ -4025,19 +4025,19 @@ class AsyncGenNode(AsyncDefNode):
is_asyncgen
=
True
class
GeneratorBodyDefNode
(
DefNode
):
# Main code body of a generator implemented as a DefNode.
#
is_generator_body
=
True
is_inlined
=
False
is_async_gen
=
False
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__
(
pos
=
pos
,
body
=
body
,
name
=
name
,
doc
=
None
,
args
=
[],
star_arg
=
None
,
starstar_arg
=
None
)
pos
=
pos
,
body
=
body
,
name
=
name
,
is_async_gen
=
is_async_gen
,
doc
=
None
,
args
=
[],
star_arg
=
None
,
starstar_arg
=
None
)
def
declare_generator_body
(
self
,
env
):
prefix
=
env
.
next_id
(
env
.
scope_prefix
)
...
...
@@ -4134,9 +4134,10 @@ class GeneratorBodyDefNode(DefNode):
# on normal generator termination, we do not take the exception propagation
# path: no traceback info is required and not creating it is much faster
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
if
code
.
error_label
in
code
.
labels_used
:
if
code
.
label_used
(
code
.
error_label
)
:
if
not
self
.
body
.
is_terminator
:
code
.
put_goto
(
code
.
return_label
)
code
.
put_label
(
code
.
error_label
)
...
...
@@ -4145,8 +4146,7 @@ class GeneratorBodyDefNode(DefNode):
if
Future
.
generator_stop
in
env
.
global_scope
().
context
.
future_directives
:
# PEP 479: turn accidental StopIteration exceptions into a RuntimeError
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
"pep479"
,
"Coroutine.c"
))
code
.
putln
(
"if (unlikely(PyErr_ExceptionMatches(PyExc_StopIteration))) "
"__Pyx_Generator_Replace_StopIteration();"
)
code
.
putln
(
"__Pyx_Generator_Replace_StopIteration(%d);"
%
bool
(
self
.
is_async_gen
))
for
cname
,
type
in
code
.
funcstate
.
all_managed_temps
():
code
.
put_xdecref
(
cname
,
type
)
code
.
put_add_traceback
(
self
.
entry
.
qualified_name
)
...
...
@@ -5583,10 +5583,12 @@ class ReturnStatNode(StatNode):
# value ExprNode or None
# return_type PyrexType
# in_generator return inside of generator => raise StopIteration
# in_async_gen return inside of async generator
child_attrs
=
[
"value"
]
is_terminator
=
True
in_generator
=
False
in_async_gen
=
False
# Whether we are in a parallel section
in_parallel
=
False
...
...
@@ -5598,6 +5600,8 @@ class ReturnStatNode(StatNode):
error
(
self
.
pos
,
"Return not inside a function body"
)
return
self
if
self
.
value
:
if
self
.
in_async_gen
:
error
(
self
.
pos
,
"Return with value in async generator"
)
self
.
value
=
self
.
value
.
analyse_types
(
env
)
if
return_type
.
is_void
or
return_type
.
is_returncode
:
error
(
self
.
value
.
pos
,
"Return with value in void function"
)
...
...
@@ -5654,6 +5658,8 @@ class ReturnStatNode(StatNode):
else
:
if
self
.
return_type
.
is_pyobject
:
if
self
.
in_generator
:
if
self
.
in_async_gen
:
code
.
put
(
"PyErr_SetNone(__Pyx_PyExc_StopAsyncIteration); "
)
code
.
putln
(
"%s = NULL;"
%
Naming
.
retval_cname
)
else
:
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):
if
node
.
is_async_def
:
coroutine_type
=
Nodes
.
AsyncGenNode
if
collector
.
has_yield
else
Nodes
.
AsyncDefNode
if
collector
.
has_yield
:
for
yield_expr
in
collector
.
yields
:
for
yield_expr
in
collector
.
yields
+
collector
.
returns
:
yield_expr
.
in_async_gen
=
True
elif
collector
.
has_await
:
found
=
next
(
y
for
y
in
collector
.
yields
if
y
.
is_await
)
...
...
@@ -2535,7 +2535,8 @@ class MarkClosureVisitor(CythonTransform):
retnode
.
in_generator
=
True
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
(
pos
=
node
.
pos
,
name
=
node
.
name
,
args
=
node
.
args
,
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.
// 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 ////////////////////
//@requires: Coroutine.c::Coroutine
...
...
@@ -12,14 +13,20 @@ typedef struct {
int
ag_closed
;
}
__pyx_PyAsyncGenObject
;
typedef
struct
__pyx_PyAsyncGenASend_struct
__pyx_PyAsyncGenASend
;
static
PyTypeObject
*
__pyx__PyAsyncGenWrappedValueType
=
0
;
static
PyTypeObject
*
__pyx__PyAsyncGenASendType
=
0
;
static
PyTypeObject
*
__pyx__PyAsyncGenAThrowType
=
0
;
static
PyTypeObject
*
__pyx_AsyncGenType
=
0
;
#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
);
...
...
@@ -120,7 +127,7 @@ typedef enum {
__PYX_AWAITABLE_STATE_CLOSED
,
/* closed */
}
__pyx_AwaitableState
;
typedef
struct
{
struct
__pyx_PyAsyncGenASend_
struct
{
PyObject_HEAD
__pyx_PyAsyncGenObject
*
ags_gen
;
...
...
@@ -128,7 +135,7 @@ typedef struct {
PyObject
*
ags_sendval
;
__pyx_AwaitableState
ags_state
;
}
__pyx_PyAsyncGenASend
;
};
typedef
struct
{
...
...
@@ -167,9 +174,6 @@ static int __Pyx_ag_asend_freelist_free = 0;
#define __pyx__PyAsyncGenWrappedValue_CheckExact(o) \
(Py_TYPE(o) == __pyx__PyAsyncGenWrappedValueType)
#define __pyx_PyAsyncGenASend_CheckExact(o) \
(Py_TYPE(o) == __pyx__PyAsyncGenASendType)
static
int
__Pyx_async_gen_traverse
(
__pyx_PyAsyncGenObject
*
gen
,
visitproc
visit
,
void
*
arg
)
...
...
@@ -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 */
PyObject_SelfIter
,
/* am_aiter */
(
unaryfunc
)
__Pyx_async_gen_anext
/* am_anext */
...
...
@@ -475,12 +479,12 @@ __Pyx_async_gen_asend_send(__pyx_PyAsyncGenASend *o, PyObject *arg)
if
(
o
->
ags_state
==
__PYX_AWAITABLE_STATE_INIT
)
{
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
;
}
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
);
if
(
result
==
NULL
)
{
...
...
@@ -494,7 +498,7 @@ __Pyx_async_gen_asend_send(__pyx_PyAsyncGenASend *o, PyObject *arg)
static
PyObject
*
__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[] = {
};
static
PyAsyncMethods
__Pyx_async_gen_asend_as_async
=
{
static
__Pyx_PyAsyncMethodsStruct
__Pyx_async_gen_asend_as_async
=
{
PyObject_SelfIter
,
/* am_await */
0
,
/* am_aiter */
0
/* am_anext */
...
...
@@ -824,7 +828,7 @@ __Pyx_async_gen_athrow_send(__pyx_PyAsyncGenAThrow *o, PyObject *arg)
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
)
{
return
__Pyx_async_gen_unwrap_value
(
o
->
agt_gen
,
retval
);
}
else
{
...
...
@@ -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 */
0
,
/* am_aiter */
0
/* am_anext */
...
...
Cython/Utility/Coroutine.c
View file @
4b8cedab
...
...
@@ -85,6 +85,16 @@ static CYTHON_INLINE PyObject* __Pyx__Coroutine_Yield_From(__pyx_CoroutineObject
gen
->
yieldfrom
=
source
;
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
{
PyObject
*
source_gen
=
__Pyx__Coroutine_GetAwaitableIter
(
source
);
if
(
unlikely
(
!
source_gen
))
...
...
@@ -292,7 +302,7 @@ static CYTHON_INLINE PyObject *__Pyx_Coroutine_GetAsyncIter(PyObject *obj) {
static
CYTHON_INLINE
PyObject
*
__Pyx_Coroutine_AsyncIterNext
(
PyObject
*
obj
)
{
#ifdef __Pyx_AsyncGen_USED
if
(
__Pyx_AsyncGen_CheckExact
(
obj
))
{
return
__Pyx_async_gen_anext
(
obj
);
return
__Pyx_async_gen_anext
(
(
__pyx_PyAsyncGenObject
*
)
obj
);
}
#endif
#if CYTHON_USE_ASYNC_SLOTS
...
...
@@ -320,22 +330,41 @@ static CYTHON_INLINE PyObject *__Pyx_Coroutine_AsyncIterNext(PyObject *obj) {
//////////////////// pep479.proto ////////////////////
static
void
__Pyx_Generator_Replace_StopIteration
(
void
);
/*proto*/
static
void
__Pyx_Generator_Replace_StopIteration
(
int
in_async_gen
);
/*proto*/
//////////////////// pep479 ////////////////////
//@requires: Exceptions.c::GetException
static
void
__Pyx_Generator_Replace_StopIteration
(
void
)
{
PyObject
*
exc
,
*
val
,
*
tb
;
// 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.
static
void
__Pyx_Generator_Replace_StopIteration
(
CYTHON_UNUSED
int
in_async_gen
)
{
PyObject
*
exc
,
*
val
,
*
tb
,
*
cur_exc
;
__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
// 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
);
Py_XDECREF
(
exc
);
Py_XDECREF
(
val
);
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) {
}
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
;
__Pyx_PyThreadState_declare
...
...
@@ -594,12 +623,22 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
}
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
if
(
__Pyx_AsyncGen_CheckExact
((
PyObject
*
)
self
))
PyErr_SetNone
(
__Pyx_PyExc_StopAsyncIteration
);
else
#endif
PyErr_SetNone
(
PyExc_StopIteration
);
}
return
NULL
;
}
...
...
@@ -652,9 +691,14 @@ PyObject *__Pyx_Coroutine_SendEx(__pyx_CoroutineObject *self, PyObject *value) {
}
static
CYTHON_INLINE
PyObject
*
__Pyx_Coroutine_MethodReturn
(
PyObject
*
retval
)
{
PyObject
*
__Pyx_Coroutine_MethodReturn
(
PyObject
*
gen
,
PyObject
*
retval
)
{
if
(
unlikely
(
!
retval
&&
!
PyErr_Occurred
()))
{
// 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
);
}
return
retval
;
...
...
@@ -667,7 +711,7 @@ PyObject *__Pyx_Coroutine_FinishDelegation(__pyx_CoroutineObject *gen) {
__Pyx_Coroutine_Undelegate
(
gen
);
__Pyx_PyGen_FetchStopIterationValue
(
&
val
);
// val == NULL on failure => pass on exception
ret
=
__Pyx_Coroutine_SendEx
(
gen
,
val
);
ret
=
__Pyx_Coroutine_SendEx
(
gen
,
val
,
0
);
Py_XDECREF
(
val
);
return
ret
;
}
...
...
@@ -693,6 +737,11 @@ static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) {
ret
=
__Pyx_Coroutine_Send
(
yf
,
value
);
}
else
#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
)
ret
=
Py_TYPE
(
yf
)
->
tp_iternext
(
yf
);
...
...
@@ -706,9 +755,9 @@ static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) {
}
retval
=
__Pyx_Coroutine_FinishDelegation
(
gen
);
}
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
...
...
@@ -776,7 +825,7 @@ static PyObject *__Pyx_Generator_Next(PyObject *self) {
}
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
)
{
...
...
@@ -796,7 +845,7 @@ static PyObject *__Pyx_Coroutine_Close(PyObject *self) {
}
if
(
err
==
0
)
PyErr_SetNone
(
PyExc_GeneratorExit
);
retval
=
__Pyx_Coroutine_SendEx
(
gen
,
NULL
);
retval
=
__Pyx_Coroutine_SendEx
(
gen
,
NULL
,
1
);
if
(
retval
)
{
const
char
*
msg
;
Py_DECREF
(
retval
);
...
...
@@ -841,12 +890,15 @@ static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject
if
(
yf
)
{
PyObject
*
ret
;
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
);
Py_DECREF
(
yf
);
__Pyx_Coroutine_Undelegate
(
gen
);
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
;
}
gen
->
is_running
=
1
;
...
...
@@ -888,11 +940,11 @@ static PyObject *__Pyx__Coroutine_Throw(PyObject *self, PyObject *typ, PyObject
if
(
!
ret
)
{
ret
=
__Pyx_Coroutine_FinishDelegation
(
gen
);
}
return
__Pyx_Coroutine_MethodReturn
(
ret
);
return
__Pyx_Coroutine_MethodReturn
(
self
,
ret
);
}
throw_here:
__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
)
{
...
...
@@ -958,6 +1010,14 @@ static void __Pyx_Coroutine_dealloc(PyObject *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
);
PyObject_GC_Del
(
gen
);
}
...
...
@@ -977,8 +1037,31 @@ static void __Pyx_Coroutine_del(PyObject *self) {
self
->
ob_refcnt
=
1
;
#endif
// Save the current exception, if any.
__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
);
res
=
__Pyx_Coroutine_Close
(
self
);
...
...
Cython/Utility/ModuleSetupCode.c
View file @
4b8cedab
...
...
@@ -387,15 +387,17 @@
#define __Pyx_PyAsyncMethodsStruct PyAsyncMethods
#define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async)
#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
{
unaryfunc
am_await
;
unaryfunc
am_aiter
;
unaryfunc
am_anext
;
}
__Pyx_PyAsyncMethodsStruct
;
#define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved))
#endif
#else
#define __Pyx_PyType_AsAsync(obj) NULL
#endif
// 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