From 7e600e0031625afe060218154ceb1535891f28d5 Mon Sep 17 00:00:00 2001 From: Jeongseop Lim Date: Fri, 30 Oct 2026 02:42:31 +0900 Subject: [PATCH 1/4] Require both _tuplegetter() arguments positionally The tp_new signature declared no minimum and no positional-only parameters, so _tuplegetter(0) and _tuplegetter() built a descriptor from defaults, and index and doc were accepted as keywords. CPython requires exactly two positional arguments and rejects keywords. Signed-off-by: Jeongseop Lim --- .../src/tests/test_collections.py | 12 +++++++++++- .../builtins/objects/tuple/TupleGetterBuiltins.java | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_collections.py b/graalpython/com.oracle.graal.python.test/src/tests/test_collections.py index 6f88d69be8..5a14f4c133 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_collections.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_collections.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -57,3 +57,13 @@ def test_import(): except ImportError: imported = False assert imported + + +def test_tuplegetter_arguments(): + from collections import _tuplegetter + assert_raises(TypeError, _tuplegetter) + assert_raises(TypeError, _tuplegetter, 0) + assert_raises(TypeError, _tuplegetter, 0, None, 1) + assert_raises(TypeError, _tuplegetter, 0, doc=None) + assert_raises(TypeError, _tuplegetter, index=0, doc=None) + assert _tuplegetter(1, 'doc').__get__((10, 20)) == 20 diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleGetterBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleGetterBuiltins.java index 1962762fda..ea5ace648e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleGetterBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/TupleGetterBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -95,7 +95,7 @@ protected List> getNodeFa } @Slot(value = SlotKind.tp_new, isComplex = true) - @SlotSignature(name = J_TUPLE_GETTER, parameterNames = {"cls", "index", "doc"}) + @SlotSignature(name = J_TUPLE_GETTER, minNumOfPositionalArgs = 3, numOfPositionalOnlyArgs = 3, parameterNames = {"cls", "index", "doc"}) @ArgumentClinic(name = "index", conversion = ArgumentClinic.ClinicConversion.Index) @GenerateNodeFactory public abstract static class TupleGetterNode extends PythonTernaryClinicBuiltinNode { From 8d42af5cb40b06fe9a419b5493ad67a041087be3 Mon Sep 17 00:00:00 2001 From: Jeongseop Lim Date: Fri, 30 Oct 2026 03:03:43 +0900 Subject: [PATCH 2/4] Add math.cbrt() and math.exp2() Both functions were added to the math module in Python 3.11 and were missing, so math.cbrt and math.exp2 raised AttributeError. cbrt uses Math.cbrt; exp2 uses Math.pow(2.0, x) and raises OverflowError on an infinite result from a finite argument, as exp does. Enable CPython's testCbrt and testExp2, which now pass. Signed-off-by: Jeongseop Lim --- .../src/tests/unittest_tags/test_math.txt | 2 ++ .../builtins/modules/MathModuleBuiltins.java | 34 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_math.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_math.txt index 538e088a16..170c54c851 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_math.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_math.txt @@ -23,6 +23,7 @@ test.test_math.MathTests.testAsinh @ darwin-arm64,linux-aarch64,linux-aarch64-gi test.test_math.MathTests.testAtan @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_math.MathTests.testAtan2 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_math.MathTests.testAtanh @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github +test.test_math.MathTests.testCbrt @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_math.MathTests.testCeil @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_math.MathTests.testComb @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_math.MathTests.testConstants @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github @@ -32,6 +33,7 @@ test.test_math.MathTests.testCosh @ darwin-arm64,linux-aarch64,linux-aarch64-git test.test_math.MathTests.testDegrees @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_math.MathTests.testDist @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_math.MathTests.testExp @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github +test.test_math.MathTests.testExp2 @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_math.MathTests.testFabs @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_math.MathTests.testFactorial @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_math.MathTests.testFactorialNonIntegers @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java index 029f6ac3cf..4f97e2fb64 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java @@ -255,6 +255,22 @@ private static double compute(Node inliningTarget, double value, PRaiseNode rais } } + @Builtin(name = "cbrt", minNumOfPositionalArgs = 1, doc = "Return the cube root of x.") + @GenerateNodeFactory + public abstract static class CbrtNode extends PythonUnaryBuiltinNode { + + @Specialization + static double doGeneric(VirtualFrame frame, Object value, + @Bind Node inliningTarget, + @Cached MathUnaryHelperNode helperNode) { + return helperNode.execute(frame, inliningTarget, value, CbrtNode::compute); + } + + private static double compute(Node inliningTarget, double value, PRaiseNode raiseNode) { + return Math.cbrt(value); + } + } + @Builtin(name = "exp", minNumOfPositionalArgs = 1) @GenerateNodeFactory public abstract static class ExpNode extends PythonUnaryBuiltinNode { @@ -273,6 +289,24 @@ private static double compute(Node inliningTarget, double value, PRaiseNode rais } } + @Builtin(name = "exp2", minNumOfPositionalArgs = 1, doc = "Return 2 raised to the power of x.") + @GenerateNodeFactory + public abstract static class Exp2Node extends PythonUnaryBuiltinNode { + + @Specialization + static double doGeneric(VirtualFrame frame, Object value, + @Bind Node inliningTarget, + @Cached MathUnaryHelperNode helperNode) { + return helperNode.execute(frame, inliningTarget, value, Exp2Node::compute); + } + + private static double compute(Node inliningTarget, double value, PRaiseNode raiseNode) { + double result = Math.pow(2.0, value); + checkMathRangeError(Double.isFinite(value) && Double.isInfinite(result), inliningTarget, raiseNode); + return result; + } + } + @Builtin(name = "expm1", minNumOfPositionalArgs = 1) @GenerateNodeFactory public abstract static class Expm1Node extends PythonUnaryBuiltinNode { From 589866504dc45b4fe403cd5545b9b21a1f7bea1b Mon Sep 17 00:00:00 2001 From: Jeongseop Lim Date: Fri, 30 Oct 2026 03:21:42 +0900 Subject: [PATCH 3/4] Accept and ignore extra _thread.RLock() arguments The constructor took only cls, so _thread.RLock(0) and threading.RLock(0) raised TypeError. CPython 3.12 and 3.13 accept and ignore any arguments, and threading.RLock passes them on after a DeprecationWarning that announces the removal for 3.15. Signed-off-by: Jeongseop Lim --- .../src/tests/test_threading.py | 7 +++++++ .../python/builtins/objects/thread/RLockBuiltins.java | 9 ++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_threading.py b/graalpython/com.oracle.graal.python.test/src/tests/test_threading.py index e3af32a7e8..0bf2a6ecfa 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_threading.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_threading.py @@ -173,3 +173,10 @@ def test_blocking_os_read_thread_does_not_deadlock_import_re(): ) assert result.returncode == 0, result.stderr assert result.stdout.rstrip().endswith("ok"), result.stdout + + +def test_rlock_new_ignores_arguments(): + import _thread + + assert type(_thread.RLock(0)) is _thread.RLock + assert type(_thread.RLock(x=1)) is _thread.RLock diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/thread/RLockBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/thread/RLockBuiltins.java index 7e39fd9078..b0f93cb3ea 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/thread/RLockBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/thread/RLockBuiltins.java @@ -52,6 +52,7 @@ import com.oracle.graal.python.builtins.PythonBuiltins; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes; +import com.oracle.graal.python.builtins.objects.function.PKeyword; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.builtins.objects.type.TypeNodes; @@ -62,6 +63,7 @@ import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode; import com.oracle.graal.python.nodes.util.CastToJavaUnsignedLongNode; import com.oracle.graal.python.runtime.GilNode; import com.oracle.graal.python.runtime.exception.PythonErrorType; @@ -85,11 +87,12 @@ protected List> getNodeFa } @Slot(value = SlotKind.tp_new, isComplex = true) - @SlotSignature(name = "RLock", minNumOfPositionalArgs = 1) + @SlotSignature(name = "RLock", minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true) @GenerateNodeFactory - public abstract static class ConstructRLockNode extends PythonUnaryBuiltinNode { + public abstract static class ConstructRLockNode extends PythonVarargsBuiltinNode { + @SuppressWarnings("unused") @Specialization - PRLock construct(Object cls, + PRLock construct(Object cls, Object[] arguments, PKeyword[] keywords, @Cached TypeNodes.GetInstanceShape getInstanceShape) { return PFactory.createRLock(cls, getInstanceShape.execute(cls)); } From 28a0b733f1325954dcdc61c6e092b6d476a5911b Mon Sep 17 00:00:00 2001 From: Jeongseop Lim Date: Fri, 30 Oct 2026 03:23:35 +0900 Subject: [PATCH 4/4] Name the _csv reader and writer types like CPython The types were registered under the names Reader and Writer, so type(csv.reader([])) printed as . In CPython the types are named reader and writer and are exposed in _csv under the aliases Reader and Writer. Rename them, keep the module name, and add the aliases. Signed-off-by: Jeongseop Lim --- .../com.oracle.graal.python.test/src/tests/test_csv.py | 9 +++++++++ .../graal/python/builtins/PythonBuiltinClassType.java | 4 ++-- .../python/builtins/modules/csv/CSVModuleBuiltins.java | 4 +++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_csv.py b/graalpython/com.oracle.graal.python.test/src/tests/test_csv.py index cc226c7679..0ab59379f3 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_csv.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_csv.py @@ -46,6 +46,15 @@ class TestUnicodeCharacters(unittest.TestCase): def test_builtin_type_as_dialect(self): self.assertIsInstance(csv.reader(re.ASCII, int), type(csv.reader([]))) + def test_reader_writer_type_names(self): + import _csv + self.assertIs(type(csv.reader([])), _csv.Reader) + self.assertEqual(_csv.Reader.__name__, 'reader') + self.assertEqual(_csv.Reader.__module__, '_csv') + with TemporaryFile("w") as fileobj: + self.assertIs(type(csv.writer(fileobj)), _csv.Writer) + self.assertEqual(_csv.Writer.__name__, 'writer') + def test_read_utf_32_delimiter(self): test_data = ['a\U0001F642b'] reader = csv.reader(test_data, delimiter="\U0001F642") diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java index 6585f85507..e185eec3cb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java @@ -1314,8 +1314,8 @@ def takewhile(predicate, iterable): // csv CSVDialect("Dialect", PythonObject, newBuilder().publishInModule("_csv").basetype().slots(CSVDialectBuiltins.SLOTS)), - CSVReader("Reader", PythonObject, newBuilder().publishInModule("_csv").basetype().disallowInstantiation().slots(CSVReaderBuiltins.SLOTS)), - CSVWriter("Writer", PythonObject, newBuilder().publishInModule("_csv").basetype().disallowInstantiation()), + CSVReader("reader", PythonObject, newBuilder().moduleName("_csv").basetype().disallowInstantiation().slots(CSVReaderBuiltins.SLOTS)), + CSVWriter("writer", PythonObject, newBuilder().moduleName("_csv").basetype().disallowInstantiation()), // codecs PEncodingMap("EncodingMap", PythonObject, newBuilder().disallowInstantiation()), diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/csv/CSVModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/csv/CSVModuleBuiltins.java index 1e0513e8d5..f933d8c448 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/csv/CSVModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/csv/CSVModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -121,6 +121,8 @@ public void initialize(Python3Core core) { addBuiltinConstant("QUOTE_STRINGS", QUOTE_STRINGS.ordinal()); addBuiltinConstant("QUOTE_NOTNULL", QUOTE_NOTNULL.ordinal()); addBuiltinConstant(T__DIALECTS, PFactory.createDict(core.getLanguage())); + addBuiltinConstant("Reader", PythonBuiltinClassType.CSVReader); + addBuiltinConstant("Writer", PythonBuiltinClassType.CSVWriter); super.initialize(core); }