Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
3e48b38d
Kaydet (Commit)
3e48b38d
authored
Şub 13, 2016
tarafından
Yury Selivanov
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Sade Fark
Merge 3.5 (issue #25887)
üst
6f79c2c8
77c96813
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
169 additions
and
12 deletions
+169
-12
datamodel.rst
Doc/reference/datamodel.rst
+4
-0
test_coroutines.py
Lib/test/test_coroutines.py
+141
-0
NEWS
Misc/NEWS
+3
-0
genobject.c
Objects/genobject.c
+21
-12
No files found.
Doc/reference/datamodel.rst
Dosyayı görüntüle @
3e48b38d
...
...
@@ -2317,6 +2317,10 @@ Coroutines also have the methods listed below, which are analogous to
those of generators (see :ref:`generator-methods`). However, unlike
generators, coroutines do not directly support iteration.
.. versionchanged:: 3.5.2
It is a :exc:`RuntimeError` to await on a coroutine more than once.
.. method:: coroutine.send(value)
Starts or resumes execution of the coroutine. If *value* is ``None``,
...
...
Lib/test/test_coroutines.py
Dosyayı görüntüle @
3e48b38d
...
...
@@ -569,6 +569,147 @@ class CoroutineTest(unittest.TestCase):
"coroutine ignored GeneratorExit"
):
c
.
close
()
def
test_func_15
(
self
):
# See http://bugs.python.org/issue25887 for details
async
def
spammer
():
return
'spam'
async
def
reader
(
coro
):
return
await
coro
spammer_coro
=
spammer
()
with
self
.
assertRaisesRegex
(
StopIteration
,
'spam'
):
reader
(
spammer_coro
)
.
send
(
None
)
with
self
.
assertRaisesRegex
(
RuntimeError
,
'cannot reuse already awaited coroutine'
):
reader
(
spammer_coro
)
.
send
(
None
)
def
test_func_16
(
self
):
# See http://bugs.python.org/issue25887 for details
@types.coroutine
def
nop
():
yield
async
def
send
():
await
nop
()
return
'spam'
async
def
read
(
coro
):
await
nop
()
return
await
coro
spammer
=
send
()
reader
=
read
(
spammer
)
reader
.
send
(
None
)
reader
.
send
(
None
)
with
self
.
assertRaisesRegex
(
Exception
,
'ham'
):
reader
.
throw
(
Exception
(
'ham'
))
reader
=
read
(
spammer
)
reader
.
send
(
None
)
with
self
.
assertRaisesRegex
(
RuntimeError
,
'cannot reuse already awaited coroutine'
):
reader
.
send
(
None
)
with
self
.
assertRaisesRegex
(
RuntimeError
,
'cannot reuse already awaited coroutine'
):
reader
.
throw
(
Exception
(
'wat'
))
def
test_func_17
(
self
):
# See http://bugs.python.org/issue25887 for details
async
def
coroutine
():
return
'spam'
coro
=
coroutine
()
with
self
.
assertRaisesRegex
(
StopIteration
,
'spam'
):
coro
.
send
(
None
)
with
self
.
assertRaisesRegex
(
RuntimeError
,
'cannot reuse already awaited coroutine'
):
coro
.
send
(
None
)
with
self
.
assertRaisesRegex
(
RuntimeError
,
'cannot reuse already awaited coroutine'
):
coro
.
throw
(
Exception
(
'wat'
))
# Closing a coroutine shouldn't raise any exception even if it's
# already closed/exhausted (similar to generators)
coro
.
close
()
coro
.
close
()
def
test_func_18
(
self
):
# See http://bugs.python.org/issue25887 for details
async
def
coroutine
():
return
'spam'
coro
=
coroutine
()
await_iter
=
coro
.
__await__
()
it
=
iter
(
await_iter
)
with
self
.
assertRaisesRegex
(
StopIteration
,
'spam'
):
it
.
send
(
None
)
with
self
.
assertRaisesRegex
(
RuntimeError
,
'cannot reuse already awaited coroutine'
):
it
.
send
(
None
)
with
self
.
assertRaisesRegex
(
RuntimeError
,
'cannot reuse already awaited coroutine'
):
# Although the iterator protocol requires iterators to
# raise another StopIteration here, we don't want to do
# that. In this particular case, the iterator will raise
# a RuntimeError, so that 'yield from' and 'await'
# expressions will trigger the error, instead of silently
# ignoring the call.
next
(
it
)
with
self
.
assertRaisesRegex
(
RuntimeError
,
'cannot reuse already awaited coroutine'
):
it
.
throw
(
Exception
(
'wat'
))
with
self
.
assertRaisesRegex
(
RuntimeError
,
'cannot reuse already awaited coroutine'
):
it
.
throw
(
Exception
(
'wat'
))
# Closing a coroutine shouldn't raise any exception even if it's
# already closed/exhausted (similar to generators)
it
.
close
()
it
.
close
()
def
test_func_19
(
self
):
CHK
=
0
@types.coroutine
def
foo
():
nonlocal
CHK
yield
try
:
yield
except
GeneratorExit
:
CHK
+=
1
async
def
coroutine
():
await
foo
()
coro
=
coroutine
()
coro
.
send
(
None
)
coro
.
send
(
None
)
self
.
assertEqual
(
CHK
,
0
)
coro
.
close
()
self
.
assertEqual
(
CHK
,
1
)
for
_
in
range
(
3
):
# Closing a coroutine shouldn't raise any exception even if it's
# already closed/exhausted (similar to generators)
coro
.
close
()
self
.
assertEqual
(
CHK
,
1
)
def
test_cr_await
(
self
):
@types.coroutine
def
a
():
...
...
Misc/NEWS
Dosyayı görüntüle @
3e48b38d
...
...
@@ -180,6 +180,9 @@ Core and Builtins
single
-
digit
longs
.
Microbenchmarks
show
2
-
2.5
x
improvement
.
Built
-
in
'divmod'
function
is
now
also
~
10
%
faster
.
-
Issue
#
25887
:
Raise
a
RuntimeError
when
a
coroutine
object
is
awaited
more
than
once
.
Library
-------
...
...
Objects/genobject.c
Dosyayı görüntüle @
3e48b38d
...
...
@@ -78,7 +78,7 @@ gen_dealloc(PyGenObject *gen)
}
static
PyObject
*
gen_send_ex
(
PyGenObject
*
gen
,
PyObject
*
arg
,
int
exc
)
gen_send_ex
(
PyGenObject
*
gen
,
PyObject
*
arg
,
int
exc
,
int
closing
)
{
PyThreadState
*
tstate
=
PyThreadState_GET
();
PyFrameObject
*
f
=
gen
->
gi_frame
;
...
...
@@ -92,9 +92,18 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc)
return
NULL
;
}
if
(
f
==
NULL
||
f
->
f_stacktop
==
NULL
)
{
/* Only set exception if called from send() */
if
(
arg
&&
!
exc
)
if
(
PyCoro_CheckExact
(
gen
)
&&
!
closing
)
{
/* `gen` 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
(
arg
&&
!
exc
)
{
/* `gen` is an exhausted generator:
only set exception if called from send(). */
PyErr_SetNone
(
PyExc_StopIteration
);
}
return
NULL
;
}
...
...
@@ -220,7 +229,7 @@ return next yielded value or raise StopIteration.");
PyObject
*
_PyGen_Send
(
PyGenObject
*
gen
,
PyObject
*
arg
)
{
return
gen_send_ex
(
gen
,
arg
,
0
);
return
gen_send_ex
(
gen
,
arg
,
0
,
0
);
}
PyDoc_STRVAR
(
close_doc
,
...
...
@@ -292,7 +301,7 @@ gen_close(PyGenObject *gen, PyObject *args)
}
if
(
err
==
0
)
PyErr_SetNone
(
PyExc_GeneratorExit
);
retval
=
gen_send_ex
(
gen
,
Py_None
,
1
);
retval
=
gen_send_ex
(
gen
,
Py_None
,
1
,
1
);
if
(
retval
)
{
char
*
msg
=
"generator ignored GeneratorExit"
;
if
(
PyCoro_CheckExact
(
gen
))
...
...
@@ -336,7 +345,7 @@ gen_throw(PyGenObject *gen, PyObject *args)
gen
->
gi_running
=
0
;
Py_DECREF
(
yf
);
if
(
err
<
0
)
return
gen_send_ex
(
gen
,
Py_None
,
1
);
return
gen_send_ex
(
gen
,
Py_None
,
1
,
0
);
goto
throw_here
;
}
if
(
PyGen_CheckExact
(
yf
))
{
...
...
@@ -369,10 +378,10 @@ gen_throw(PyGenObject *gen, PyObject *args)
/* Termination repetition of YIELD_FROM */
gen
->
gi_frame
->
f_lasti
++
;
if
(
_PyGen_FetchStopIterationValue
(
&
val
)
==
0
)
{
ret
=
gen_send_ex
(
gen
,
val
,
0
);
ret
=
gen_send_ex
(
gen
,
val
,
0
,
0
);
Py_DECREF
(
val
);
}
else
{
ret
=
gen_send_ex
(
gen
,
Py_None
,
1
);
ret
=
gen_send_ex
(
gen
,
Py_None
,
1
,
0
);
}
}
return
ret
;
...
...
@@ -426,7 +435,7 @@ throw_here:
}
PyErr_Restore
(
typ
,
val
,
tb
);
return
gen_send_ex
(
gen
,
Py_None
,
1
);
return
gen_send_ex
(
gen
,
Py_None
,
1
,
0
);
failed_throw:
/* Didn't use our arguments, so restore their original refcounts */
...
...
@@ -440,7 +449,7 @@ failed_throw:
static
PyObject
*
gen_iternext
(
PyGenObject
*
gen
)
{
return
gen_send_ex
(
gen
,
NULL
,
0
);
return
gen_send_ex
(
gen
,
NULL
,
0
,
0
);
}
/*
...
...
@@ -893,13 +902,13 @@ coro_wrapper_dealloc(PyCoroWrapper *cw)
static
PyObject
*
coro_wrapper_iternext
(
PyCoroWrapper
*
cw
)
{
return
gen_send_ex
((
PyGenObject
*
)
cw
->
cw_coroutine
,
NULL
,
0
);
return
gen_send_ex
((
PyGenObject
*
)
cw
->
cw_coroutine
,
NULL
,
0
,
0
);
}
static
PyObject
*
coro_wrapper_send
(
PyCoroWrapper
*
cw
,
PyObject
*
arg
)
{
return
gen_send_ex
((
PyGenObject
*
)
cw
->
cw_coroutine
,
arg
,
0
);
return
gen_send_ex
((
PyGenObject
*
)
cw
->
cw_coroutine
,
arg
,
0
,
0
);
}
static
PyObject
*
...
...
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