Change error type for bad objects in "with" and "async with"

This patch does not cover all cases of `test_contextlib.py`

`bytecode::Instruction::SetupWith` and `BeforeAsyncWith`
raise a TypeError instead of an AttributeError.

Co-authored-by: Jeong YunWon <69878+youknowone@users.noreply.github.com>
This commit is contained in:
LYKandJeong YunWon committed 2023-03-08 01:45:12 +09:00
1 parent f00e6b69f2
commit ef77e45427
3 files changed
+36 -19

No files matched your search

-4
View File
@@ -545,8 +545,6 @@ class TestContextDecorator(unittest.TestCase):
self.assertEqual(test.b, 2)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_typo_enter(self):
class mycontext(ContextDecorator):
def __unter__(self):
@@ -559,8 +557,6 @@ class TestContextDecorator(unittest.TestCase):
pass
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_typo_exit(self):
class mycontext(ContextDecorator):
def __enter__(self):
-6
View File
@@ -109,8 +109,6 @@ class FailureTestCase(unittest.TestCase):
with foo: pass
self.assertRaises(NameError, fooNotDeclared)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def testEnterAttributeError1(self):
class LacksEnter(object):
def __exit__(self, type, value, traceback):
@@ -121,8 +119,6 @@ class FailureTestCase(unittest.TestCase):
with foo: pass
self.assertRaisesRegex(TypeError, 'the context manager', fooLacksEnter)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def testEnterAttributeError2(self):
class LacksEnterAndExit(object):
pass
@@ -132,8 +128,6 @@ class FailureTestCase(unittest.TestCase):
with foo: pass
self.assertRaisesRegex(TypeError, 'the context manager', fooLacksEnterAndExit)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def testExitAttributeError(self):
class LacksExit(object):
def __enter__(self):
+36 -9
View File
@@ -840,12 +840,24 @@ impl ExecutingFrame<'_> {
}
bytecode::Instruction::SetupWith { end } => {
let context_manager = self.pop_value();
let enter_res = vm.call_special_method(
context_manager.clone(),
identifier!(vm, __enter__),
(),
)?;
let exit = context_manager.get_attr(identifier!(vm, __exit__), vm)?;
let error_string = || -> String {
format!(
"'{:.200}' object does not support the context manager protocol",
context_manager.class().name(),
)
};
let enter_res = vm
.get_special_method(context_manager.clone(), identifier!(vm, __enter__))?
.map_err(|_obj| vm.new_type_error(error_string()))?
.invoke((), vm)?;
let exit = context_manager
.get_attr(identifier!(vm, __exit__), vm)
.map_err(|_exc| {
vm.new_type_error({
format!("'{} (missed __exit__ method)", error_string())
})
})?;
self.push_value(exit);
self.push_block(BlockType::Finally {
handler: end.get(arg),
@@ -855,9 +867,24 @@ impl ExecutingFrame<'_> {
}
bytecode::Instruction::BeforeAsyncWith => {
let mgr = self.pop_value();
let aenter_res =
vm.call_special_method(mgr.clone(), identifier!(vm, __aenter__), ())?;
let aexit = mgr.get_attr(identifier!(vm, __aexit__), vm)?;
let error_string = || -> String {
format!(
"'{:.200}' object does not support the asynchronous context manager protocol",
mgr.class().name(),
)
};
let aenter_res = vm
.get_special_method(mgr.clone(), identifier!(vm, __aenter__))?
.map_err(|_obj| vm.new_type_error(error_string()))?
.invoke((), vm)?;
let aexit = mgr
.get_attr(identifier!(vm, __aexit__), vm)
.map_err(|_exc| {
vm.new_type_error({
format!("'{} (missed __aexit__ method)", error_string())
})
})?;
self.push_value(aexit);
self.push_value(aenter_res);