8000 Merge pull request #5254 from youknowone/exception-group · RustPython/RustPython@c7ca173 · GitHub
[go: up one dir, main page]

Skip to content

Commit c7ca173

Browse files
authored
Merge pull request #5254 from youknowone/exception-group
ExceptionGroup
2 parents c9161c0 + 27bcba3 commit c7ca173

File tree

11 files changed

+406
-70
lines changed

11 files changed

+406
-70
lines changed

Lib/test/test_baseexception.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ def verify_instance_interface(self, ins):
1818
"%s missing %s attribute" %
1919
(ins.__class__.__name__, attr))
2020

21-
# TODO: RUSTPYTHON
22-
@unittest.expectedFailure
2321
def test_inheritance(self):
2422
# Make sure the inheritance hierarchy matches the documentation
2523
exc_set = set()

Lib/test/test_contextlib.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,8 +1271,6 @@ def test_cm_is_reentrant(self):
12711271
1/0
12721272
self.assertTrue(outer_continued)
12731273

1274-
# TODO: RUSTPYTHON
1275-
@unittest.expectedFailure
12761274
def test_exception_groups(self):
12771275
eg_ve = lambda: ExceptionGroup(
12781276
"EG with ValueErrors only",

Lib/test/test_exception_group.py

Lines changed: 32 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
import collections.abc
2-
import traceback
32
import types
43
import unittest
5-
4+
from test.support import C_RECURSION_LIMIT
65

76
class Te 1E0A stExceptionGroupTypeHierarchy(unittest.TestCase):
8-
# TODO: RUSTPYTHON
9-
@unittest.expectedFailure
107
def test_exception_group_types(self):
118
self.assertTrue(issubclass(ExceptionGroup, Exception))
129
self.assertTrue(issubclass(ExceptionGroup, BaseExceptionGroup))
@@ -38,17 +35,13 @@ def test_bad_EG_construction__too_many_args(self):
3835
with self.assertRaisesRegex(TypeError, MSG):
3936
ExceptionGroup('eg', [ValueError('too')], [TypeError('many')])
4037

41-
# TODO: RUSTPYTHON
42-
@unittest.expectedFailure
4338
def test_bad_EG_construction__bad_message(self):
4439
MSG = 'argument 1 must be str, not '
4540
with self.assertRaisesRegex(TypeError, MSG):
4641
ExceptionGroup(ValueError(12), SyntaxError('bad syntax'))
4742
with self.assertRaisesRegex(TypeError, MSG):
4843
ExceptionGroup(None, [ValueError(12)])
4944

50-
# TODO: RUSTPYTHON
51-
@unittest.expectedFailure
5245
def test_bad_EG_construction__bad_excs_sequence(self):
5346
MSG = r'second argument \(exceptions\) must be a sequence'
5447
with self.assertRaisesRegex(TypeError, MSG):
@@ -60,8 +53,6 @@ def test_bad_EG_construction__bad_excs_sequence(self):
6053
with self.assertRaisesRegex(ValueError, MSG):
6154
ExceptionGroup("eg", [])
6255

63-
# TODO: RUSTPYTHON
64-
@unittest.expectedFailure
6556
def test_bad_EG_construction__nested_non_exceptions(self):
6657
MSG = (r'Item [0-9]+ of second argument \(exceptions\)'
6758
' is not an exception')
@@ -78,16 +69,12 @@ def test_EG_wraps_Exceptions__creates_EG(self):
7869
type(ExceptionGroup("eg", excs)),
7970
ExceptionGroup)
8071

81-
# TODO: RUSTPYTHON
82-
@unittest.expectedFailure
8372
def test_BEG_wraps_Exceptions__creates_EG(self):
8473
excs = [ValueError(1), TypeError(2)]
8574
self.assertIs(
8675
type(BaseExceptionGroup("beg", excs)),
8776
ExceptionGroup)
8877

