Update types from v3.14.2 (#6833)

This pull request updates `types` module to v3.14.2. While doing it, it
fixes also async-related feature. This pull request's base is generated
by #6827.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Generators that act as iterable coroutines are now recognized as
awaitable, improving async behavior.
* Yield-from and await interactions now handle coroutine-iterable
sources more consistently.

* **Bug Fixes**
* Reduces spurious TypeError cases when awaiting or yielding from
wrapped coroutine-like generators.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Lee Dogeon authored and GitHub committed 2026-01-23 23:23:02 +09:00
1 parent efce325cbf
commit 5c7f6a2afa
6 files changed
+107 -74

No files matched your search

-2
View File
@@ -787,7 +787,6 @@ def _test_gen():
class TestOneTrickPonyABCs(ABCTestCase):
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_Awaitable(self):
def gen():
yield
@@ -840,7 +839,6 @@ class TestOneTrickPonyABCs(ABCTestCase):
CoroLike = None
support.gc_collect() # Kill CoroLike to clean-up ABCMeta cache
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_Coroutine(self):
def gen():
yield
-2
View File
@@ -2174,7 +2174,6 @@ class CoroutineTests(unittest.TestCase):
foo = types.coroutine(foo)
self.assertIs(aw, foo())
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_async_def(self):
# Test that types.coroutine passes 'async def' coroutines
# without modification
@@ -2431,7 +2430,6 @@ class CoroutineTests(unittest.TestCase):
foo = types.coroutine(foo)
self.assertIs(foo(), gencoro)
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_genfunc(self):
def gen(): yield
self.assertIs(types.coroutine(gen), gen)
+66 -68
View File
@@ -2,65 +2,78 @@
Define names for built-in types that aren't directly accessible as a builtin.
"""
import sys
# Iterators in Python aren't a matter of type but of protocol. A large
# and changing number of builtin types implement *some* flavor of
# iterator. Don't check the type! Use hasattr to check for both
# "__iter__" and "__next__" attributes instead.
def _f(): pass
FunctionType = type(_f)
LambdaType = type(lambda: None) # Same as FunctionType
CodeType = type(_f.__code__)
MappingProxyType = type(type.__dict__)
SimpleNamespace = type(sys.implementation)
def _cell_factory():
a = 1
def f():
nonlocal a
return f.__closure__[0]
CellType = type(_cell_factory())
def _g():
yield 1
GeneratorType = type(_g())
async def _c(): pass
_c = _c()
CoroutineType = type(_c)
_c.close() # Prevent ResourceWarning
async def _ag():
yield
_ag = _ag()
AsyncGeneratorType = type(_ag)
class _C:
def _m(self): pass
MethodType = type(_C()._m)
BuiltinFunctionType = type(len)
BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
WrapperDescriptorType = type(object.__init__)
MethodWrapperType = type(object().__str__)
MethodDescriptorType = type(str.join)
ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
ModuleType = type(sys)
try:
raise TypeError
except TypeError as exc:
TracebackType = type(exc.__traceback__)
FrameType = type(exc.__traceback__.tb_frame)
from _types import *
except ImportError:
import sys
GetSetDescriptorType = type(FunctionType.__code__)
MemberDescriptorType = type(FunctionType.__globals__)
def _f(): pass
FunctionType = type(_f)
LambdaType = type(lambda: None) # Same as FunctionType
CodeType = type(_f.__code__)
MappingProxyType = type(type.__dict__)
SimpleNamespace = type(sys.implementation)
del sys, _f, _g, _C, _c, _ag, _cell_factory # Not for export
def _cell_factory():
a = 1
def f():
nonlocal a
return f.__closure__[0]
CellType = type(_cell_factory())
def _g():
yield 1
GeneratorType = type(_g())
async def _c(): pass
_c = _c()
CoroutineType = type(_c)
_c.close() # Prevent ResourceWarning
async def _ag():
yield
_ag = _ag()
AsyncGeneratorType = type(_ag)
class _C:
def _m(self): pass
MethodType = type(_C()._m)
BuiltinFunctionType = type(len)
BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
WrapperDescriptorType = type(object.__init__)
MethodWrapperType = type(object().__str__)
MethodDescriptorType = type(str.join)
ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
ModuleType = type(sys)
try:
raise TypeError
except TypeError as exc:
TracebackType = type(exc.__traceback__)
FrameType = type(exc.__traceback__.tb_frame)
GetSetDescriptorType = type(FunctionType.__code__)
MemberDescriptorType = type(FunctionType.__globals__)
GenericAlias = type(list[int])
UnionType = type(int | str)
EllipsisType = type(Ellipsis)
NoneType = type(None)
NotImplementedType = type(NotImplemented)
# CapsuleType cannot be accessed from pure Python,
# so there is no fallback definition.
del sys, _f, _g, _C, _c, _ag, _cell_factory # Not for export
# Provide a PEP 3115 compliant mechanism for class creation
@@ -279,8 +292,7 @@ def coroutine(func):
if not callable(func):
raise TypeError('types.coroutine() expects a callable')
# XXX RUSTPYTHON TODO: iterable coroutine
if (False and func.__class__ is FunctionType and
if (func.__class__ is FunctionType and
getattr(func, '__code__', None).__class__ is CodeType):
co_flags = func.__code__.co_flags
@@ -325,18 +337,4 @@ def coroutine(func):
return wrapped
GenericAlias = type(list[int])
UnionType = type(int | str)
EllipsisType = type(Ellipsis)
NoneType = type(None)
NotImplementedType = type(NotImplemented)
def __getattr__(name):
if name == 'CapsuleType':
import _socket
return type(_socket.CAPI)
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
__all__ = [n for n in globals() if n[:1] != '_']
__all__ += ['CapsuleType']
__all__ = [n for n in globals() if not n.startswith('_')] # for pydoc
+1
View File
@@ -297,6 +297,7 @@ bitflags! {
const VARKEYWORDS = 0x0008;
const GENERATOR = 0x0020;
const COROUTINE = 0x0080;
const ITERABLE_COROUTINE = 0x0100;
/// If a code object represents a function and has a docstring,
/// this bit is set and the first item in co_consts is the docstring.
const HAS_DOCSTRING = 0x4000000;
+23 -1
View File
@@ -1,4 +1,4 @@
use super::{PyCode, PyGenericAlias, PyStrRef, PyType, PyTypeRef};
use super::{PyCode, PyGenerator, PyGenericAlias, PyStrRef, PyType, PyTypeRef};
use crate::{
AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
builtins::PyBaseExceptionRef,
@@ -596,6 +596,28 @@ impl PyAnextAwaitable {
let awaitable = if wrapped.class().is(vm.ctx.types.coroutine_type) {
// Coroutine - get __await__ later
wrapped.clone()
} else if let Some(generator) = wrapped.downcast_ref::<PyGenerator>() {
// Generator with CO_ITERABLE_COROUTINE flag can be awaited
// (e.g., generators decorated with @types.coroutine)
if generator
.as_coro()
.frame()
.code
.flags
.contains(crate::bytecode::CodeFlags::ITERABLE_COROUTINE)
{
// Return the generator itself as the iterator
return Ok(wrapped.clone());
}
// Fall through: try to get __await__ method for generator subclasses
if let Some(await_method) = vm.get_method(wrapped.clone(), identifier!(vm, __await__)) {
await_method?.call((), vm)?
} else {
return Err(vm.new_type_error(format!(
"object {} can't be used in 'await' expression",
wrapped.class().name()
)));
}
} else {
// Try to get __await__ method
if let Some(await_method) = vm.get_method(wrapped.clone(), identifier!(vm, __await__)) {
+17 -1
View File
@@ -1013,6 +1013,20 @@ impl ExecutingFrame<'_> {
);
}
awaited_obj
} else if awaited_obj
.downcast_ref::<PyGenerator>()
.is_some_and(|generator| {
generator
.as_coro()
.frame()
.code
.flags
.contains(bytecode::CodeFlags::ITERABLE_COROUTINE)
})
{
// Generator with CO_ITERABLE_COROUTINE flag can be awaited
// (e.g., generators decorated with @types.coroutine)
awaited_obj
} else {
let await_method = vm.get_method_or_type_error(
awaited_obj.clone(),
@@ -1051,7 +1065,9 @@ impl ExecutingFrame<'_> {
let iterable = self.pop_value();
let iter = if iterable.class().is(vm.ctx.types.coroutine_type) {
// Coroutine requires CO_COROUTINE or CO_ITERABLE_COROUTINE flag
if !self.code.flags.intersects(bytecode::CodeFlags::COROUTINE) {
if !self.code.flags.intersects(
bytecode::CodeFlags::COROUTINE | bytecode::CodeFlags::ITERABLE_COROUTINE,
) {
return Err(vm.new_type_error(
"cannot 'yield from' a coroutine object in a non-coroutine generator"
.to_owned(),