mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
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:
1 parent
efce325cbf
commit
5c7f6a2afa
6 files changed
+107
-74
No files matched your search
Vendored
-2
@@ -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
|
||||
|
||||
Vendored
-2
@@ -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)
|
||||
|
||||
Vendored
+66
-68
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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(),
|
||||
|
||||
Reference in new issue
Block a user