diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_bytes.py b/graalpython/com.oracle.graal.python.test/src/tests/test_bytes.py index 7a74fd9518..e4ac58ade1 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_bytes.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_bytes.py @@ -89,6 +89,16 @@ def __bytes__(self): assert_raises(TypeError, bytes, errors="strict") +def test_decode_empty_skips_codec_lookup(): + assert str(b'', 'x') == '' + assert str(bytearray(), 'x', 'y') == '' + assert str(memoryview(b''), 'x') == '' + assert b''.decode('x') == '' + assert bytearray().decode('x') == '' + assert_raises(LookupError, str, b'a', 'x') + assert_raises(TypeError, str, 1, 'x') + + def test_from_ssize(): assert bytes(0) == b'' assert bytes(1) == b'\x00' diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_complex.py b/graalpython/com.oracle.graal.python.test/src/tests/test_complex.py index e1b6ea9ec9..096e2256ee 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_complex.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_complex.py @@ -304,6 +304,20 @@ class SubComplex(complex): assert result == 2 + 3j assert type(result) is complex + +def test_create_checks_arguments_before_converting(): + class RaisingReal: + def __float__(self): + raise KeyError + + class RaisingImag: + def __float__(self): + raise RuntimeError + + assert_raises(TypeError, complex, {}, RaisingImag()) + assert_raises(TypeError, complex, RaisingReal(), {}) + assert_raises(KeyError, complex, RaisingReal(), RaisingImag()) + class ComplexTest(unittest.TestCase): def assertAlmostEqual(self, a, b): diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_dict.py b/graalpython/com.oracle.graal.python.test/src/tests/test_dict.py index 63ce7afee6..96b1a538f3 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_dict.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_dict.py @@ -2007,3 +2007,16 @@ def test_bulk_value_update_preserves_iterators(): d.update({k: -v for k, v in d.items()}) assert list(it) == expected[1:] assert list(reverse) == expected[-2::-1] + + +def test_reversed_iterator_types(): + d = {1: 'a', 2: 'b'} + assert type(reversed(d)).__name__ == 'dict_reversekeyiterator' + assert type(reversed(d.keys())).__name__ == 'dict_reversekeyiterator' + assert type(reversed(d.values())).__name__ == 'dict_reversevalueiterator' + assert type(reversed(d.items())).__name__ == 'dict_reverseitemiterator' + assert type(reversed(d)) is not type(iter(d)) + assert_raises(TypeError, type(reversed(d))) + assert_raises(TypeError, type(reversed(d.values()))) + assert_raises(TypeError, type(reversed(d.items()))) + assert list(reversed(d.items())) == [(2, 'b'), (1, 'a')] diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_parser.py b/graalpython/com.oracle.graal.python.test/src/tests/test_parser.py index 5941b6668d..96d1f70b19 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_parser.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_parser.py @@ -42,6 +42,15 @@ import types +def assert_raises(err, fn, *args, **kwargs): + raised = False + try: + fn(*args, **kwargs) + except err: + raised = True + assert raised + + def test_incomplete_input_error(): flags = 0x4000 | 0x200 # PyCF_ALLOW_INCOMPLETE_INPUT | PyCF_DONT_IMPLY_DEDENT @@ -64,6 +73,15 @@ def test_incomplete_input_error(): assert False, "SyntaxError was not raised" +def test_compile_unrecognised_flags_message(): + try: + compile("1", "", "exec", 0x7fffffff) + except ValueError as e: + assert str(e) == "compile(): unrecognised flags" + else: + assert False, "ValueError was not raised" + + def test_lambdas_as_function_default_argument_values(): globs = {} exec(""" @@ -152,6 +170,16 @@ def newhook(value): sys.displayhook = oldhook +def test_compile_checks_mode_before_source(): + assert_raises(ValueError, compile, None, "", "x") + assert_raises(ValueError, compile, "\x00", "", "x") + assert_raises(ValueError, compile, b"\xff", "", "x") + assert_raises(ValueError, compile, b"\x00", "", "x") + assert_raises(ValueError, compile, None, "", "x", ast.PyCF_ONLY_AST) + assert_raises(ValueError, compile, None, "", "func_type") + assert_raises(ValueError, compile, ast.parse("1"), "", "func_type") + + def test_underscore_in_numbers(): assert eval('1_0') == 10 assert eval('0b1_1') == 0b11 diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java index 2eaeb899fc..f999eca52e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java @@ -1011,16 +1011,11 @@ Object doCompile(VirtualFrame frame, TruffleString expression, TruffleString fil Object compile(TruffleString expression, TruffleString filename, TruffleString mode, int flags, @SuppressWarnings("unused") boolean dontInherit, int optimize, int featureVersion) { checkFlags(flags); checkOptimize(optimize, optimize); + InputType type = getParserInputType(mode, flags); checkSource(expression); TruffleString code = expression; PythonContext context = getContext(); - InputType type = getParserInputType(mode, flags); - if (type == InputType.FUNCTION_TYPE) { - if ((flags & PyCF_ONLY_AST) == 0) { - throw PRaiseNode.raiseStatic(this, ValueError, ErrorMessages.COMPILE_MODE_FUNC_TYPE_REQUIED_FLAG_ONLY_AST); - } - } if (lstrip && !code.isEmpty()) { int c = code.codePointAtIndexUncached(0, TS_ENCODING); if (c == ' ' || c == '\t') { @@ -1087,11 +1082,12 @@ Object generic(VirtualFrame frame, Object wSource, Object wFilename, TruffleStri } checkFlags(flags); checkOptimize(optimize, optimize); + InputType type = getParserInputType(mode, flags); Object saved = BoundaryCallContext.enter(frame, boundaryCallData); try { if (AstModuleBuiltins.isAst(context, wSource)) { - ModTy mod = AstModuleBuiltins.obj2sst(inliningTarget, context, wSource, getParserInputType(mode, flags)); + ModTy mod = AstModuleBuiltins.obj2sst(inliningTarget, context, wSource, type); if ((flags & PyCF_ONLY_AST) != 0) { if ((flags & PyCF_OPTIMIZED_AST) != PyCF_OPTIMIZED_AST) { return wSource; @@ -1143,7 +1139,7 @@ private void checkOptimize(int optimize, Object kwOptimize) throws PException { @TruffleBoundary private void checkFlags(int flags) { if ((flags & ~(PyCF_MASK | PyCF_MASK_OBSOLETE | PyCF_COMPILE_MASK)) != 0) { - throw PRaiseNode.raiseStatic(this, ValueError, null, NO_VALUE, ErrorMessages.UNRECOGNIZED_FLAGS, PythonUtils.EMPTY_OBJECT_ARRAY); + throw PRaiseNode.raiseStatic(this, ValueError, ErrorMessages.UNRECOGNIZED_FLAGS); } } @@ -1156,6 +1152,9 @@ private InputType getParserInputType(TruffleString mode, int flags) { } else if (mode.equalsUncached(StringLiterals.T_SINGLE, TS_ENCODING)) { return InputType.SINGLE; } else if (mode.equalsUncached(StringLiterals.T_FUNC_TYPE, TS_ENCODING)) { + if ((flags & PyCF_ONLY_AST) == 0) { + throw PRaiseNode.raiseStatic(this, ValueError, ErrorMessages.COMPILE_MODE_FUNC_TYPE_REQUIED_FLAG_ONLY_AST); + } return InputType.FUNCTION_TYPE; } else { if ((flags & PyCF_ONLY_AST) != 0) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java index 5920ee72a9..a506ecbccb 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/bytes/BytesCommonBuiltins.java @@ -203,9 +203,15 @@ protected ArgumentClinicProvider getArgumentClinic() { @Specialization static Object decode(VirtualFrame frame, Object self, TruffleString encoding, TruffleString errors, @Bind Node inliningTarget, + @Cached GetBytesStorage getBytesStorage, + @Cached InlinedConditionProfile emptyStringProfile, @Cached CodecsModuleBuiltins.DecodeNode decodeNode, @Cached PyUnicodeCheckNode unicodeCheckNode, @Cached PRaiseNode raiseNode) { + // like CPython's PyUnicode_FromEncodedObject: no codec lookup for empty input + if (emptyStringProfile.profile(inliningTarget, getBytesStorage.execute(inliningTarget, self).length() == 0)) { + return T_EMPTY_STRING; + } Object result = decodeNode.executeWithStrings(frame, self, encoding, errors); if (!unicodeCheckNode.execute(inliningTarget, result)) { throw raiseNode.raise(inliningTarget, TypeError, DECODER_RETURNED_P_INSTEAD_OF_BYTES, encoding, result); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java index 6dcc4631a6..8a54ebd963 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java @@ -618,21 +618,17 @@ Object complexFromComplexObject(VirtualFrame frame, Object cls, Object one, Obje @Cached.Shared("tryComplex") @Cached TryComplexSpecialMethodNode tryComplexNode, @Cached.Shared @Cached PRaiseNode raiseNode) { PComplex oneValue = getComplexNumberFromObject(frame, one, inliningTarget, isComplexType, tryComplexNode); - if (canBeDoubleNode.execute(inliningTarget, two)) { - double twoValue = asDoubleNode.execute(frame, inliningTarget, two); - if (oneValue == null) { - if (one == PNone.NO_VALUE) { - return createComplexNode.execute(inliningTarget, cls, 0, twoValue); - } else if (canBeDoubleNode.execute(inliningTarget, one)) { - return createComplexNode.execute(inliningTarget, cls, asDoubleNode.execute(frame, inliningTarget, one), twoValue); - } else { - throw raiseFirstArgError(one, inliningTarget, raiseNode); - } - } - return createComplexNode.execute(inliningTarget, cls, oneValue.getReal(), oneValue.getImag() + twoValue); - } else { + if (oneValue == null && one != PNone.NO_VALUE && !canBeDoubleNode.execute(inliningTarget, one)) { + throw raiseFirstArgError(one, inliningTarget, raiseNode); + } + if (!canBeDoubleNode.execute(inliningTarget, two)) { throw raiseSecondArgError(two, inliningTarget, raiseNode); } + if (oneValue == null) { + double oneDouble = one == PNone.NO_VALUE ? 0 : asDoubleNode.execute(frame, inliningTarget, one); + return createComplexNode.execute(inliningTarget, cls, oneDouble, asDoubleNode.execute(frame, inliningTarget, two)); + } + return createComplexNode.execute(inliningTarget, cls, oneValue.getReal(), oneValue.getImag() + asDoubleNode.execute(frame, inliningTarget, two)); } @Specialization diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictBuiltins.java index af5b42dcb5..2ecf206665 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictBuiltins.java @@ -436,7 +436,7 @@ static Object run(Object self, @Cached HashingStorageGetReverseIterator getReverseIterator, @Bind PythonLanguage language) { var storage = getStorageNode.execute(inliningTarget, self); - return PFactory.createDictKeyIterator(language, getReverseIterator.execute(inliningTarget, storage), storage, lenNode.execute(inliningTarget, storage)); + return PFactory.createDictReverseKeyIterator(language, getReverseIterator.execute(inliningTarget, storage), storage, lenNode.execute(inliningTarget, storage)); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictValuesBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictValuesBuiltins.java index 4e27468861..c4c8c9dc40 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictValuesBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictValuesBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -109,7 +109,7 @@ static Object doPDictValuesView(PDictValuesView self, @Cached HashingStorageGetReverseIterator getReverseIter, @Bind PythonLanguage language) { HashingStorage storage = self.getWrappedStorage(); - return PFactory.createDictValueIterator(language, getReverseIter.execute(inliningTarget, storage), storage, lenNode.execute(inliningTarget, storage)); + return PFactory.createDictReverseValueIterator(language, getReverseIter.execute(inliningTarget, storage), storage, lenNode.execute(inliningTarget, storage)); } } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictViewBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictViewBuiltins.java index a203480f5d..2f4ee1db81 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictViewBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/dict/DictViewBuiltins.java @@ -193,7 +193,7 @@ static Object getReversedKeysViewIter(PDictKeysView self, @Shared @Cached HashingStorageGetReverseIterator getReverseIterator, @Bind PythonLanguage language) { HashingStorage storage = self.getWrappedStorage(); - return PFactory.createDictKeyIterator(language, getReverseIterator.execute(inliningTarget, storage), storage, lenNode.execute(inliningTarget, storage)); + return PFactory.createDictReverseKeyIterator(language, getReverseIterator.execute(inliningTarget, storage), storage, lenNode.execute(inliningTarget, storage)); } @Specialization @@ -203,7 +203,7 @@ static Object getReversedItemsViewIter(PDictItemsView self, @Shared @Cached HashingStorageGetReverseIterator getReverseIterator, @Bind PythonLanguage language) { HashingStorage storage = self.getWrappedStorage(); - return PFactory.createDictItemIterator(language, getReverseIterator.execute(inliningTarget, storage), storage, lenNode.execute(inliningTarget, storage)); + return PFactory.createDictReverseItemIterator(language, getReverseIterator.execute(inliningTarget, storage), storage, lenNode.execute(inliningTarget, storage)); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java index 06494a5bcf..7f6f1a653a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PFactory.java @@ -1085,14 +1085,29 @@ public static PDictItemIterator createDictItemIterator(PythonLanguage language, initialSize); } + public static PDictItemIterator createDictReverseItemIterator(PythonLanguage language, HashingStorageNodes.HashingStorageIterator iterator, HashingStorage hashingStorage, int initialSize) { + return new PDictItemIterator(PythonBuiltinClassType.PDictReverseItemIterator, PythonBuiltinClassType.PDictReverseItemIterator.getInstanceShape(language), iterator, hashingStorage, + initialSize); + } + public static PDictKeyIterator createDictKeyIterator(PythonLanguage language, HashingStorageNodes.HashingStorageIterator iterator, HashingStorage hashingStorage, int initialSize) { return new PDictKeyIterator(PythonBuiltinClassType.PDictKeyIterator, PythonBuiltinClassType.PDictKeyIterator.getInstanceShape(language), iterator, hashingStorage, initialSize); } + public static PDictKeyIterator createDictReverseKeyIterator(PythonLanguage language, HashingStorageNodes.HashingStorageIterator iterator, HashingStorage hashingStorage, int initialSize) { + return new PDictKeyIterator(PythonBuiltinClassType.PDictReverseKeyIterator, PythonBuiltinClassType.PDictReverseKeyIterator.getInstanceShape(language), iterator, hashingStorage, + initialSize); + } + public static PDictValueIterator createDictValueIterator(PythonLanguage language, HashingStorageNodes.HashingStorageIterator iterator, HashingStorage hashingStorage, int initialSize) { return new PDictValueIterator(PythonBuiltinClassType.PDictValueIterator, PythonBuiltinClassType.PDictValueIterator.getInstanceShape(language), iterator, hashingStorage, initialSize); } + public static PDictValueIterator createDictReverseValueIterator(PythonLanguage language, HashingStorageNodes.HashingStorageIterator iterator, HashingStorage hashingStorage, int initialSize) { + return new PDictValueIterator(PythonBuiltinClassType.PDictReverseValueIterator, PythonBuiltinClassType.PDictReverseValueIterator.getInstanceShape(language), iterator, hashingStorage, + initialSize); + } + public static Object createSentinelIterator(PythonLanguage language, Object callable, Object sentinel) { return new PSentinelIterator(PythonBuiltinClassType.PSentinelIterator, PythonBuiltinClassType.PSentinelIterator.getInstanceShape(language), callable, sentinel); }