diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 027d209f38..2c26da7113 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -24,7 +24,7 @@ from inspect import CO_COROUTINE from itertools import product from textwrap import dedent -from types import AsyncGeneratorType, FunctionType +from types import AsyncGeneratorType, FunctionType, CellType from operator import neg from test import support from test.support import (swap_attr, maybe_get_event_loop_policy) @@ -94,7 +94,7 @@ def write(self, line): ('', ValueError), (' ', ValueError), (' \t\t ', ValueError), - # (str(br'\u0663\u0661\u0664 ','raw-unicode-escape'), 314), XXX RustPython + (str(br'\u0663\u0661\u0664 ','raw-unicode-escape'), 314), (chr(0x200), ValueError), ] @@ -116,7 +116,7 @@ def write(self, line): ('', ValueError), (' ', ValueError), (' \t\t ', ValueError), - # (str(br'\u0663\u0661\u0664 ','raw-unicode-escape'), 314), XXX RustPython + (str(br'\u0663\u0661\u0664 ','raw-unicode-escape'), 314), (chr(0x200), ValueError), ] @@ -161,7 +161,7 @@ def test_import(self): __import__('string') __import__(name='sys') __import__(name='time', level=0) - self.assertRaises(ImportError, __import__, 'spamspam') + self.assertRaises(ModuleNotFoundError, __import__, 'spamspam') self.assertRaises(TypeError, __import__, 1, 2, 3, 4) self.assertRaises(ValueError, __import__, '') self.assertRaises(TypeError, __import__, 'sys', name='sys') @@ -403,6 +403,10 @@ def test_compile_top_level_await_no_coro(self): # TODO: RUSTPYTHON @unittest.expectedFailure + @unittest.skipIf( + support.is_emscripten or support.is_wasi, + "socket.accept is broken" + ) def test_compile_top_level_await(self): """Test whether code some top level await can be compiled. @@ -519,10 +523,15 @@ def test_compile_async_generator(self): exec(co, glob) self.assertEqual(type(glob['ticker']()), AsyncGeneratorType) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_delattr(self): sys.spam = 1 delattr(sys, 'spam') self.assertRaises(TypeError, delattr) + self.assertRaises(TypeError, delattr, sys) + msg = r"^attribute name must be string, not 'int'$" + self.assertRaisesRegex(TypeError, msg, delattr, sys, 1) # TODO: RUSTPYTHON @unittest.expectedFailure @@ -748,11 +757,9 @@ def test_exec_globals(self): self.assertRaises(TypeError, exec, code, {'__builtins__': 123}) - # no __build_class__ function - code = compile("class A: pass", "", "exec") - self.assertRaisesRegex(NameError, "__build_class__ not found", - exec, code, {'__builtins__': {}}) - + # TODO: RUSTPYTHON + @unittest.expectedFailure + def test_exec_globals_frozen(self): class frozendict_error(Exception): pass @@ -769,12 +776,55 @@ def __setitem__(self, key, value): self.assertRaises(frozendict_error, exec, code, {'__builtins__': frozen_builtins}) + # no __build_class__ function + code = compile("class A: pass", "", "exec") + self.assertRaisesRegex(NameError, "__build_class__ not found", + exec, code, {'__builtins__': {}}) + # __build_class__ in a custom __builtins__ + exec(code, {'__builtins__': frozen_builtins}) + self.assertRaisesRegex(NameError, "__build_class__ not found", + exec, code, {'__builtins__': frozendict()}) + # read-only globals namespace = frozendict({}) code = compile("x=1", "test", "exec") self.assertRaises(frozendict_error, exec, code, namespace) + # TODO: RUSTPYTHON + @unittest.expectedFailure + def test_exec_globals_error_on_get(self): + # custom `globals` or `builtins` can raise errors on item access + class setonlyerror(Exception): + pass + + class setonlydict(dict): + def __getitem__(self, key): + raise setonlyerror + + # globals' `__getitem__` raises + code = compile("globalname", "test", "exec") + self.assertRaises(setonlyerror, + exec, code, setonlydict({'globalname': 1})) + + # builtins' `__getitem__` raises + code = compile("superglobal", "test", "exec") + self.assertRaises(setonlyerror, exec, code, + {'__builtins__': setonlydict({'superglobal': 1})}) + + # TODO: RUSTPYTHON + @unittest.expectedFailure + def test_exec_globals_dict_subclass(self): + class customdict(dict): # this one should not do anything fancy + pass + + code = compile("superglobal", "test", "exec") + # works correctly + exec(code, {'__builtins__': customdict({'superglobal': 1})}) + # custom builtins dict subclass is missing key + self.assertRaisesRegex(NameError, "name 'superglobal' is not defined", + exec, code, {'__builtins__': customdict()}) + def test_exec_redirected(self): savestdout = sys.stdout sys.stdout = None # Whatever that cannot flush() @@ -786,6 +836,86 @@ def test_exec_redirected(self): finally: sys.stdout = savestdout + # TODO: RUSTPYTHON + @unittest.expectedFailure + def test_exec_closure(self): + def function_without_closures(): + return 3 * 5 + + result = 0 + def make_closure_functions(): + a = 2 + b = 3 + c = 5 + def three_freevars(): + nonlocal result + nonlocal a + nonlocal b + result = a*b + def four_freevars(): + nonlocal result + nonlocal a + nonlocal b + nonlocal c + result = a*b*c + return three_freevars, four_freevars + three_freevars, four_freevars = make_closure_functions() + + # "smoke" test + result = 0 + exec(three_freevars.__code__, + three_freevars.__globals__, + closure=three_freevars.__closure__) + self.assertEqual(result, 6) + + # should also work with a manually created closure + result = 0 + my_closure = (CellType(35), CellType(72), three_freevars.__closure__[2]) + exec(three_freevars.__code__, + three_freevars.__globals__, + closure=my_closure) + self.assertEqual(result, 2520) + + # should fail: closure isn't allowed + # for functions without free vars + self.assertRaises(TypeError, + exec, + function_without_closures.__code__, + function_without_closures.__globals__, + closure=my_closure) + + # should fail: closure required but wasn't specified + self.assertRaises(TypeError, + exec, + three_freevars.__code__, + three_freevars.__globals__, + closure=None) + + # should fail: closure of wrong length + self.assertRaises(TypeError, + exec, + three_freevars.__code__, + three_freevars.__globals__, + closure=four_freevars.__closure__) + + # should fail: closure using a list instead of a tuple + my_closure = list(my_closure) + self.assertRaises(TypeError, + exec, + three_freevars.__code__, + three_freevars.__globals__, + closure=my_closure) + + # should fail: closure tuple with one non-cell-var + my_closure[0] = int + my_closure = tuple(my_closure) + self.assertRaises(TypeError, + exec, + three_freevars.__code__, + three_freevars.__globals__, + closure=my_closure) + + def test_filter(self): self.assertEqual(list(filter(lambda c: 'a' <= c <= 'z', 'Hello World')), list('elloorld')) self.assertEqual(list(filter(None, [1, 'hello', [], [3], '', None, 9, 0])), [1, 'hello', [3], 9]) @@ -817,19 +947,27 @@ def test_filter_pickle(self): f2 = filter(filter_char, "abcdeabcde") self.check_iter_pickle(f1, list(f2), proto) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_getattr(self): self.assertTrue(getattr(sys, 'stdout') is sys.stdout) - self.assertRaises(TypeError, getattr, sys, 1) - self.assertRaises(TypeError, getattr, sys, 1, "foo") self.assertRaises(TypeError, getattr) + self.assertRaises(TypeError, getattr, sys) + msg = r"^attribute name must be string, not 'int'$" + self.assertRaisesRegex(TypeError, msg, getattr, sys, 1) + self.assertRaisesRegex(TypeError, msg, getattr, sys, 1, 'spam') self.assertRaises(AttributeError, getattr, sys, chr(sys.maxunicode)) # unicode surrogates are not encodable to the default encoding (utf8) self.assertRaises(AttributeError, getattr, 1, "\uDAD1\uD51E") + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_hasattr(self): self.assertTrue(hasattr(sys, 'stdout')) - self.assertRaises(TypeError, hasattr, sys, 1) self.assertRaises(TypeError, hasattr) + self.assertRaises(TypeError, hasattr, sys) + msg = r"^attribute name must be string, not 'int'$" + self.assertRaisesRegex(TypeError, msg, hasattr, sys, 1) self.assertEqual(False, hasattr(sys, chr(sys.maxunicode))) # Check that hasattr propagates all exceptions outside of @@ -1216,7 +1354,7 @@ def test_open_default_encoding(self): del os.environ[key] self.write_testfile() - current_locale_encoding = locale.getpreferredencoding(False) + current_locale_encoding = locale.getencoding() with warnings.catch_warnings(): warnings.simplefilter("ignore", EncodingWarning) fp = open(TESTFN, 'w') @@ -1227,6 +1365,7 @@ def test_open_default_encoding(self): os.environ.update(old_environ) @unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON Windows') + @support.requires_subprocess() def test_open_non_inheritable(self): fileobj = open(__file__, encoding="utf-8") with fileobj: @@ -1475,11 +1614,16 @@ def test_bug_27936(self): self.assertEqual(round(x, None), round(x)) self.assertEqual(type(round(x, None)), type(round(x))) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_setattr(self): setattr(sys, 'spam', 1) self.assertEqual(sys.spam, 1) - self.assertRaises(TypeError, setattr, sys, 1, 'spam') self.assertRaises(TypeError, setattr) + self.assertRaises(TypeError, setattr, sys) + self.assertRaises(TypeError, setattr, sys, 'spam') + msg = r"^attribute name must be string, not 'int'$" + self.assertRaisesRegex(TypeError, msg, setattr, sys, 1, 'spam') # test_str(): see test_unicode.py and test_bytes.py for str() tests. @@ -1998,10 +2142,6 @@ def test_envar_ignored_when_hook_is_set(self): breakpoint() mock.assert_not_called() - def test_runtime_error_when_hook_is_lost(self): - del sys.breakpointhook - with self.assertRaises(RuntimeError): - breakpoint() @unittest.skipUnless(pty, "the pty and signal modules must be available") class PtyTests(unittest.TestCase): @@ -2270,6 +2410,8 @@ def test_type_nokwargs(self): with self.assertRaises(TypeError): type('a', (), dict={}) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_type_name(self): for name in 'A', '\xc4', '\U0001f40d', 'B.A', '42', '': with self.subTest(name=name): @@ -2279,10 +2421,8 @@ def test_type_name(self): self.assertEqual(A.__module__, __name__) with self.assertRaises(ValueError): type('A\x00B', (), {}) - # TODO: RUSTPYTHON (https://github.com/RustPython/RustPython/issues/935) - with self.assertRaises(AssertionError): - with self.assertRaises(ValueError): - type('A\udcdcB', (), {}) + with self.assertRaises(UnicodeEncodeError): + type('A\udcdcB', (), {}) with self.assertRaises(TypeError): type(b'A', (), {}) @@ -2298,13 +2438,9 @@ def test_type_name(self): with self.assertRaises(ValueError): A.__name__ = 'A\x00B' self.assertEqual(A.__name__, 'C') - # TODO: RUSTPYTHON (https://github.com/RustPython/RustPython/issues/935) - with self.assertRaises(AssertionError): - with self.assertRaises(ValueError): - A.__name__ = 'A\udcdcB' - self.assertEqual(A.__name__, 'C') - # TODO: RUSTPYTHON: the previous __name__ set should fail but doesn't: reset it - A.__name__ = 'C' + with self.assertRaises(UnicodeEncodeError): + A.__name__ = 'A\udcdcB' + self.assertEqual(A.__name__, 'C') with self.assertRaises(TypeError): A.__name__ = b'A' self.assertEqual(A.__name__, 'C')