From 36cc6d194597c2769f23272aeaed21137efbf6db Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Tue, 29 Jul 2025 13:18:36 +0900 Subject: [PATCH 1/2] Backport CPython gh-137195 https://github.com/python/cpython/pull/137195 --- Lib/test/support/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index b69278f9902..652a8cd92b3 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -514,7 +514,12 @@ def has_no_debug_ranges(): return not bool(config['code_debug_ranges']) def requires_debug_ranges(reason='requires co_positions / debug_ranges'): - return unittest.skipIf(has_no_debug_ranges(), reason) + try: + skip = has_no_debug_ranges() + except unittest.SkipTest as e: + skip = True + reason = e.args[0] if e.args else reason + return unittest.skipIf(skip, reason) @contextlib.contextmanager def suppress_immortalization(suppress=True): From f8891ffe3a166849f71217524cc11219684c51d1 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Tue, 29 Jul 2025 14:31:29 +0900 Subject: [PATCH 2/2] Fix test_compile --- Lib/test/test_compile.py | 63 ++++++++++++++++++++++++++++++---------- vm/src/builtins/code.rs | 12 ++++++++ 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 51c834d7982..5b07b3c85b7 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -138,7 +138,6 @@ def f(x): def test_argument_order(self): self.assertRaises(SyntaxError, exec, 'def f(a=1, b): pass') - @unittest.skip("TODO: RUSTPYTHON, thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseFloatError { kind: Invalid }'") def test_float_literals(self): # testing bad float literals self.assertRaises(SyntaxError, eval, "2e") @@ -201,6 +200,8 @@ def test_literals_with_leading_zeroes(self): self.assertEqual(eval("0o777"), 511) self.assertEqual(eval("-0o0000010"), -8) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_int_literals_too_long(self): n = 3000 source = f"a = 1\nb = 2\nc = {'3'*n}\nd = 4" @@ -274,6 +275,8 @@ def test_none_assignment(self): self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'single') self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec') + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_import(self): succeed = [ 'import sys', @@ -821,6 +824,8 @@ def continue_in_while(): self.assertEqual(None, opcodes[1].argval) self.assertEqual('RETURN_VALUE', opcodes[2].opname) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_consts_in_conditionals(self): def and_true(x): return True and x @@ -844,6 +849,8 @@ def or_false(x): self.assertIn('LOAD_', opcodes[-2].opname) self.assertEqual('RETURN_VALUE', opcodes[-1].opname) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_imported_load_method(self): sources = [ """\ @@ -878,6 +885,8 @@ def foo(x): self.assertIn('LOAD_ATTR', instructions) self.assertIn('PRECALL', instructions) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_lineno_procedure_call(self): def call(): ( @@ -886,6 +895,8 @@ def call(): line1 = call.__code__.co_firstlineno + 1 assert line1 not in [line for (_, _, line) in call.__code__.co_lines()] + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_lineno_after_implicit_return(self): TRUE = True # Don't use constant True or False, as compiler will remove test @@ -920,6 +931,8 @@ def save_caller_frame(): func(save_caller_frame) self.assertEqual(frame.f_lineno-frame.f_code.co_firstlineno, lastline) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_lineno_after_no_code(self): def no_code1(): "doc string" @@ -944,6 +957,8 @@ def get_code_lines(self, code): last_line = line return res + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_lineno_attribute(self): def load_attr(): return ( @@ -988,6 +1003,8 @@ def aug_store_attr(): code_lines = self.get_code_lines(func.__code__) self.assertEqual(lines, code_lines) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_line_number_genexp(self): def return_genexp(): @@ -1002,6 +1019,8 @@ def return_genexp(): code_lines = self.get_code_lines(genexp_code) self.assertEqual(genexp_lines, code_lines) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_line_number_implicit_return_after_async_for(self): async def test(aseq): @@ -1022,6 +1041,8 @@ def test_big_dict_literal(self): the_dict = "{" + ",".join(f"{x}:{x}" for x in range(dict_size)) + "}" self.assertEqual(len(eval(the_dict)), dict_size) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_redundant_jump_in_if_else_break(self): # Check if bytecode containing jumps that simply point to the next line # is generated around if-else-break style structures. See bpo-42615. @@ -1051,6 +1072,8 @@ def if_else_break(): elif instr.opname in HANDLED_JUMPS: self.assertNotEqual(instr.arg, (line + 1)*INSTR_SIZE) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_no_wraparound_jump(self): # See https://bugs.python.org/issue46724 @@ -1061,6 +1084,8 @@ def while_not_chained(a, b, c): for instr in dis.Bytecode(while_not_chained): self.assertNotEqual(instr.opname, "EXTENDED_ARG") + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_compare_positions(self): for opname, op in [ ("COMPARE_OP", "<"), @@ -1361,64 +1386,66 @@ def check_stack_size(self, code): max_size = math.ceil(math.log(len(code.co_code))) self.assertLessEqual(code.co_stacksize, max_size) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_and(self): self.check_stack_size("x and " * self.N + "x") - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_or(self): self.check_stack_size("x or " * self.N + "x") - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_and_or(self): self.check_stack_size("x and x or " * self.N + "x") - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_chained_comparison(self): self.check_stack_size("x < " * self.N + "x") - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_if_else(self): self.check_stack_size("x if x else " * self.N + "x") - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_binop(self): self.check_stack_size("x + " * self.N + "x") + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_list(self): self.check_stack_size("[" + "x, " * self.N + "x]") + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_tuple(self): self.check_stack_size("(" + "x, " * self.N + "x)") + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_set(self): self.check_stack_size("{" + "x, " * self.N + "x}") + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_dict(self): self.check_stack_size("{" + "x:x, " * self.N + "x:x}") + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_func_args(self): self.check_stack_size("f(" + "x, " * self.N + ")") + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_func_kwargs(self): kwargs = (f'a{i}=x' for i in range(self.N)) self.check_stack_size("f(" + ", ".join(kwargs) + ")") + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_meth_args(self): self.check_stack_size("o.m(" + "x, " * self.N + ")") + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_meth_kwargs(self): kwargs = (f'a{i}=x' for i in range(self.N)) self.check_stack_size("o.m(" + ", ".join(kwargs) + ")") - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_func_and(self): code = "def f(x):\n" code += " x and x\n" * self.N @@ -1513,6 +1540,8 @@ def test_try_except_as(self): """ self.check_stack_size(snippet) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_try_except_star_qualified(self): snippet = """ try: @@ -1524,6 +1553,8 @@ def test_try_except_star_qualified(self): """ self.check_stack_size(snippet) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_try_except_star_as(self): snippet = """ try: @@ -1535,6 +1566,8 @@ def test_try_except_star_as(self): """ self.check_stack_size(snippet) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_try_except_star_finally(self): snippet = """ try: diff --git a/vm/src/builtins/code.rs b/vm/src/builtins/code.rs index 8286b63f64e..1ce0f3b3e03 100644 --- a/vm/src/builtins/code.rs +++ b/vm/src/builtins/code.rs @@ -326,6 +326,18 @@ impl PyCode { vm.ctx.new_tuple(varnames) } + #[pygetset] + pub fn co_code(&self, vm: &VirtualMachine) -> crate::builtins::PyBytesRef { + // SAFETY: CodeUnit is #[repr(C)] with size 2, so we can safely transmute to bytes + let bytes = unsafe { + std::slice::from_raw_parts( + self.code.instructions.as_ptr() as *const u8, + self.code.instructions.len() * 2, + ) + }; + vm.ctx.new_bytes(bytes.to_vec()) + } + #[pygetset] pub fn co_freevars(&self, vm: &VirtualMachine) -> PyTupleRef { let names = self