Skip to content

Commit bdce56d

Browse files
authored
Merge pull request #4656 from dalinaum/with-type-error
Change error type for bad objects in "with" and "async with"
2 parents f4a7b65 + ef77e45 commit bdce56d

File tree

3 files changed

+36
-19
lines changed

3 files changed

+36
-19
lines changed

Lib/test/test_contextlib.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -545,8 +545,6 @@ def method(self, a, b, c=None):
545545
self.assertEqual(test.b, 2)
546546

547547

548-
# TODO: RUSTPYTHON
549-
@unittest.expectedFailure
550548
def test_typo_enter(self):
551549
class mycontext(ContextDecorator):
552550
def __unter__(self):
@@ -559,8 +557,6 @@ def __exit__(self, *exc):
559557
pass
560558

561559

562-
# TODO: RUSTPYTHON
563-
@unittest.expectedFailure
564560
def test_typo_exit(self):
565561
class mycontext(ContextDecorator):
566562
def __enter__(self):

Lib/test/test_with.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,6 @@ def fooNotDeclared():
109109
with foo: pass
110110
self.assertRaises(NameError, fooNotDeclared)
111111

112-
# TODO: RUSTPYTHON
113-
@unittest.expectedFailure
114112
def testEnterAttributeError1(self):
115113
class LacksEnter(object):
116114
def __exit__(self, type, value, traceback):
@@ -121,8 +119,6 @@ def fooLacksEnter():
121119
with foo: pass
122120
self.assertRaisesRegex(TypeError, 'the context manager', fooLacksEnter)
123121

124-
# TODO: RUSTPYTHON
125-
@unittest.expectedFailure
126122
def testEnterAttributeError2(self):
127123
class LacksEnterAndExit(object):
128124
pass
@@ -132,8 +128,6 @@ def fooLacksEnterAndExit():
132128
with foo: pass
133129
self.assertRaisesRegex(TypeError, 'the context manager', fooLacksEnterAndExit)
134130

135-
# TODO: RUSTPYTHON
136-
@unittest.expectedFailure
137131
def testExitAttributeError(self):
138132
class LacksExit(object):
139133
def __enter__(self):

vm/src/frame.rs

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -840,12 +840,24 @@ impl ExecutingFrame<'_> {
840840
}
841841
bytecode::Instruction::SetupWith { end } => {
842842
let context_manager = self.pop_value();
843-
let enter_res = vm.call_special_method(
844-
context_manager.clone(),
845-
identifier!(vm, __enter__),
846-
(),
847-
)?;
848-
let exit = context_manager.get_attr(identifier!(vm, __exit__), vm)?;
843+
let error_string = || -> String {
844+
format!(
845+
"'{:.200}' object does not support the context manager protocol",
846+
context_manager.class().name(),
847+
)
848+
};
849+
let enter_res = vm
850+
.get_special_method(context_manager.clone(), identifier!(vm, __enter__))?
851+
.map_err(|_obj| vm.new_type_error(error_string()))?
852+
.invoke((), vm)?;
853+
854+
let exit = context_manager
855+
.get_attr(identifier!(vm, __exit__), vm)
856+
.map_err(|_exc| {
857+
vm.new_type_error({
858+
format!("'{} (missed __exit__ method)", error_string())
859+
})
860+
})?;
849861
self.push_value(exit);
850862
self.push_block(BlockType::Finally {
851863
handler: end.get(arg),
@@ -855,9 +867,24 @@ impl ExecutingFrame<'_> {
855867
}
856868
bytecode::Instruction::BeforeAsyncWith => {
857869
let mgr = self.pop_value();
858-
let aenter_res =
859-
vm.call_special_method(mgr.clone(), identifier!(vm, __aenter__), ())?;
860-
let aexit = mgr.get_attr(identifier!(vm, __aexit__), vm)?;
870+
let error_string = || -> String {
871+
format!(
872+
"'{:.200}' object does not support the asynchronous context manager protocol",
873+
mgr.class().name(),
874+
)
875+
};
876+
877+
let aenter_res = vm
878+
.get_special_method(mgr.clone(), identifier!(vm, __aenter__))?
879+
.map_err(|_obj| vm.new_type_error(error_string()))?
880+
.invoke((), vm)?;
881+
let aexit = mgr
882+
.get_attr(identifier!(vm, __aexit__), vm)
883+
.map_err(|_exc| {
884+
vm.new_type_error({
885+
format!("'{} (missed __aexit__ method)", error_string())
886+
})
887+
})?;
861888
self.push_value(aexit);
862889
self.push_value(aenter_res);
863890

0 commit comments

Comments
 (0)