89-
# TODO: RUSTPYTHON
90-
@unittest.expectedFailure
9178
def test_EG_wraps_BaseException__raises_TypeError(self):
9279
MSG= "Cannot nest BaseExceptions in an ExceptionGroup"
9380
with self.assertRaisesRegex(TypeError, MSG):
@@ -105,8 +92,6 @@ class MyEG(ExceptionGroup):
10592
type(MyEG("eg", [ValueError(12), TypeError(42)])),
10693
MyEG)
10794

108-
# TODO: RUSTPYTHON
109-
@unittest.expectedFailure
11095
def test_EG_subclass_does_not_wrap_base_exceptions(self):
11196
class MyEG(ExceptionGroup):
11297
pass
@@ -115,8 +100,6 @@ class MyEG(ExceptionGroup):
115100
with self.assertRaisesRegex(TypeError, msg):
116101
MyEG("eg", [ValueError(12), KeyboardInterrupt(42)])
117102

118-
# TODO: RUSTPYTHON
119-
@unittest.expectedFailure
120103
def test_BEG_and_E_subclass_does_not_wrap_base_exceptions(self):
121104
class MyEG(BaseExceptionGroup, ValueError):
122105
pass
@@ -125,6 +108,21 @@ class MyEG(BaseExceptionGroup, ValueError):
125108
with self.assertRaisesRegex(TypeError, msg):
126109
MyEG("eg", [ValueError(12), KeyboardInterrupt(42)])
127110

111+
def test_EG_and_specific_subclass_can_wrap_any_nonbase_exception(self):
112+
class MyEG(ExceptionGroup, ValueError):
113+
pass
114+
115+
# The restriction is specific to Exception, not "the other base class"
116+
MyEG("eg", [ValueError(12), Exception()])
117+
118+
def test_BEG_and_specific_subclass_can_wrap_any_nonbase_exception(self):
119+
class MyEG(BaseExceptionGroup, ValueError):
120+
pass
121+
122+
# The restriction is specific to Exception, not "the other base class"
123+
MyEG("eg", [ValueError(12), Exception()])
124+
125+
128126
def test_BEG_subclass_wraps_anything(self):
129127
class MyBEG(BaseExceptionGroup):
130128
pass
@@ -138,8 +136,6 @@ class MyBEG(BaseExceptionGroup):
138136

139137

140138
class StrAndReprTests(unittest.TestCase):
141-
# TODO: RUSTPYTHON
142-
@unittest.expectedFailure
143139
def test_ExceptionGroup(self):
144140
eg = BaseExceptionGroup(
145141
'flat', [ValueError(1), TypeError(2)])
@@ -160,8 +156,6 @@ def test_ExceptionGroup(self):
160156
"ExceptionGroup('flat', "
161157
"[ValueError(1), TypeError(2)]), TypeError(2)])")
162158

163-
# TODO: RUSTPYTHON
164-
@unittest.expectedFailure
165159
def test_BaseExceptionGroup(self):
166160
eg = BaseExceptionGroup(
167161
'flat', [ValueError(1), KeyboardInterrupt(2)])
@@ -184,8 +178,6 @@ def test_BaseExceptionGroup(self):
184178
"BaseExceptionGroup('flat', "
185179
"[ValueError(1), KeyboardInterrupt(2)])])")
186180

187-
# TODO: RUSTPYTHON
188-
@unittest.expectedFailure
189181
def test_custom_exception(self):
190182
class MyEG(ExceptionGroup):
191183
pass
@@ -270,8 +262,6 @@ def test_basics_ExceptionGroup_fields(self):
270262
self.assertIsNone(tb.tb_next)
271263
self.assertEqual(tb.tb_lineno, tb_linenos[1][i])
272264

273-
# TODO: RUSTPYTHON
274-
@unittest.expectedFailure
275265
def test_fields_are_readonly(self):
276266
eg = ExceptionGroup('eg', [TypeError(1), OSError(2)])
277267

