From 0eea760443d4cdf41c88012377ac19cf47a2b6d2 Mon Sep 17 00:00:00 2001 From: JaeyoungAhn Date: Sat, 25 Mar 2023 20:17:27 +0900 Subject: [PATCH 1/4] Update test_builtin.py from CPython v3.11.2 --- Lib/test/test_builtin.py | 177 ++++++++++++++++++++++++++++++++------- 1 file changed, 147 insertions(+), 30 deletions(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 027d209f38..e3d1288992 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. @@ -523,6 +527,9 @@ 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 +755,7 @@ 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__': {}}) - + def test_exec_globals_frozen(self): class frozendict_error(Exception): pass @@ -769,12 +772,51 @@ 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) + 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})}) + + 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 +828,84 @@ def test_exec_redirected(self): finally: sys.stdout = savestdout + 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]) @@ -819,17 +939,21 @@ def test_filter_pickle(self): 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") 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 +1340,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') @@ -1226,7 +1350,7 @@ def test_open_default_encoding(self): os.environ.clear() 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: @@ -1478,8 +1602,11 @@ def test_bug_27936(self): 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 +2125,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): @@ -2279,10 +2402,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 +2419,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') From 0873e451a80a3367e3b355ce256e2efc55f390f2 Mon Sep 17 00:00:00 2001 From: JaeyoungAhn Date: Sat, 25 Mar 2023 20:30:40 +0900 Subject: [PATCH 2/4] update test_builtin.py from cpython v3.11.2 --- Lib/test/test_builtin.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index e3d1288992..05f0dc696c 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -523,6 +523,8 @@ 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') @@ -755,6 +757,8 @@ def test_exec_globals(self): self.assertRaises(TypeError, exec, code, {'__builtins__': 123}) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_exec_globals_frozen(self): class frozendict_error(Exception): pass @@ -787,6 +791,8 @@ def __setitem__(self, key, value): 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): @@ -806,6 +812,8 @@ def __getitem__(self, key): 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 @@ -828,6 +836,8 @@ 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 @@ -937,6 +947,8 @@ 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) @@ -948,6 +960,8 @@ def test_getattr(self): # 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) @@ -1599,6 +1613,8 @@ 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) @@ -2393,6 +2409,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): From f750c0ca0631289ccc4792387d59d1a5b007cf1e Mon Sep 17 00:00:00 2001 From: JaeyoungAhn Date: Sat, 25 Mar 2023 22:13:50 +0900 Subject: [PATCH 3/4] added back the skipIf for windows --- Lib/test/test_builtin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 05f0dc696c..4e9da81220 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -1364,6 +1364,7 @@ def test_open_default_encoding(self): os.environ.clear() 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") @@ -1614,7 +1615,7 @@ def test_bug_27936(self): self.assertEqual(type(round(x, None)), type(round(x))) # TODO: RUSTPYTHON - @unittest.expectedFailure + # @unittest.expectedFailure def test_setattr(self): setattr(sys, 'spam', 1) self.assertEqual(sys.spam, 1) From 44da5728933ddfc6885b3426fb67cbd2acb2948f Mon Sep 17 00:00:00 2001 From: JaeyoungAhn Date: Sat, 25 Mar 2023 22:19:15 +0900 Subject: [PATCH 4/4] uncomment annotation --- Lib/test/test_builtin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 4e9da81220..2c26da7113 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -1615,7 +1615,7 @@ def test_bug_27936(self): self.assertEqual(type(round(x, None)), type(round(x))) # TODO: RUSTPYTHON - # @unittest.expectedFailure + @unittest.expectedFailure def test_setattr(self): setattr(sys, 'spam', 1) self.assertEqual(sys.spam, 1)