diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_builtin.py b/graalpython/com.oracle.graal.python.test/src/tests/test_builtin.py index 4feae1418b..ce3cbe295b 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_builtin.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_builtin.py @@ -18,6 +18,13 @@ def __index__(self): return self.value class BuiltinTest(unittest.TestCase): + def test_build_class_checks_body_arguments(self): + def body(required): + pass + + with self.assertRaises(TypeError): + __build_class__(body, "", "") + def test_bin(self): self.assertEqual(bin(0), '0b0') self.assertEqual(bin(1), '0b1') 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 e8d4c4322f..cc226c7679 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 @@ -1,4 +1,4 @@ -# Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 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 @@ -39,9 +39,13 @@ import unittest import csv +import re from tempfile import TemporaryFile class TestUnicodeCharacters(unittest.TestCase): + def test_builtin_type_as_dialect(self): + self.assertIsInstance(csv.reader(re.ASCII, int), type(csv.reader([]))) + def test_read_utf_32_delimiter(self): test_data = ['a\U0001F642b'] reader = csv.reader(test_data, delimiter="\U0001F642") @@ -77,4 +81,3 @@ def test_write_utf32_field_with_utf32_delimiter(self): - diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_datetime.py b/graalpython/com.oracle.graal.python.test/src/tests/test_datetime.py index baf8398fa7..ecbc5dec1d 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_datetime.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_datetime.py @@ -249,6 +249,21 @@ def test_fromtimestamp(self): with self.assertRaisesRegex(OverflowError, "timestamp out of range for platform time_t"): datetime.date.fromtimestamp(1e200) + def test_fromtimestamp_before_importing_time(self): + proc = subprocess.run( + [ + sys.executable, + "-c", + "import datetime\n" + "datetime.date.fromtimestamp(0)\n" + "datetime.datetime.fromtimestamp(0)\n", + ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + self.assertEqual(proc.returncode, 0, proc.stderr) + def test_fromisocalendar(self): with self.assertRaisesRegex(ValueError, "Year is out of range: -1"): diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_hashlib.py b/graalpython/com.oracle.graal.python.test/src/tests/test_hashlib.py index 263d02e6d2..cf4f60c5df 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_hashlib.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_hashlib.py @@ -44,6 +44,11 @@ class HashlibTest(unittest.TestCase): + def test_new_validates_type(self): + self.assertRaises(TypeError, hashlib.sha3_224.__new__) + self.assertRaises(TypeError, hashlib.sha3_224.__new__, '') + self.assertRaises(TypeError, hashlib.sha3_224.__new__, int) + def test_messagedigest_update_after_digest(self): sha1 = hashlib.sha1() sha1.update(b'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 08a212a64d..5941b6668d 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 @@ -295,6 +295,11 @@ def test_invalid_return_statement(): assert_raise_syntax_error("return 10", "'return' outside function") assert_raise_syntax_error("class A: return 10\n", "'return' outside function") + +def test_top_level_async_with(): + assert_raise_syntax_error("async with _:\n pass", "'async with' outside async function") + + def test_outside_of_loop_errors(): assert_raise_syntax_error("break", "'break' outside loop") # TODO: parser gives invalid syntax for this one, but should be: "'break' outside loop" diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_re.py b/graalpython/com.oracle.graal.python.test/src/tests/test_re.py index 807e3a493f..5789ed3651 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_re.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_re.py @@ -1411,6 +1411,9 @@ def test_flags(self): self.assertEqual(re.compile('(?u)').flags, re.UNICODE) self.assertEqual(re.compile('(?x)').flags, re.VERBOSE | re.UNICODE) + with self.assertRaisesRegex(ValueError, "cannot use LOCALE flag with a str pattern"): + re.compile('A', 9999) + def test_groups(self): # returns number of capturing groups in the pattern diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_signal.py b/graalpython/com.oracle.graal.python.test/src/tests/test_signal.py index a3fdde3fa6..4a0788fa73 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_signal.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_signal.py @@ -43,6 +43,10 @@ class SignalTests(unittest.TestCase): + def test_getsignal_rejects_invalid_number(self): + with self.assertRaisesRegex(ValueError, "signal number out of range"): + signal.getsignal(0) + def test_args_validation(self): try: import _signal diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_time.py b/graalpython/com.oracle.graal.python.test/src/tests/test_time.py index 77475f56bf..73e1e2415f 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_time.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_time.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018, 2025, 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,6 +57,11 @@ def test_sleep_sec(): assert time.time() - start > 1 +def test_mktime_requires_tuple(): + with unittest.TestCase().assertRaisesRegex(TypeError, "Tuple or struct_time argument required"): + time.mktime(sum) + + def test_monotonic(): times = [time.monotonic() for _ in range(100)] for t1, t2 in zip(times[:-1], times[1:]): 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 53dbff0c99..51ac7a8a55 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 @@ -222,6 +222,7 @@ import com.oracle.graal.python.nodes.SpecialAttributeNames; import com.oracle.graal.python.nodes.SpecialMethodNames; import com.oracle.graal.python.nodes.StringLiterals; +import com.oracle.graal.python.nodes.argument.CreateArgumentsNode; import com.oracle.graal.python.nodes.argument.ReadArgumentNode; import com.oracle.graal.python.nodes.attributes.GetFixedAttributeNode; import com.oracle.graal.python.nodes.attributes.ReadAttributeFromModuleNode; @@ -2265,6 +2266,7 @@ protected Object doItNonFunction(VirtualFrame frame, Object function, Object[] a @Cached PyMappingCheckNode pyMappingCheckNode, @Cached CallNode callPrep, @Cached CallNode callType, + @Cached CreateArgumentsNode createArguments, @Cached CallDispatchers.FunctionCachedInvokeNode invokeBody, @Cached UpdateBasesNode update, @Cached PyObjectSetItem setOrigBases, @@ -2356,9 +2358,11 @@ class InitializeBuildClass { if (!pyMappingCheckNode.execute(inliningTarget, ns)) { throw raiseNoMapping(init.isClass, init.meta, ns); } - Object[] bodyArguments = PArguments.create(0); + PFunction bodyFunction = (PFunction) function; + Object[] bodyArguments = createArguments.execute(inliningTarget, bodyFunction, PythonUtils.EMPTY_OBJECT_ARRAY, PKeyword.EMPTY_KEYWORDS, + bodyFunction.getCode().getSignature(), null, null, bodyFunction.getDefaults(), bodyFunction.getKwDefaults(), false); PArguments.setSpecialArgument(bodyArguments, ns); - invokeBody.execute(frame, inliningTarget, (PFunction) function, bodyArguments); + invokeBody.execute(frame, inliningTarget, bodyFunction, bodyArguments); if (init.bases != basesArray) { setOrigBases.execute(frame, inliningTarget, ns, SpecialAttributeNames.T___ORIG_BASES__, PFactory.createTuple(language, basesArray)); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java index 270af53e82..16dad2ca2a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SignalModuleBuiltins.java @@ -112,6 +112,7 @@ public final class SignalModuleBuiltins extends PythonBuiltins { private static final int ITIMER_VIRTUAL = 1; private static final int ITIMER_PROF = 2; private static final TruffleString T_ITIMER_ERROR = tsLiteral("ItimerError"); + private static final TruffleString T_SIGNAL_NUMBER_OUT_OF_RANGE = tsLiteral("signal number out of range"); public static final String J_DEFAULT_INT_HANDLER = "default_int_handler"; public static final TruffleString T_DEFAULT_INT_HANDLER = tsLiteral(J_DEFAULT_INT_HANDLER); @@ -336,7 +337,11 @@ private static Object handlerToPython(SignalHandler handler, int signum, ModuleD abstract static class GetSignalNode extends PythonBinaryClinicBuiltinNode { @Specialization @TruffleBoundary - static Object getsignal(PythonModule mod, int signum) { + static Object getsignal(PythonModule mod, int signum, + @Bind Node inliningTarget) { + if (!Signals.isValidSignal(signum)) { + throw PRaiseNode.raiseStatic(inliningTarget, PythonErrorType.ValueError, T_SIGNAL_NUMBER_OUT_OF_RANGE); + } ModuleData data = mod.getModuleState(ModuleData.class); return handlerToPython(Signals.getCurrentSignalHandler(signum), signum, data); } @@ -616,7 +621,11 @@ public void handle(sun.misc.Signal arg0) { } static String signalNumberToName(int signum) { - return signum > SIGMAX ? "INVALID SIGNAL" : SIGNAL_NAMES[signum]; + return isValidSignal(signum) ? SIGNAL_NAMES[signum] : "INVALID SIGNAL"; + } + + static boolean isValidSignal(int signum) { + return signum > 0 && signum <= SIGMAX && SIGNAL_NAMES[signum] != null; } @TruffleBoundary diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TimeModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TimeModuleBuiltins.java index 0b6665fb07..633d7fdf6a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TimeModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TimeModuleBuiltins.java @@ -198,9 +198,7 @@ private static void setGlobalTimeZone(PythonModule timeModule, PythonLanguage la timeZone = TimeZone.getTimeZone(tzEnv); } - // save in the module state - ModuleState moduleState = timeModule.getModuleState(ModuleState.class); - moduleState.currentZoneId = timeZone.toZoneId(); + context.setCurrentZoneId(timeZone.toZoneId()); // update time module attributes TruffleString noDaylightSavingZone = toTruffleStringUncached(timeZone.getDisplayName(false, TimeZone.SHORT)); @@ -217,20 +215,6 @@ public static double timeSeconds() { return System.currentTimeMillis() / 1000.0; } - /** - * Return current time zone (that can be changed with time.tzset()). The only correct way to get - * it. - */ - @TruffleBoundary - public static TimeZone getGlobalTimeZone(PythonContext context) { - PythonModule timeModule = context.lookupBuiltinModule(T_TIME); - - ModuleState moduleState = timeModule.getModuleState(ModuleState.class); - ZoneId zoneId = moduleState.currentZoneId; - - return TimeZone.getTimeZone(zoneId); - } - private static final int TM_YEAR = 0; /* year */ private static final int TM_MON = 1; /* month */ private static final int TM_MDAY = 2; /* day of the month */ @@ -368,12 +352,12 @@ Object tzset(PythonModule self) { public abstract static class PythonLocalTimeNode extends PythonBinaryBuiltinNode { @Specialization - static PTuple localtime(VirtualFrame frame, PythonModule module, Object seconds, + static PTuple localtime(VirtualFrame frame, @SuppressWarnings("unused") PythonModule module, Object seconds, @Bind Node inliningTarget, + @Bind PythonContext context, @Cached ToLongTime toLongTime, @Bind PythonLanguage language) { - ModuleState moduleState = module.getModuleState(ModuleState.class); - return PFactory.createStructSeq(language, STRUCT_TIME_DESC, getTimeStruct(moduleState.currentZoneId, toLongTime.execute(frame, inliningTarget, seconds))); + return PFactory.createStructSeq(language, STRUCT_TIME_DESC, getTimeStruct(context.getCurrentZoneId(), toLongTime.execute(frame, inliningTarget, seconds))); } } @@ -982,19 +966,21 @@ private static TimeZone getTimeZone(ZoneId currentZoneId) { } @Specialization - static TruffleString formatTime(PythonModule module, TruffleString format, @SuppressWarnings("unused") PNone time, + static TruffleString formatTime(@SuppressWarnings("unused") PythonModule module, TruffleString format, @SuppressWarnings("unused") PNone time, @Bind Node inliningTarget, + @Bind PythonContext context, @Shared("byteIndexOfCp") @Cached TruffleString.ByteIndexOfCodePointNode byteIndexOfCodePointNode, @Shared("ts2js") @Cached ToJavaStringNode toJavaStringNode, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Exclusive @Cached PRaiseNode raiseNode) { - ModuleState moduleState = module.getModuleState(ModuleState.class); - return format(toJavaStringNode.execute(format), getIntLocalTimeStruct(moduleState.currentZoneId, (long) timeSeconds()), getTimeZone(moduleState.currentZoneId), fromJavaStringNode); + ZoneId currentZoneId = context.getCurrentZoneId(); + return format(toJavaStringNode.execute(format), getIntLocalTimeStruct(currentZoneId, (long) timeSeconds()), getTimeZone(currentZoneId), fromJavaStringNode); } @Specialization(guards = "tupleCheckNode.execute(inliningTarget, time)", limit = "1") - static TruffleString formatTime(VirtualFrame frame, PythonModule module, TruffleString format, Object time, + static TruffleString formatTime(VirtualFrame frame, @SuppressWarnings("unused") PythonModule module, TruffleString format, Object time, @Bind Node inliningTarget, + @Bind PythonContext context, @SuppressWarnings("unused") @Cached PyTupleCheckNode tupleCheckNode, @Cached GetTupleStorage getTupleStorage, @Cached SequenceStorageNodes.GetInternalObjectArrayNode getArray, @@ -1004,7 +990,7 @@ static TruffleString formatTime(VirtualFrame frame, PythonModule module, Truffle @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode, @Exclusive @Cached PRaiseNode raiseNode) { int[] date = checkStructtime(frame, inliningTarget, getTupleStorage.execute(inliningTarget, time), getArray, asSizeNode, raiseNode); - return format(toJavaStringNode.execute(format), date, getTimeZone(module.getModuleState(ModuleState.class).currentZoneId), fromJavaStringNode); + return format(toJavaStringNode.execute(format), date, getTimeZone(context.getCurrentZoneId()), fromJavaStringNode); } @Specialization @@ -1027,8 +1013,9 @@ abstract static class MkTimeNode extends PythonBinaryBuiltinNode { @ExplodeLoop @Specialization(guards = "tupleCheckNode.execute(inliningTarget, tuple)", limit = "1") - static double mktime(VirtualFrame frame, PythonModule module, Object tuple, + static double mktime(VirtualFrame frame, @SuppressWarnings("unused") PythonModule module, Object tuple, @Bind Node inliningTarget, + @Bind PythonContext context, @SuppressWarnings("unused") @Cached PyTupleCheckNode tupleCheckNode, @Cached GetTupleStorage getTupleStorage, @Cached PyNumberAsSizeNode asSizeNode, @@ -1044,8 +1031,14 @@ static double mktime(VirtualFrame frame, PythonModule module, Object tuple, for (int i = 0; i < ELEMENT_COUNT; i++) { integers[i] = asSizeNode.executeExact(frame, inliningTarget, items[i]); } - ModuleState moduleState = module.getModuleState(ModuleState.class); - return op(moduleState.currentZoneId, integers); + return op(context.getCurrentZoneId(), integers); + } + + @Fallback + @SuppressWarnings("unused") + static Object mktime(Object module, Object tuple, + @Bind Node inliningTarget) { + throw PRaiseNode.raiseStatic(inliningTarget, TypeError, ErrorMessages.TUPLE_OR_STRUCT_TIME_ARG_REQUIRED); } @TruffleBoundary @@ -1061,12 +1054,12 @@ private static long op(ZoneId timeZone, int[] integers) { public abstract static class CTimeNode extends PythonBinaryBuiltinNode { @Specialization - public static TruffleString localtime(VirtualFrame frame, PythonModule module, Object seconds, + public static TruffleString localtime(VirtualFrame frame, @SuppressWarnings("unused") PythonModule module, Object seconds, @Bind Node inliningTarget, + @Bind PythonContext context, @Cached ToLongTime toLongTime, @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { - ModuleState moduleState = module.getModuleState(ModuleState.class); - int[] tm = getIntLocalTimeStruct(moduleState.currentZoneId, toLongTime.execute(frame, inliningTarget, seconds)); + int[] tm = getIntLocalTimeStruct(context.getCurrentZoneId(), toLongTime.execute(frame, inliningTarget, seconds)); return format(tm, fromJavaStringNode); } @@ -1090,10 +1083,10 @@ public abstract static class ASCTimeNode extends PythonBinaryBuiltinNode { }; @Specialization - static TruffleString localtime(PythonModule module, @SuppressWarnings("unused") PNone time, + static TruffleString localtime(@SuppressWarnings("unused") PythonModule module, @SuppressWarnings("unused") PNone time, + @Bind PythonContext context, @Shared("js2ts") @Cached TruffleString.FromJavaStringNode fromJavaStringNode) { - ModuleState moduleState = module.getModuleState(ModuleState.class); - return format(getIntLocalTimeStruct(moduleState.currentZoneId, (long) timeSeconds()), fromJavaStringNode); + return format(getIntLocalTimeStruct(context.getCurrentZoneId(), (long) timeSeconds()), fromJavaStringNode); } @Specialization(guards = "tupleCheckNode.execute(inliningTarget, time)", limit = "1") @@ -1216,7 +1209,6 @@ public Object strptime(VirtualFrame frame, TruffleString dataString, TruffleStri } private static final class ModuleState { - ZoneId currentZoneId; long timeSlept; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/csv/CSVDialectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/csv/CSVDialectBuiltins.java index 2438bab62c..cfacafe30a 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/csv/CSVDialectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/csv/CSVDialectBuiltins.java @@ -67,7 +67,6 @@ import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.module.PythonModule; import com.oracle.graal.python.builtins.objects.str.PString; -import com.oracle.graal.python.builtins.objects.type.PythonClass; import com.oracle.graal.python.builtins.objects.type.TpSlots; import com.oracle.graal.python.builtins.objects.type.TypeNodes; import com.oracle.graal.python.lib.PyLongAsIntNode; @@ -199,8 +198,8 @@ static Object doStringWithKeywords(VirtualFrame frame, PythonBuiltinClassType cl quotecharObj, quotingObj, skipinitialspaceObj, strictObj, isTrueNode, pyLongCheckExactNode, pyLongAsIntNode, raiseNode); } - @Specialization - static Object doDialectClassWithKeywords(VirtualFrame frame, PythonBuiltinClassType cls, PythonClass dialectObj, Object delimiterObj, Object doublequoteObj, Object escapecharObj, + @Specialization(guards = "isPythonClass(dialectObj)") + static Object doDialectClassWithKeywords(VirtualFrame frame, PythonBuiltinClassType cls, Object dialectObj, Object delimiterObj, Object doublequoteObj, Object escapecharObj, Object lineterminatorObj, Object quotecharObj, Object quotingObj, Object skipinitialspaceObj, Object strictObj, @Bind Node inliningTarget, @Exclusive @Cached PyObjectLookupAttr getFirstAttributesNode, diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateBuiltins.java index 1c6f83a063..b5ccbc586c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateBuiltins.java @@ -120,6 +120,7 @@ import com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext; import com.oracle.graal.python.runtime.IndirectCallData; import com.oracle.graal.python.runtime.IndirectCallData.BoundaryCallData; +import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.object.PFactory; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Bind; @@ -580,7 +581,7 @@ private static Object fromTimestampBoundary(Object cls, Object timestampObject, throw PRaiseNode.raiseStatic(inliningTarget, OverflowError, ErrorMessages.TIMESTAMP_OUT_OF_RANGE); } - TimeZone timeZone = TimeModuleBuiltins.getGlobalTimeZone(getContext(inliningTarget)); + TimeZone timeZone = PythonContext.get(inliningTarget).getGlobalTimeZone(); ZoneId zoneId = timeZone.toZoneId(); LocalDate localDate = LocalDate.ofInstant(instant, zoneId); return DateNodes.SubclassNewNode.executeUncached(cls, localDate.getYear(), localDate.getMonthValue(), localDate.getDayOfMonth()); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateTimeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateTimeBuiltins.java index ccdaba3ea8..9e64f7a3a1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateTimeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/DateTimeBuiltins.java @@ -1034,12 +1034,13 @@ private static Object fromTimestampBoundary(Object cls, Object timestampObject, if (tzInfo == null) { // convert from UTC to system timezone - TimeZone timeZone = TimeModuleBuiltins.getGlobalTimeZone(getContext(inliningTarget)); + PythonContext context = PythonContext.get(inliningTarget); + TimeZone timeZone = context.getGlobalTimeZone(); ZoneId zoneId = timeZone.toZoneId(); ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, zoneId).plusNanos(microseconds * 1_000); final int fold; - if (isBackwardTransitionDetected(instant, getContext(inliningTarget))) { + if (isBackwardTransitionDetected(instant, context)) { fold = 1; } else { fold = 0; @@ -2002,7 +2003,7 @@ private static Object inTimeZoneBoundary(Object selfObj, Object tzInfo, Node inl // CPython: local_timezone_from_local() private static PTimeZone getSystemTimeZoneAt(LocalDateTime localDateTime, int fold, Node inliningTarget) { - TimeZone timeZone = TimeModuleBuiltins.getGlobalTimeZone(getContext(inliningTarget)); + TimeZone timeZone = PythonContext.get(inliningTarget).getGlobalTimeZone(); ZoneId zoneId = timeZone.toZoneId(); ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId); @@ -2255,7 +2256,7 @@ private static double toTimestampBoundary(Object selfObj, Node inliningTarget, O DateTimeValue self = TemporalValueNodes.GetDateTimeValue.executeUncached(inliningTarget, selfObj); if (tzInfo == null) { // CPython: local_to_seconds() - TimeZone timeZone = TimeModuleBuiltins.getGlobalTimeZone(getContext(inliningTarget)); + TimeZone timeZone = PythonContext.get(inliningTarget).getGlobalTimeZone(); ZoneId zoneId = timeZone.toZoneId(); LocalDateTime localDateTime = self.toLocalDateTime(); @@ -2603,7 +2604,7 @@ private static Object getResultDateTimeType(Object selfObj, Node inliningTarget, */ @TruffleBoundary private static boolean isBackwardTransitionDetected(Instant instant, PythonContext context) { - TimeZone timeZone = TimeModuleBuiltins.getGlobalTimeZone(context); + TimeZone timeZone = context.getGlobalTimeZone(); int offsetMillis = timeZone.getOffset(instant.toEpochMilli()); Instant probe = instant.minusSeconds(MAX_FOLD_SECONDS); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/TRegexCache.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/TRegexCache.java index 3fbf8e949e..cdea7942e4 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/TRegexCache.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/re/TRegexCache.java @@ -125,6 +125,7 @@ public TRegexCache(Node node, Object pattern, int flags) { bufferLib.release(buffer); } } + validateFlags(node, binary, flags); this.pattern = patternStr; this.binary = binary; this.flags = getTRegexFlags(flags); @@ -132,6 +133,24 @@ public TRegexCache(Node node, Object pattern, int flags) { this.localeSensitiveRegexps = this.localeSensitive ? EconomicMap.create() : null; } + private static void validateFlags(Node node, boolean binary, int flags) { + if (binary) { + if ((flags & FLAG_UNICODE) != 0) { + throw PRaiseNode.raiseStatic(node, ValueError, T_VALUE_ERROR_UNICODE_FLAG_BYTES_PATTERN); + } + if ((flags & FLAG_ASCII) != 0 && (flags & FLAG_LOCALE) != 0) { + throw PRaiseNode.raiseStatic(node, ValueError, T_VALUE_ERROR_ASCII_LOCALE_INCOMPATIBLE); + } + } else { + if ((flags & FLAG_LOCALE) != 0) { + throw PRaiseNode.raiseStatic(node, ValueError, T_VALUE_ERROR_LOCALE_FLAG_STR_PATTERN); + } + if ((flags & FLAG_ASCII) != 0 && (flags & FLAG_UNICODE) != 0) { + throw PRaiseNode.raiseStatic(node, ValueError, T_VALUE_ERROR_ASCII_UNICODE_INCOMPATIBLE); + } + } + } + public boolean isBinary() { return binary; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java index 994b0f3b82..94a8219899 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java @@ -137,11 +137,15 @@ import com.oracle.graal.python.builtins.objects.str.PString; import com.oracle.graal.python.builtins.objects.tuple.PTuple; import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; +import com.oracle.graal.python.builtins.objects.type.TpSlots.GetCachedTpSlotsNode; import com.oracle.graal.python.builtins.objects.type.TypeFlags; +import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetBaseClassNode; import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetTypeFlagsNode; import com.oracle.graal.python.builtins.objects.type.TypeNodes.IsSameTypeNode; +import com.oracle.graal.python.builtins.objects.type.TypeNodes.IsTypeNode; import com.oracle.graal.python.builtins.objects.type.slots.TpSlot; import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotNative; +import com.oracle.graal.python.builtins.objects.type.slots.TpSlot.TpSlotPythonSingle; import com.oracle.graal.python.lib.PyNumberAsSizeNode; import com.oracle.graal.python.lib.RichCmpOp; import com.oracle.graal.python.nodes.ErrorMessages; @@ -151,6 +155,7 @@ import com.oracle.graal.python.nodes.argument.ReadIndexedArgumentNode; import com.oracle.graal.python.nodes.argument.ReadVarArgsNode; import com.oracle.graal.python.nodes.argument.ReadVarKeywordsNode; +import com.oracle.graal.python.nodes.classes.IsSubtypeNode; import com.oracle.graal.python.nodes.object.IsForeignObjectNode; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.runtime.ExecutionContext.CalleeContext; @@ -188,6 +193,7 @@ import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; +import com.oracle.truffle.api.profiles.InlinedLoopConditionProfile; import com.oracle.truffle.api.strings.TruffleString; public abstract class ExternalFunctionNodes { @@ -860,9 +866,59 @@ public Signature getSignature() { } } + @GenerateInline(false) + abstract static class ValidateNewArgumentNode extends Node { + abstract void execute(Object owner, Object cls); + + @Specialization + static void check(Object owner, Object cls, + @Bind Node inliningTarget, + @Cached IsTypeNode isTypeNode, + @Cached IsSubtypeNode isSubtypeNode, + @Cached GetCachedTpSlotsNode getSlotsCls, + @Cached GetCachedTpSlotsNode getSlotsOwner, + @Cached GetCachedTpSlotsNode getSlotsBase1, + @Cached GetCachedTpSlotsNode getSlotsBase2, + @Cached GetBaseClassNode getBase1, + @Cached GetBaseClassNode getBase2, + @Cached InlinedLoopConditionProfile loopProfile, + @Cached PRaiseNode raiseNotType, + @Cached PRaiseNode raiseNotSubytpe, + @Cached PRaiseNode raiseNotSafe) { + if (!isTypeNode.execute(inliningTarget, cls)) { + throw raiseNotType.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.NEW_X_ISNT_TYPE_OBJ, owner, cls); + } + if (!isSubtypeNode.execute(cls, owner)) { + throw raiseNotSubytpe.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.IS_NOT_SUBTYPE_OF, owner, cls, cls, owner); + } + Object staticBase = cls; + TpSlot staticBaseNew = getSlotsCls.execute(inliningTarget, staticBase).tp_new(); + if (staticBaseNew instanceof TpSlotPythonSingle) { + staticBase = getBase1.execute(inliningTarget, staticBase); + staticBaseNew = getSlotsBase1.execute(inliningTarget, staticBase).tp_new(); + while (loopProfile.profile(inliningTarget, staticBaseNew instanceof TpSlotPythonSingle)) { + staticBase = getBase2.execute(inliningTarget, staticBase); + staticBaseNew = getSlotsBase2.execute(inliningTarget, staticBase).tp_new(); + } + } + TpSlot ownerNew = getSlotsOwner.execute(inliningTarget, owner).tp_new(); + boolean sameNew = staticBaseNew == ownerNew || staticBaseNew instanceof TpSlotNative staticBaseNative && ownerNew instanceof TpSlotNative ownerNative && staticBaseNative.isSameCallable( + ownerNative); + if (!sameNew) { + if (staticBaseNew == null) { + throw raiseNotSafe.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.CANNOT_CREATE_N_INSTANCES, cls); + } + throw raiseNotSafe.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.NEW_IS_NOT_SAFE_USE_ELSE, owner, cls, cls); + } + } + } + @CApiWrapperDescriptor(value = NEW) abstract static class MethNewRoot extends MethNewOrCallRoot { + @Child private ValidateNewArgumentNode validateNewArgumentNode; + private final BranchProfile noArgumentsProfile = BranchProfile.create(); + public MethNewRoot(PythonLanguage language, TruffleString name, PExternalFunctionWrapper provider) { super(language, name, provider); } @@ -875,8 +931,19 @@ protected Object readArgumentsAndInvokeExternalFunction(VirtualFrame frame, Nati PythonContext context = PythonContext.get(this); Object[] args = readVarargsNode.execute(frame); - // TODO checks + Object owner = readSelf(frame); + if (args.length == 0) { + noArgumentsProfile.enter(); + throw PRaiseNode.raiseStatic(this, PythonBuiltinClassType.TypeError, ErrorMessages.NEW_NOT_ENOUGH_ARGUMENTS, owner); + } Object self = args[0]; + if (self != owner) { + if (validateNewArgumentNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + validateNewArgumentNode = insert(ExternalFunctionNodesFactory.ValidateNewArgumentNodeGen.create()); + } + validateNewArgumentNode.execute(owner, self); + } args = PythonUtils.arrayCopyOfRange(args, 1, args.length); PTuple managedArgsTuple; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java index f8c12fabef..4f6ef210db 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/compiler/bytecode_dsl/RootNodeCompiler.java @@ -4054,11 +4054,8 @@ private void emitAsyncFor(StackValue iterStackValue, ExprTy target, StmtTy[] @Override public Void visit(StmtTy.AsyncWith node) { - if (!scope.isFunction()) { - ctx.errorCallback.onError(ErrorType.Syntax, currentLocation, "'async with' outside function"); - } if (scopeType != CompilationScope.AsyncFunction && scopeType != CompilationScope.Comprehension) { - ctx.errorCallback.onError(ErrorType.Syntax, currentLocation, "'async with' outside async function"); + ctx.errorCallback.onError(ErrorType.Syntax, node.getSourceRange(), "'async with' outside async function"); } beginStatement(node, b); visitWithRecurse(node.items, 0, node.body, true); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java index 2e73793ff5..a075489c78 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java @@ -459,7 +459,7 @@ public abstract class ErrorMessages { public static final TruffleString INIT_TAKES_ONE_ARG_OBJECT = tsLiteral("object.__init__() takes exactly one argument (the instance to initialize)"); public static final TruffleString INVALID_TYPE_FOR_S = tsLiteral("Invalid type for %s"); public static final TruffleString INVALID_VALUE_NAN = tsLiteral("Invalid value NaN (not a number)"); - public static final TruffleString IS_NOT_SUBTYPE_OF = tsLiteral("%s.__new__(%N): %N is not a subtype of %s"); + public static final TruffleString IS_NOT_SUBTYPE_OF = tsLiteral("%N.__new__(%N): %N is not a subtype of %N"); public static final TruffleString IS_NOT_TYPE_OBJ = tsLiteral("%s is not a type object (%p)"); public static final TruffleString MAX_FACTOR_MUST_BE_AT_LEAST_ONE = tsLiteral("'max_factor' must be at least 1.0"); public static final TruffleString N_MUST_BE_AT_LEAST_ONE = tsLiteral("n must be at least one"); @@ -1346,8 +1346,9 @@ public abstract class ErrorMessages { public static final TruffleString BYTE_ARRAY_TOO_LONG_TO_CONVERT_TO_INT = tsLiteral("byte array too long to convert to int"); public static final TruffleString INVALID_SEQ_ITEM = tsLiteral("sequence item %d: expected str instance, %p found"); - public static final TruffleString NEW_X_ISNT_TYPE_OBJ = tsLiteral("%s.__new__(X): X is not a type object (%p)"); - public static final TruffleString NEW_IS_NOT_SAFE_USE_ELSE = tsLiteral("%s.__new__(%N) is not safe, use %N.__new__()"); + public static final TruffleString NEW_NOT_ENOUGH_ARGUMENTS = tsLiteral("%N.__new__(): not enough arguments"); + public static final TruffleString NEW_X_ISNT_TYPE_OBJ = tsLiteral("%N.__new__(X): X is not a type object (%p)"); + public static final TruffleString NEW_IS_NOT_SAFE_USE_ELSE = tsLiteral("%N.__new__(%N) is not safe, use %N.__new__()"); public static final TruffleString INSTANCE_OF_CONTEXTVAR_EXPECTED = tsLiteral("an instance of ContextVar was expected"); public static final TruffleString INSTANCE_OF_TOKEN_EXPECTED = tsLiteral("expected an instance of Token, got %s"); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/builtins/WrapTpNew.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/builtins/WrapTpNew.java index 23aac69f7d..0459328442 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/builtins/WrapTpNew.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/function/builtins/WrapTpNew.java @@ -91,10 +91,10 @@ static void check(PythonBuiltinClassType owner, Object cls, @Cached PRaiseNode raiseNotSubytpe, @Cached PRaiseNode raiseNotSafe) { if (!isTypeNode.execute(inliningTarget, cls)) { - throw raiseNotType.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.NEW_X_ISNT_TYPE_OBJ, owner.getName(), cls); + throw raiseNotType.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.NEW_X_ISNT_TYPE_OBJ, owner, cls); } if (!isSubtypeNode.execute(cls, owner)) { - throw raiseNotSubytpe.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.IS_NOT_SUBTYPE_OF, owner.getName(), cls, cls, owner.getName()); + throw raiseNotSubytpe.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.IS_NOT_SUBTYPE_OF, owner, cls, cls, owner); } /* * CPython comment: Check that the use doesn't do something silly and unsafe like @@ -116,7 +116,7 @@ static void check(PythonBuiltinClassType owner, Object cls, if (staticBaseNew == null) { throw raiseNotSafe.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.CANNOT_CREATE_N_INSTANCES, cls); } - throw raiseNotSafe.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.NEW_IS_NOT_SAFE_USE_ELSE, owner.getName(), cls, cls); + throw raiseNotSafe.raise(inliningTarget, PythonBuiltinClassType.TypeError, ErrorMessages.NEW_IS_NOT_SAFE_USE_ELSE, owner, cls, cls); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java index df0b4c4c53..6844ae061c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java @@ -75,6 +75,7 @@ import java.security.ProviderException; import java.security.SecureRandom; import java.text.MessageFormat; +import java.time.ZoneId; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashMap; @@ -84,6 +85,7 @@ import java.util.Map; import java.util.Optional; import java.util.Random; +import java.util.TimeZone; import java.util.WeakHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -821,6 +823,9 @@ public Thread getOwner() { /** State for the locale module, the default locale can be passed as an option */ private PythonLocale currentLocale; + /** The current time zone, which can be changed by {@code time.tzset()}. */ + private ZoneId currentZoneId; + @CompilationFinal(dimensions = 1) private Object[] optionValues; @CompilationFinal private long perfCounterStart = System.nanoTime(); @@ -1165,6 +1170,22 @@ public PythonLocale getCurrentLocale() { return currentLocale; } + public ZoneId getCurrentZoneId() { + return currentZoneId; + } + + public void setCurrentZoneId(ZoneId currentZoneId) { + this.currentZoneId = currentZoneId; + } + + /** + * Return the current time zone, which can be changed by {@code time.tzset()}. + */ + @TruffleBoundary + public TimeZone getGlobalTimeZone() { + return TimeZone.getTimeZone(currentZoneId); + } + public boolean isInitialized() { return isInitialized; } @@ -1334,6 +1355,7 @@ private void setupRuntimeInformation(boolean isPatching) { initializeHashSecret(); } initializeLocale(); + currentZoneId = env.getTimeZone(); setIntMaxStrDigits(getOption(PythonOptions.IntMaxStrDigits)); if (!PythonImageBuildOptions.WITHOUT_COMPRESSION_LIBRARIES) { nativeZlib = NativeZlibSupport.createNative(this, "");