@@ -287,8 +277,6 @@ def test_fields_are_readonly(self):
287277

288278

289279
class ExceptionGroupTestBase(unittest.TestCase):
290-
# TODO: RUSTPYTHON
291-
@unittest.expectedFailure
292280
def assertMatchesTemplate(self, exc, exc_type, template):
293281
""" Assert that the exception matches the template
294282
@@ -318,7 +306,6 @@ def setUp(self):
318306
self.eg = create_simple_eg()
319307
self.eg_template = [ValueError(1), TypeError(int), ValueError(2)]
320308

321-
@unittest.skip("TODO: RUSTPYTHON")
322309
def test_basics_subgroup_split__bad_arg_type(self):
323310
bad_args = ["bad arg",
324311
OSError('instance not type'),
@@ -330,20 +317,16 @@ def test_basics_subgroup_split__bad_arg_type(self):
330317
with self.assertRaises(TypeError):
331318
self.eg.split(arg)
332319

333-
334-
@unittest.skip("TODO: RUSTPYTHON")
335320
def test_basics_subgroup_by_type__passthrough(self):
336321
eg = self.eg
337322
self.assertIs(eg, eg.subgroup(BaseException))
338323
self.assertIs(eg, eg.subgroup(Exception))
339324
self.assertIs(eg, eg.subgroup(BaseExceptionGroup))
340325
self.assertIs(eg, eg.subgroup(ExceptionGroup))
341326

342-
@unittest.skip("TODO: RUSTPYTHON")
343327
def test_basics_subgroup_by_type__no_match(self):
344328
self.assertIsNone(self.eg.subgroup(OSError))
345329

346-
@unittest.skip("TODO: RUSTPYTHON")
347330
def test_basics_subgroup_by_type__match(self):
348331
eg = self.eg
349332
testcases = [
@@ -358,15 +341,12 @@ def test_basics_subgroup_by_type__match(self):
358341
self.assertEqual(subeg.message, eg.message)
359342
self.assertMatchesTemplate(subeg, ExceptionGroup, template)
360343

361-
@unittest.skip("TODO: RUSTPYTHON")
362344
def test_basics_subgroup_by_predicate__passthrough(self):
363345
self.assertIs(self.eg, self.eg.subgroup(lambda e: True))
364346

365-
@unittest.skip("TODO: RUSTPYTHON")
366347
def test_basics_subgroup_by_predicate__no_match(self):
367348
self.assertIsNone(self.eg.subgroup(lambda e: False))
368349

369-
@unittest.skip("TODO: RUSTPYTHON")
370350
def test_basics_subgroup_by_predicate__match(self):
371351
eg = self.eg
372352
testcases = [
@@ -386,7 +366,6 @@ def setUp(self):
386366
self.eg = create_simple_eg()
387367
self.eg_template = [ValueError(1), TypeError(int), ValueError(2)]
388368

389-
@unittest.skip("TODO: RUSTPYTHON")
390369
def test_basics_split_by_type__passthrough(self):
391370
for E in [BaseException, Exception,
392371
BaseExceptionGroup, ExceptionGroup]:
@@ -395,14 +374,12 @@ def test_basics_split_by_type__passthrough(self):
395374
match, ExceptionGroup, self.eg_template)
396375
self.assertIsNone(rest)
397376

398-
@unittest.skip("TODO: RUSTPYTHON")
399377
def test_basics_split_by_type__no_match(self):
400378
match, rest = self.eg.split(OSError)
401379
self.assertIsNone(match)
402380
self.assertMatchesTemplate(
403381
rest, ExceptionGroup, self.eg_template)
404382

405-
@unittest.skip("TODO: RUSTPYTHON")
406383
def test_basics_split_by_type__match(self):
407384
eg = self.eg
408385
VE = ValueError
@@ -427,19 +404,16 @@ def test_basics_split_by_type__match(self):
427404
else:
428405
self.assertIsNone(rest)
429406

430-
@unittest.skip("TODO: RUSTPYTHON")
431407
def test_basics_split_by_predicate__passthrough(self):
432408
match, rest = self.eg.split(lambda e: True)
433409
self.assertMatchesTemplate(match, ExceptionGroup, self.eg_template)
434410
self.assertIsNone(rest)
435411

436-
@unittest.skip("TODO: RUSTPYTHON")
437412
def test_basics_split_by_predicate__no_match(self):
438413
match, rest = self.eg.split(lambda e: False)
439414
self.assertIsNone(match)
440415
self.assertMatchesTemplate(rest, ExceptionGroup, self.eg_template)
441416

442-
@unittest.skip("TODO: RUSTPYTHON")
443417
def test_basics_split_by_predicate__match(self):
444418
eg = self.eg
445419
VE = ValueError
@@ -465,19 +439,15 @@ def test_basics_split_by_predicate__match(self):
465439
class DeepRecursionInSplitAndSubgroup(unittest.TestCase):
466440
def make_deep_eg(self):
467441
e = TypeError(1)
468-
for i in range(2000):
442+
for i in range(C_RECURSION_LIMIT + 1):
469443
e = ExceptionGroup('eg', [e])
470444
return e
471445

472-
# TODO: RUSTPYTHON
473-
@unittest.expectedFailure
474446
def test_deep_split(self):
475447
e = self.make_deep_eg()
476448
with self.assertRaises(RecursionError):
477449
e.split(TypeError)
478450

479-
# TODO: RUSTPYTHON
480-
@unittest.expectedFailure
481451
def test_deep_subgroup(self):
482452
e = self.make_deep_eg()
483453
with self.assertRaises(RecursionError):
@@ -501,7 +471,7 @@ def leaf_generator(exc, tbs=None):
501471

502472
class LeafGeneratorTest(unittest.TestCase):
503473
# The leaf_generator is mentioned in PEP 654 as a suggestion
504-
# on how to iterate over leaf nodes of an EG. It is also
474+
# on how to iterate over leaf nodes of an EG. Is is also
505475
# used below as a test utility. So we test it here.
506476

507477
def test_leaf_generator(self):
@@ -654,8 +624,6 @@ def tb_linenos(tbs):
654624

655625
class NestedExceptionGroupSplitTest(ExceptionGroupSplitTestBase):
656626

657-
# TODO: RUSTPYTHON
658-
@unittest.expectedFailure
659627
def test_split_by_type(self):
660628
class MyExceptionGroup(ExceptionGroup):
661629
pass
@@ -755,8 +723,6 @@ def level3(i):
755723
self.assertMatchesTemplate(match, ExceptionGroup, [eg_template[0]])
756724
self.assertMatchesTemplate(rest, ExceptionGroup, [eg_template[1]])
757725

758-
# TODO: RUSTPYTHON
759-
@unittest.expectedFailure
760726
def test_split_BaseExceptionGroup(self):
761727
def exc(ex):
762728
try:
@@ -797,8 +763,6 @@ def exc(ex):
797763
self.assertMatchesTemplate(
798764
rest, ExceptionGroup, [ValueError(1)])
799765

800-
# TODO: RUSTPYTHON
801-
@unittest.expectedFailure
802766
def test_split_copies_notes(self):
803767
# make sure each exception group after a split has its own __notes__ list
804768
eg = ExceptionGroup("eg", [ValueError(1), TypeError(2)])
@@ -830,11 +794,23 @@ def test_split_does_not_copy_non_sequence_notes(self):
830794
self.assertFalse(hasattr(match, '__notes__'))
831795
self.assertFalse(hasattr(rest, '__notes__'))
832796

797+
# TODO: RUSTPYTHON
798+
@unittest.expectedFailure
799+
def test_drive_invalid_return_value(self):
800+
class MyEg(ExceptionGroup):
801+
def derive(self, excs):
802+
return 42
803+
804+
eg = MyEg('eg', [TypeError(1), ValueError(2)])
805+
msg = "derive must return an instance of BaseExceptionGroup"
806+
with self.assertRaisesRegex(TypeError, msg):
807+
eg.split(TypeError)
808+
with self.assertRaisesRegex(TypeError, msg):
809+
eg.subgroup(TypeError)
810+
833811

834812
class NestedExceptionGroupSubclassSplitTest(ExceptionGroupSplitTestBase):
835813

836-
# TODO: RUSTPYTHON
837-
@unittest.expectedFailure
838814
def test_split_ExceptionGroup_subclass_no_derive_no_new_override(self):
839815
class EG(ExceptionGroup):
840816
pass
@@ -877,8 +853,6 @@ class EG(ExceptionGroup):
877853
self.assertMatchesTemplate(match, ExceptionGroup, [[TypeError(2)]])
878854
self.assertMatchesTemplate(rest, ExceptionGroup, [ValueError(1)])
879855

880-
# TODO: RUSTPYTHON
881-
@unittest.expectedFailure
882856
def test_split_BaseExceptionGroup_subclass_no_derive_new_override(self):
883857
class EG(BaseExceptionGroup):
884858
def __new__(cls, message, excs, unused):
@@ -921,8 +895,6 @@ def __new__(cls, message, excs, unused):
921895
match, BaseExceptionGroup, [KeyboardInterrupt(2)])
922896
self.assertMatchesTemplate(rest, ExceptionGroup, [ValueError(1)])
923897

924-
# TODO: RUSTPYTHON
925-
@unittest.expectedFailure
926898
def test_split_ExceptionGroup_subclass_derive_and_new_overrides(self):
927899
class EG(ExceptionGroup):
928900
def __new__(cls, message, excs, code):

Lib/typing.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
from abc import abstractmethod, ABCMeta
2323
import collections
2424
import collections.abc
25-
import contextlib
2625
import functools
2726
import operator
2827
import re as stdlib_re # Avoid confusion with the re we export.
@@ -2138,8 +2137,13 @@ class Other(Leaf): # Error reported by type checker
21382137
KeysView = _alias(collections.abc.KeysView, 1)
21392138
ItemsView = _alias(collections.abc.ItemsView, 2)
21402139
ValuesView = _alias(collections.abc.ValuesView, 1)
2141-
ContextManager = _alias(contextlib.AbstractContextManager, 1, name='ContextManager')
2142-
AsyncContextManager = _alias(contextlib.AbstractAsyncContextManager, 1, name='AsyncContextManager')
2140+
try:
2141+
# XXX: RUSTPYTHON; contextlib support for wasm
2142+
import contextlib
2143+
ContextManager = _alias(contextlib.AbstractContextManager, 1, name='ContextManager')
2144+
AsyncContextManager = _alias(contextlib.AbstractAsyncContextManager, 1, name='AsyncContextManager')
2145+
except ImportError:
2146+
pass
21432147
Dict = _alias(dict, 2, inst=False, name='Dict')
21442148
DefaultDict = _alias(collections.defaultdict, 2, name='DefaultDict')
21452149
OrderedDict = _alias(collections.OrderedDict, 2)

src/interpreter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub type InitHook = Box<dyn FnOnce(&mut VirtualMachine)>;
1818
/// let mut settings = Settings::default();
1919
/// settings.debug = 1;
2020
/// // You may want to add paths to `rustpython_vm::Settings::path_list` to allow import python libraries.
21+
/// settings.path_list.push("Lib".to_owned()); // add standard library directory
2122
/// settings.path_list.push("".to_owned()); // add current working directory
2223
/// let interpreter = rustpython::InterpreterConfig::new()
2324
/// .settings(settings)

0 commit comments

Comments
 (0)
0