Skip to content

Commit 5c7f6a2

Browse files
authored
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 -->
1 parent efce325 commit 5c7f6a2

File tree

6 files changed

+104
-71
lines changed

6 files changed

+104
-71
lines changed

Lib/test/test_collections.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,6 @@ def _test_gen():
787787

788788
class TestOneTrickPonyABCs(ABCTestCase):
789789

790-
@unittest.expectedFailure # TODO: RUSTPYTHON
791790
def test_Awaitable(self):
792791
def gen():
793792
yield
@@ -840,7 +839,6 @@ class CoroLike: pass
840839
CoroLike = None
841840
support.gc_collect() # Kill CoroLike to clean-up ABCMeta cache
842841

843-
@unittest.expectedFailure # TODO: RUSTPYTHON
844842
def test_Coroutine(self):
845843
def gen():
846844
yield

Lib/test/test_types.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,7 +2174,6 @@ def foo():
21742174
foo = types.coroutine(foo)
21752175
self.assertIs(aw, foo())
21762176

2177-
@unittest.expectedFailure # TODO: RUSTPYTHON
21782177
def test_async_def(self):
21792178
# Test that types.coroutine passes 'async def' coroutines
21802179
# without modification
@@ -2431,7 +2430,6 @@ def foo():
24312430
foo = types.coroutine(foo)
24322431
self.assertIs(foo(), gencoro)
24332432

2434-
@unittest.expectedFailure # TODO: RUSTPYTHON
24352433
def test_genfunc(self):
24362434
def gen(): yield
24372435
self.assertIs(types.coroutine(gen), gen)

Lib/types.py

