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
f8c0aafb
Commit
f8c0aafb
authored
May 24, 2015
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
implement some error cases from the PEP 492 test suite
parent
d78673fc
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
137 additions
and
14 deletions
+137
-14
Cython/Utility/Coroutine.c
Cython/Utility/Coroutine.c
+65
-2
tests/run/test_coroutines_pep492.pyx
tests/run/test_coroutines_pep492.pyx
+72
-12
No files found.
Cython/Utility/Coroutine.c
View file @
f8c0aafb
...
...
@@ -8,8 +8,23 @@ static CYTHON_INLINE PyObject* __Pyx_Generator_Yield_From(__pyx_CoroutineObject
static
CYTHON_INLINE
PyObject
*
__Pyx_Generator_Yield_From
(
__pyx_CoroutineObject
*
gen
,
PyObject
*
source
)
{
PyObject
*
source_gen
,
*
retval
;
source_gen
=
PyObject_GetIter
(
source
);
if
(
unlikely
(
!
source_gen
))
if
(
unlikely
(
!
source_gen
))
{
#ifdef __Pyx_Coroutine_USED
#if CYTHON_COMPILING_IN_CPYTHON
// avoid exception instantiation if possible
if
(
PyErr_Occurred
()
==
PyExc_TypeError
#else
if
(
PyErr_ExceptionMatches
(
PyExc_TypeError
)
#endif
&&
__Pyx_Coroutine_CheckExact
(
source
))
{
PyErr_Clear
();
// TODO: this should only happen for types.coroutine()ed generators, but we can't determine that here
Py_INCREF
(
source
);
source_gen
=
source
;
}
else
#endif
return
NULL
;
}
// source_gen is now the iterator, make the first next() call
retval
=
Py_TYPE
(
source_gen
)
->
tp_iternext
(
source_gen
);
if
(
likely
(
retval
))
{
...
...
@@ -871,6 +886,54 @@ static __pyx_CoroutineObject *__Pyx__Coroutine_New(PyTypeObject* type, __pyx_cor
//@requires: CoroutineBase
//@requires: PatchGeneratorABC
static
void
__Pyx_Coroutine_check_and_dealloc
(
PyObject
*
self
)
{
__pyx_CoroutineObject
*
gen
=
(
__pyx_CoroutineObject
*
)
self
;
if
(
gen
->
resume_label
==
0
&&
!
PyErr_Occurred
())
{
#if PY_VERSION_HEX >= 0x03030000 || defined(PyErr_WarnFormat)
PyErr_WarnFormat
(
PyExc_RuntimeWarning
,
1
,
"coroutine '%.50S' was never awaited"
,
gen
->
gi_qualname
);
#else
PyObject
*
msg
,
*
qualname
;
char
*
cname
,
*
cmsg
;
#if PY_MAJOR_VERSION >= 3
qualname
=
PyUnicode_AsUTF8String
(
gen
->
gi_qualname
);
if
(
likely
(
qualname
))
{
cname
=
PyBytes_AS_STRING
(
qualname
);
}
else
{
PyErr_Clear
();
cname
=
(
char
*
)
"?"
;
}
msg
=
PyBytes_FromFormat
(
#else
qualname
=
gen
->
gi_qualname
;
cname
=
PyString_AS_STRING
(
qualname
);
msg
=
PyString_FromFormat
(
#endif
"coroutine '%.50s' was never awaited"
,
cname
);
#if PY_MAJOR_VERSION >= 3
Py_XDECREF
(
qualname
);
#endif
if
(
unlikely
(
!
msg
))
{
PyErr_Clear
();
cmsg
=
(
char
*
)
"coroutine was never awaited"
;
}
else
{
#if PY_MAJOR_VERSION >= 3
cmsg
=
PyBytes_AS_STRING
(
msg
);
#else
cmsg
=
PyString_AS_STRING
(
msg
);
#endif
}
if
(
unlikely
(
PyErr_WarnEx
(
PyExc_RuntimeWarning
,
cmsg
,
1
)
<
0
))
PyErr_WriteUnraisable
(
self
);
Py_XDECREF
(
msg
);
#endif
}
__Pyx_Coroutine_dealloc
(
self
);
}
#if PY_VERSION_HEX >= 0x030500B1
static
PyAsyncMethods
__pyx_Coroutine_as_async
{
0
,
/*am_await*/
...
...
@@ -884,7 +947,7 @@ static PyTypeObject __pyx_CoroutineType_type = {
"coroutine"
,
/*tp_name*/
sizeof
(
__pyx_CoroutineObject
),
/*tp_basicsize*/
0
,
/*tp_itemsize*/
(
destructor
)
__Pyx_Coroutine_dealloc
,
/*tp_dealloc*/
(
destructor
)
__Pyx_Coroutine_
check_and_
dealloc
,
/*tp_dealloc*/
0
,
/*tp_print*/
0
,
/*tp_getattr*/
0
,
/*tp_setattr*/
...
...
tests/run/test_coroutines_pep492.pyx
View file @
f8c0aafb
...
...
@@ -3,7 +3,7 @@
import
re
import
gc
import
sys
import
types
#
import types
import
os.path
import
inspect
import
unittest
...
...
@@ -11,6 +11,35 @@ import warnings
import
contextlib
# fake types.coroutine() decorator
class
types_coroutine
(
object
):
def
__init__
(
self
,
gen
):
self
.
_gen
=
gen
class
as_coroutine
(
object
):
def
__init__
(
self
,
gen
):
self
.
_gen
=
gen
self
.
send
=
gen
.
send
self
.
throw
=
gen
.
throw
self
.
close
=
gen
.
close
def
__await__
(
self
):
return
self
.
_gen
def
__iter__
(
self
):
return
self
.
_gen
def
__call__
(
self
,
*
args
,
**
kwargs
):
return
self
.
as_coroutine
(
self
.
_gen
(
*
args
,
**
kwargs
))
# compiled exec()
def
exec
(
code_string
,
l
,
g
):
from
Cython.Shadow
import
inline
ns
=
inline
(
code_string
,
locals
=
l
,
globals
=
g
,
lib_dir
=
os
.
path
.
dirname
(
__file__
))
g
.
update
(
ns
)
class
AsyncYieldFrom
:
def
__init__
(
self
,
obj
):
self
.
obj
=
obj
...
...
@@ -29,7 +58,7 @@ class AsyncYield:
def
run_async
(
coro
):
#assert coro.__class__ is types.GeneratorType
assert
coro
.
__class__
.
__name__
==
'coroutine'
assert
coro
.
__class__
.
__name__
in
(
'coroutine'
,
'as_coroutine'
)
buffer
=
[]
result
=
None
...
...
@@ -53,9 +82,6 @@ def silence_coro_gc():
class
TokenizerRegrTest
(
unittest
.
TestCase
):
def
test_oneline_defs
(
self
):
import
Cython.Shadow
compile_dir
=
os
.
path
.
dirname
(
__file__
)
buf
=
[]
for
i
in
range
(
500
):
buf
.
append
(
'def i{i}(): return {i}'
.
format
(
i
=
i
))
...
...
@@ -63,16 +89,14 @@ class TokenizerRegrTest(unittest.TestCase):
# Test that 500 consequent, one-line defs is OK
ns
=
{}
#exec(buf, ns, ns)
ns
=
Cython
.
Shadow
.
inline
(
buf
,
locals
=
ns
,
globals
=
ns
,
lib_dir
=
compile_dir
)
exec
(
buf
,
ns
,
ns
)
self
.
assertEqual
(
ns
[
'i499'
](),
499
)
# Test that 500 consequent, one-line defs *and*
# one 'async def' following them is OK
buf
+=
'
\
n
async def foo():
\
n
return'
ns
=
{}
#exec(buf, ns, ns)
ns
=
Cython
.
Shadow
.
inline
(
buf
,
locals
=
ns
,
globals
=
ns
,
lib_dir
=
compile_dir
)
exec
(
buf
,
ns
,
ns
)
self
.
assertEqual
(
ns
[
'i499'
](),
499
)
if
hasattr
(
inspect
,
'iscoroutinefunction'
):
self
.
assertTrue
(
inspect
.
iscoroutinefunction
(
ns
[
'foo'
]))
...
...
@@ -80,6 +104,20 @@ class TokenizerRegrTest(unittest.TestCase):
class
CoroutineTest
(
unittest
.
TestCase
):
def
setUpClass
(
cls
):
# never mark warnings as "already seen" to prevent them from being suppressed
from
warnings
import
simplefilter
simplefilter
(
"always"
)
@
contextlib
.
contextmanager
def
assertRaises
(
self
,
exc_type
):
try
:
yield
except
exc_type
:
self
.
assertTrue
(
True
)
else
:
self
.
assertTrue
(
False
)
@
contextlib
.
contextmanager
def
assertRaisesRegex
(
self
,
exc_type
,
regex
):
# the error messages usually don't match, so we just ignore them
...
...
@@ -90,6 +128,28 @@ class CoroutineTest(unittest.TestCase):
else
:
self
.
assertTrue
(
False
)
@
contextlib
.
contextmanager
def
assertWarnsRegex
(
self
,
exc_type
,
regex
):
from
warnings
import
catch_warnings
with
catch_warnings
(
record
=
True
)
as
log
:
yield
first_match
=
None
for
warning
in
log
:
w
=
warning
.
message
if
not
isinstance
(
w
,
exc_type
):
continue
if
first_match
is
None
:
first_match
=
w
if
re
.
search
(
regex
,
str
(
w
)):
self
.
assertTrue
(
True
)
return
if
first_match
is
None
:
self
.
assertTrue
(
False
,
"no warning was raised of type '%s'"
%
exc_type
.
__name__
)
else
:
self
.
assertTrue
(
False
,
"'%s' did not match '%s'"
%
(
first_match
,
regex
))
def
assertRegex
(
self
,
value
,
regex
):
self
.
assertTrue
(
re
.
search
(
regex
,
str
(
value
)),
"'%s' did not match '%s'"
%
(
value
,
regex
))
...
...
@@ -160,7 +220,7 @@ class CoroutineTest(unittest.TestCase):
[
i
for
i
in
foo
()]
def
test_func_5
(
self
):
@
types
.
coroutine
@
types
_
coroutine
def
bar
():
yield
1
...
...
@@ -181,7 +241,7 @@ class CoroutineTest(unittest.TestCase):
self
.
assertEqual
(
next
(
iter
(
bar
())),
1
)
def
test_func_6
(
self
):
@
types
.
coroutine
@
types
_
coroutine
def
bar
():
yield
1
yield
2
...
...
@@ -209,7 +269,7 @@ class CoroutineTest(unittest.TestCase):
list
(
foo
())
def
test_func_8
(
self
):
@
types
.
coroutine
@
types
_
coroutine
def
bar
():
return
(
yield
from
foo
())
...
...
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