Lines changed: 63 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,65 +2,78 @@
22
Define names for built-in types that aren't directly accessible as a builtin.
33
"""
44

5-
import sys
6-
75
# Iterators in Python aren't a matter of type but of protocol. A large
86
# and changing number of builtin types implement *some* flavor of
97
# iterator. Don't check the type! Use hasattr to check for both
108
# "__iter__" and "__next__" attributes instead.
119

12-
def _f(): pass
13-
FunctionType = type(_f)
14-
LambdaType = type(lambda: None) # Same as FunctionType
15-
CodeType = type(_f.__code__)
16-
MappingProxyType = type(type.__dict__)
17-
SimpleNamespace = type(sys.implementation)
18-
19-
def _cell_factory():
20-
a = 1
21-
def f():
22-
nonlocal a
23-
return f.__closure__[0]
24-
CellType = type(_cell_factory())
25-
26-
def _g():
27-
yield 1
28-
GeneratorType = type(_g())
29-
30-
async def _c(): pass
31-
_c = _c()
32-
CoroutineType = type(_c)
33-
_c.close() # Prevent ResourceWarning
34-
35-
async def _ag():
36-
yield
37-
_ag = _ag()
38-
AsyncGeneratorType = type(_ag)
39-
40-
class _C:
41-
def _m(self): pass
42-
MethodType = type(_C()._m)
10+
try:
11+
from _types import *
12+
except ImportError:
13+
import sys
14+
15+
def _f(): pass
16+
FunctionType = type(_f)
17+
LambdaType = type(lambda: None) # Same as FunctionType
18+
CodeType = type(_f.__code__)
19+
MappingProxyType = type(type.__dict__)
20+
SimpleNamespace = type(sys.implementation)
21+
22+
def _cell_factory():
23+
a = 1
24+
def f():
25+
nonlocal a
26+
return f.__closure__[0]
27+
CellType = type(_cell_factory())
28+
29+
def _g():
30+
yield 1
31+
GeneratorType = type(_g())
32+
33+
async def _c(): pass
34+
_c = _c()
35+
CoroutineType = type(_c)
36+
_c.close() # Prevent ResourceWarning
37+
38+
async def _ag():
39+
yield
40+
_ag = _ag()
41+
AsyncGeneratorType = type(_ag)
42+
43+
class _C:
44+
def _m(self): pass
45+
MethodType = type(_C()._m)
46+
47+
BuiltinFunctionType = type(len)
48+
BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
49+
50+
WrapperDescriptorType = type(object.__init__)
51+
MethodWrapperType = type(object().__str__)
52+
MethodDescriptorType = type(str.join)
53+
ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
54+
55+
ModuleType = type(sys)
4356

44-
BuiltinFunctionType = type(len)
45-
BuiltinMethodType = type([].append) # Same as BuiltinFunctionType
57+
try:
58+
raise TypeError
59+
except TypeError as exc:
60+
TracebackType = type(exc.__traceback__)
61+
FrameType = type(exc.__traceback__.tb_frame)
4662

47-
WrapperDescriptorType = type(object.__init__)
48-
MethodWrapperType = type(object().__str__)
49-
MethodDescriptorType = type(str.join)
50-
ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
63+
GetSetDescriptorType = type(FunctionType.__code__)
64+
MemberDescriptorType = type(FunctionType.__globals__)
5165

52-
ModuleType = type(sys)
66+
GenericAlias = type(list[int])
67+
UnionType = type(int | str)
5368

54-
try:
55-
raise TypeError
56-
except TypeError as exc:
57-
TracebackType = type(exc.__traceback__)
58-
FrameType = type(exc.__traceback__.tb_frame)
69+
EllipsisType = type(Ellipsis)
70+
NoneType = type(None)
71+
NotImplementedType = type(NotImplemented)
5972

60-
GetSetDescriptorType = type(FunctionType.__code__)
61-
MemberDescriptorType = type(FunctionType.__globals__)
73+
# CapsuleType cannot be accessed from pure Python,
74+
# so there is no fallback definition.
6275

63-
del sys, _f, _g, _C, _c, _ag, _cell_factory # Not for export
76+
del sys, _f, _g, _C, _c, _ag, _cell_factory # Not for export
6477

6578

6679
# Provide a PEP 3115 compliant mechanism for class creation
@@ -279,8 +292,7 @@ def coroutine(func):
279292
if not callable(func):
280293
raise TypeError('types.coroutine() expects a callable')
281294

282-
# XXX RUSTPYTHON TODO: iterable coroutine
283-
if (False and func.__class__ is FunctionType and
295+
if (func.__class__ is FunctionType and
284296
getattr(func, '__code__', None).__class__ is CodeType):
285297

286298
co_flags = func.__code__.co_flags
@@ -325,18 +337,4 @@ def wrapped(*args, **kwargs):
325337

326338
return wrapped
327339

328-
GenericAlias = type(list[int])
329-
UnionType = type(int | str)
330-
331-
EllipsisType = type(Ellipsis)
332-
NoneType = type(None)
333-
NotImplementedType = type(NotImplemented)
334-
335-
def __getattr__(name):
336-
if name == 'CapsuleType':
337-
import _socket
338-
return type(_socket.CAPI)
339-
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
340-
341-
__all__ = [n for n in globals() if n[:1] != '_']
342-
__all__ += ['CapsuleType']
340+
__all__ = [n for n in globals() if not n.startswith('_')] # for pydoc

crates/compiler-core/src/bytecode.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ bitflags! {
297297
const VARKEYWORDS = 0x0008;
298298
const GENERATOR = 0x0020;
299299
const COROUTINE = 0x0080;
300+
const ITERABLE_COROUTINE = 0x0100;
300301
/// If a code object represents a function and has a docstring,
301302
/// this bit is set and the first item in co_consts is the docstring.
302303
const HAS_DOCSTRING = 0x4000000;

crates/vm/src/builtins/asyncgenerator.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{PyCode, PyGenericAlias, PyStrRef, PyType, PyTypeRef};
1+
use super::{PyCode, PyGenerator, PyGenericAlias, PyStrRef, PyType, PyTypeRef};
22
use crate::{
33
AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
44
builtins::PyBaseExceptionRef,
@@ -596,6 +596,28 @@ impl PyAnextAwaitable {
596596
let awaitable = if wrapped.class().is(vm.ctx.types.coroutine_type) {
597597
// Coroutine - get __await__ later
598598
wrapped.clone()
599+
} else if let Some(generator) = wrapped.downcast_ref::<PyGenerator>() {
600+
// Generator with CO_ITERABLE_COROUTINE flag can be awaited
601+
// (e.g., generators decorated with @types.coroutine)
602+
if generator
603+
.as_coro()
604+
.frame()
605+
.code
606+
.flags
607+
.contains(crate::bytecode::CodeFlags::ITERABLE_COROUTINE)
608+
{
609+
// Return the generator itself as the iterator
610+
return Ok(wrapped.clone());
611+
}
612+
// Fall through: try to get __await__ method for generator subclasses
613+
if let Some(await_method) = vm.get_method(wrapped.clone(), identifier!(vm, __await__)) {
614+
await_method?.call((), vm)?
615+
} else {
616+
return Err(vm.new_type_error(format!(
617+
"object {} can't be used in 'await' expression",
618+
wrapped.class().name()
619+
)));
620+
}
599621
} else {
600622
// Try to get __await__ method
601623
if let Some(await_method) = vm.get_method(wrapped.clone(), identifier!(vm, __await__)) {

crates/vm/src/frame.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,20 @@ impl ExecutingFrame<'_> {
10131013
);
10141014
}
10151015
awaited_obj
1016+
} else if awaited_obj
1017+
.downcast_ref::<PyGenerator>()
1018+
.is_some_and(|generator| {
1019+
generator
1020+
.as_coro()
1021+
.frame()
1022+
.code
1023+
.flags
1024+
.contains(bytecode::CodeFlags::ITERABLE_COROUTINE)
1025+
})
1026+
{
1027+
// Generator with CO_ITERABLE_COROUTINE flag can be awaited
1028+
// (e.g., generators decorated with @types.coroutine)
1029+
awaited_obj
10161030
} else {
10171031
let await_method = vm.get_method_or_type_error(
10181032
awaited_obj.clone(),
@@ -1051,7 +1065,9 @@ impl ExecutingFrame<'_> {
10511065
let iterable = self.pop_value();
10521066
let iter = if iterable.class().is(vm.ctx.types.coroutine_type) {
10531067
// Coroutine requires CO_COROUTINE or CO_ITERABLE_COROUTINE flag
1054-
if !self.code.flags.intersects(bytecode::CodeFlags::COROUTINE) {
1068+
if !self.code.flags.intersects(
1069+
bytecode::CodeFlags::COROUTINE | bytecode::CodeFlags::ITERABLE_COROUTINE,
1070+
) {
10551071
return Err(vm.new_type_error(
10561072
"cannot 'yield from' a coroutine object in a non-coroutine generator"
10571073
.to_owned(),

0 commit comments

Comments
 (0)