From 480aa8068959a291a3e7941db97266ff386b2358 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Mon, 22 Jun 2026 16:41:37 +0200 Subject: [PATCH 1/5] Implement sys._getframemodulename Fixes #976 --- .../src/tests/test_frame_tests.py | 48 +++++++++++++++++++ .../builtins/modules/SysModuleBuiltins.java | 35 ++++++++++++++ .../python/builtins/objects/frame/PFrame.java | 4 ++ 3 files changed, 87 insertions(+) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_frame_tests.py b/graalpython/com.oracle.graal.python.test/src/tests/test_frame_tests.py index 8551270f30..37c649d0ae 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_frame_tests.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_frame_tests.py @@ -184,6 +184,54 @@ def test_code(): assert code.co_name == test_code.__code__.co_name +def test_getframemodulename(): + assert sys._getframemodulename() == __name__ + assert sys._getframemodulename(0) == __name__ + assert sys._getframemodulename(-1) == __name__ + assert sys._getframemodulename(10**6) is None + + namespace = {"sys": sys, "__name__": "test_getframemodulename_custom"} + exec("def get_module_name(depth=0): return sys._getframemodulename(depth)", namespace) + assert namespace["get_module_name"]() == "test_getframemodulename_custom" + assert namespace["get_module_name"](1) == __name__ + + +def test_getframemodulename_uses_function_module(): + def get_module_name(): + return sys._getframemodulename() + + old_module = get_module_name.__module__ + try: + get_module_name.__module__ = "test_getframemodulename_function_module" + assert get_module_name() == "test_getframemodulename_function_module" + finally: + get_module_name.__module__ = old_module + + +def test_getframemodulename_missing_name(): + namespace = {"sys": sys} + exec("def get_module_name(): return sys._getframemodulename()", namespace) + assert namespace["get_module_name"]() is None + + +def test_getframemodulename_non_string_name(): + namespace = {"sys": sys, "__name__": 42} + exec("def get_module_name(): return sys._getframemodulename()", namespace) + assert namespace["get_module_name"]() == 42 + + +def test_getframemodulename_audit(): + seen = [] + + def hook(event, args): + if event == "sys._getframemodulename": + seen.append(args) + + sys.addaudithook(hook) + assert sys._getframemodulename() == __name__ + assert seen[-1] == (0,) + + def test_builtins(): assert print == sys._getframe().f_builtins["print"] diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java index bbd4d5ee00..4add7cf6f9 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java @@ -162,6 +162,7 @@ import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.PythonBuiltins; import com.oracle.graal.python.builtins.modules.SysModuleBuiltinsClinicProviders.GetFrameNodeClinicProviderGen; +import com.oracle.graal.python.builtins.modules.SysModuleBuiltinsClinicProviders.GetFrameModuleNameNodeClinicProviderGen; import com.oracle.graal.python.builtins.modules.SysModuleBuiltinsClinicProviders.SetDlopenFlagsClinicProviderGen; import com.oracle.graal.python.builtins.modules.io.BufferedReaderBuiltins; import com.oracle.graal.python.builtins.modules.io.BufferedWriterBuiltins; @@ -186,6 +187,7 @@ import com.oracle.graal.python.builtins.objects.exception.PBaseExceptionGroup; import com.oracle.graal.python.builtins.objects.frame.PFrame; import com.oracle.graal.python.builtins.objects.function.PArguments; +import com.oracle.graal.python.builtins.objects.function.PFunction; import com.oracle.graal.python.builtins.objects.function.PKeyword; import com.oracle.graal.python.builtins.objects.ints.PInt; import com.oracle.graal.python.builtins.objects.iterator.IteratorNodes; @@ -897,6 +899,39 @@ static PFrame counted(VirtualFrame frame, int depth, } } + @Builtin(name = "_getframemodulename", parameterNames = "depth", minNumOfPositionalArgs = 0, needsFrame = true, callerFlags = CallerFlags.NEEDS_PFRAME) + @ArgumentClinic(name = "depth", defaultValue = "0", conversion = ClinicConversion.Int) + @GenerateNodeFactory + public abstract static class GetFrameModuleNameNode extends PythonUnaryClinicBuiltinNode { + private static final TruffleString T_SYS_GET_FRAME_MODULE_NAME = tsLiteral("sys._getframemodulename"); + + @Override + protected ArgumentClinicProvider getArgumentClinic() { + return GetFrameModuleNameNodeClinicProviderGen.INSTANCE; + } + + @Specialization + static Object counted(VirtualFrame frame, int depth, + @Bind Node inliningTarget, + @Cached AuditNode auditNode, + @Cached ReadFrameNode readFrameNode, + @Cached PyObjectLookupAttr lookupAttrNode) { + auditNode.audit(frame, inliningTarget, T_SYS_GET_FRAME_MODULE_NAME, depth); + int frameDepth = Math.max(depth, 0); + PFrame requested = readFrameNode.getFrameForReference(frame, PArguments.getCurrentFrameInfo(frame), ReadFrameNode.AllPythonFramesSelector.INSTANCE, frameDepth, 0); + if (requested == null) { + return PNone.NONE; + } + + PFunction function = requested.getFunction(); + if (function == null) { + return PNone.NONE; + } + Object moduleName = lookupAttrNode.execute(frame, inliningTarget, function, T___MODULE__); + return moduleName != PNone.NO_VALUE ? moduleName : PNone.NONE; + } + } + @Builtin(name = "_current_frames") @GenerateNodeFactory abstract static class CurrentFrames extends PythonBuiltinNode { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java index f3fb8cc9ac..bc0eff8e44 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java @@ -359,6 +359,10 @@ public RootCallTarget getTarget() { return getCode().getRootCallTarget(); } + public PFunction getFunction() { + return function; + } + public PCode getCode() { if (code == null && function != null) { code = function.getCode(); From bb707f9a3494a67d4121f276c31f9c2bbabae9eb Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Mon, 22 Jun 2026 16:42:17 +0200 Subject: [PATCH 2/5] Hide launcher frame from Python frame selection --- .../oracle/graal/python/shell/GraalPythonMain.java | 2 +- .../src/tests/unittest_tags/test_sys.txt | 1 + .../graal/python/nodes/frame/ReadFrameNode.java | 11 ++++++++++- .../graal/python/runtime/PythonSourceOptions.java | 3 +++ .../modules/standalone/resources/Py2BinLauncher.java | 8 ++++---- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java b/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java index fb3c33a6fe..76798264ac 100644 --- a/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java +++ b/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java @@ -1190,7 +1190,7 @@ private void evalNonInteractive(Context context, ConsoleHandler consoleHandler) src = Source.newBuilder(getLanguageId(), commandString, "").build(); } else { // the path is passed through a context option, may be empty when running from stdin - src = Source.newBuilder(getLanguageId(), "__graalpython__.run_path()", "").internal(true).build(); + src = Source.newBuilder(getLanguageId(), "__graalpython__.run_path()", "").internal(true).option("python.NoPythonFrame", "true").build(); } context.eval(src); } diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_sys.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_sys.txt index 0703917933..4a98d588e9 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_sys.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_sys.txt @@ -19,6 +19,7 @@ test.test_sys.SysModuleTest.test_exit @ darwin-arm64,linux-aarch64,linux-aarch64 test.test_sys.SysModuleTest.test_getdefaultencoding @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_sys.SysModuleTest.test_getfilesystemencoding @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_sys.SysModuleTest.test_getframe @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github +test.test_sys.SysModuleTest.test_getframemodulename @ linux-x86_64 test.test_sys.SysModuleTest.test_getrecursionlimit @ darwin-arm64,linux-aarch64,linux-aarch64-github,linux-x86_64,linux-x86_64-github,win32-AMD64,win32-AMD64-github test.test_sys.SysModuleTest.test_getwindowsversion @ win32-AMD64,win32-AMD64-github test.test_sys.SysModuleTest.test_implementation @ 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/nodes/frame/ReadFrameNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadFrameNode.java index 93f83cec88..be5ad0478d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadFrameNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/frame/ReadFrameNode.java @@ -64,6 +64,7 @@ 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.PythonSourceOptions; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; @@ -86,6 +87,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.profiles.InlinedBranchProfile; +import com.oracle.truffle.api.source.Source; @GenerateUncached @GenerateInline(false) @@ -111,7 +113,14 @@ public static class AllPythonFramesSelector implements FrameSelector { @Override public boolean skip(RootNode rootNode) { - return PBytecodeDSLRootNode.cast(rootNode) == null; + PBytecodeDSLRootNode bytecodeDSLRootNode = PBytecodeDSLRootNode.cast(rootNode); + return bytecodeDSLRootNode == null || hasNoPythonFrame(bytecodeDSLRootNode); + } + + @TruffleBoundary + private static boolean hasNoPythonFrame(PBytecodeDSLRootNode rootNode) { + Source source = rootNode.getSource(); + return source != null && source.getOptions(PythonLanguage.get(rootNode)).get(PythonSourceOptions.NoPythonFrame); } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonSourceOptions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonSourceOptions.java index d031d6762a..249f313d5e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonSourceOptions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonSourceOptions.java @@ -65,5 +65,8 @@ private PythonSourceOptions() { @Option(category = OptionCategory.USER, stability = OptionStability.STABLE, help = "Run this source with a fresh globals dictionary instead of the main module globals") // public static final OptionKey NewGlobals = new OptionKey<>(false); + @Option(category = OptionCategory.INTERNAL, stability = OptionStability.STABLE, help = "Do not expose this source as a Python frame") // + public static final OptionKey NoPythonFrame = new OptionKey<>(false); + public static final OptionDescriptors DESCRIPTORS = new PythonSourceOptionsOptionDescriptors(); } diff --git a/graalpython/lib-graalpython/modules/standalone/resources/Py2BinLauncher.java b/graalpython/lib-graalpython/modules/standalone/resources/Py2BinLauncher.java index 793c62f453..56ae9a9357 100644 --- a/graalpython/lib-graalpython/modules/standalone/resources/Py2BinLauncher.java +++ b/graalpython/lib-graalpython/modules/standalone/resources/Py2BinLauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -61,7 +61,7 @@ */ public class Py2BinLauncher { - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws IOException { Builder builder = GraalPyResources.contextBuilder() .allowExperimentalOptions(true) .allowAllAccess(true) @@ -72,7 +72,7 @@ public static void main(String[] args) throws IOException { } try (var context = builder.build()) { try { - var src = Source.newBuilder("python", "__graalpython__.run_path()", "").internal(true).build(); + var src = Source.newBuilder("python", "__graalpython__.run_path()", "").internal(true).option("python.NoPythonFrame", "true").build(); context.eval(src); } catch (PolyglotException e) { if (e.isExit()) { @@ -82,7 +82,7 @@ public static void main(String[] args) throws IOException { } } } - } + } private static String getProgramName() { if (ImageInfo.inImageRuntimeCode()) { From 2f71597e192f6ba9d8077d0523ead07a8015fbaf Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Thu, 2 Jul 2026 15:25:57 +0200 Subject: [PATCH 3/5] Simplify getting benchmark name in bisection --- mx.graalpython/mx_graalpython_bisect.py | 9 +++++- scripts/bisect_benchmark_regression.py | 41 +------------------------ 2 files changed, 9 insertions(+), 41 deletions(-) diff --git a/mx.graalpython/mx_graalpython_bisect.py b/mx.graalpython/mx_graalpython_bisect.py index b5033ac3ba..812d49f91e 100644 --- a/mx.graalpython/mx_graalpython_bisect.py +++ b/mx.graalpython/mx_graalpython_bisect.py @@ -251,6 +251,13 @@ def __str__(self): return "works" if self.value == 0 else "doesn't work" +def filter_benchmark_results(docs, benchmark_name): + exact_docs = [x for x in docs if x['benchmark'] == benchmark_name] + if exact_docs: + return exact_docs + return [x for x in docs if x['benchmark'].endswith(f'.{benchmark_name}')] + + def _bisect_benchmark(argv, bisect_id, email_to): default_metric = 'time' if 'BISECT_BENCHMARK_CONFIG' in os.environ: @@ -360,7 +367,7 @@ def benchmark_callback(repo_path: Path, commit, bench_command=args.benchmark_com data = json.load(f) docs = [x for x in data['queries'] if x['metric.name'] == args.benchmark_metric] if args.benchmark_name: - docs = [x for x in docs if x['benchmark'] == args.benchmark_name] + docs = filter_benchmark_results(docs, args.benchmark_name) if not docs: raise RuntimeError(f"Couldn't find specified metric {args.benchmark_metric!r} in the results") if len(docs) > 1: diff --git a/scripts/bisect_benchmark_regression.py b/scripts/bisect_benchmark_regression.py index 4fbe068e52..1207b5adbe 100644 --- a/scripts/bisect_benchmark_regression.py +++ b/scripts/bisect_benchmark_regression.py @@ -273,45 +273,6 @@ def extract_commands(log: str, benchmark_name: str) -> tuple[str, str]: return build_commands[-1], narrow_command(benchmark_commands[-1], benchmark_name) -def benchmark_match_score(candidate: str, selector: str) -> int: - if candidate == selector: - return 100 - if candidate.rsplit(".", 1)[-1] == selector: - return 90 - if candidate.rsplit(":", 1)[-1] == selector: - return 80 - if candidate.endswith(".{}".format(selector)): - return 70 - if candidate.endswith(":{}".format(selector)): - return 60 - return 0 - - -def resolve_results_benchmark_name(build_url: str, selector: str, metric: str) -> str | None: - if metric == "WORKS": - return None - data = json.loads(fetch_uploaded_log_text(build_url, "bench-results.json")) - candidates: list[tuple[int, int, str]] = [] - for index, document in enumerate(data.get("queries", [])): - if document.get("metric.name") != metric: - continue - benchmark = document.get("benchmark") - if not isinstance(benchmark, str): - continue - score = benchmark_match_score(benchmark, selector) - if score > 0: - candidates.append((score, index, benchmark)) - if not candidates: - return None - candidates.sort() - best_score = candidates[-1][0] - best_matches = [benchmark for score, _index, benchmark in candidates if score == best_score] - if len(set(best_matches)) != 1: - return None - best_match = best_matches[-1] - return best_match if best_match != selector else None - - def build_config_text( build_command: str, benchmark_command: str, @@ -556,7 +517,7 @@ def generate_config( debug("Using reference build {} ({})".format(reference_build.build_number, reference_build.url)) build_log = run_command(["gdev-cli", "buildbot", "get-log", str(reference_build.build_number)], cwd=repo_dir) build_command, benchmark_command = extract_commands(build_log, benchmark_name) - results_benchmark_name = resolve_results_benchmark_name(reference_build.url, benchmark_name, metric) + results_benchmark_name = None if metric == "WORKS" else benchmark_selector_for_command(benchmark_name) enterprise = "enterprise" in build_command return build_config_text( build_command=build_command, From 3a78571311a5e9fa32fe57ee9f5a8f7b0257bbae Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 3 Jul 2026 15:25:27 +0200 Subject: [PATCH 4/5] Remove email sending from bisection script --- ci.jsonnet | 2 -- ci/python-bench.libsonnet | 3 --- ci/python-gate.libsonnet | 3 --- mx.graalpython/mx_graalpython_bisect.py | 35 ++----------------------- 4 files changed, 2 insertions(+), 41 deletions(-) diff --git a/ci.jsonnet b/ci.jsonnet index e40b99b93d..80b8f9b50b 100644 --- a/ci.jsonnet +++ b/ci.jsonnet @@ -26,8 +26,6 @@ PIP_EXTRA_INDEX_URL: "", WATCHDOG_GIT: "", COMPLIANCE_GIT: "", - BISECT_EMAIL_SMTP_SERVER: "", - BISECT_EMAIL_FROM: "", npm_config_registry: "", RODINIA_DATASET_ZIP: "", GRAALPY_GRAALOS_TOOLCHAIN_URL: "", diff --git a/ci/python-bench.libsonnet b/ci/python-bench.libsonnet index a8f2857110..1b8694cc98 100644 --- a/ci/python-bench.libsonnet +++ b/ci/python-bench.libsonnet @@ -261,9 +261,6 @@ }, environment +: environment(self.os, self.arch) + { BISECT_BENCHMARK_CONFIG: "bisect-benchmark.ini", - BISECT_EMAIL_SMTP_SERVER: $.overlay_imports.BISECT_EMAIL_SMTP_SERVER, - BISECT_EMAIL_TO_PATTERN: ".*@oracle.com", - BISECT_EMAIL_FROM: $.overlay_imports.BISECT_EMAIL_FROM, ENABLE_POLYBENCH_HPC: "yes", POLYBENCH_HPC_EXTRA_HEADERS: "/cm/shared/apps/papi/papi-5.5.1/include", POLYBENCH_HPC_PAPI_LIB_DIR: "/cm/shared/apps/papi/papi-5.5.1/lib", diff --git a/ci/python-gate.libsonnet b/ci/python-gate.libsonnet index 5be4dcfa44..737107887e 100644 --- a/ci/python-gate.libsonnet +++ b/ci/python-gate.libsonnet @@ -134,9 +134,6 @@ MX_OUTPUT_ROOT_INCLUDES_CONFIG: "false", // this is important so we can build things on JDK-latest and run them on older JDKs CI: "true", BISECT_BENCHMARK_CONFIG: "bisect-benchmark.ini", - BISECT_EMAIL_FROM: $.overlay_imports.BISECT_EMAIL_FROM, - BISECT_EMAIL_SMTP_SERVER: $.overlay_imports.BISECT_EMAIL_SMTP_SERVER, - BISECT_EMAIL_TO_PATTERN: ".*@oracle.com", TRUFFLE_STRICT_OPTION_DEPRECATION: "true", npm_config_registry: $.overlay_imports.npm_config_registry, CFLAGS: "-ggdb", diff --git a/mx.graalpython/mx_graalpython_bisect.py b/mx.graalpython/mx_graalpython_bisect.py index 812d49f91e..c696c806cc 100644 --- a/mx.graalpython/mx_graalpython_bisect.py +++ b/mx.graalpython/mx_graalpython_bisect.py @@ -40,9 +40,7 @@ import argparse import json import os -import re import shlex -import sys import types from pathlib import Path @@ -258,7 +256,7 @@ def filter_benchmark_results(docs, benchmark_name): return [x for x in docs if x['benchmark'].endswith(f'.{benchmark_name}')] -def _bisect_benchmark(argv, bisect_id, email_to): +def _bisect_benchmark(argv, bisect_id): default_metric = 'time' if 'BISECT_BENCHMARK_CONFIG' in os.environ: import configparser @@ -423,41 +421,12 @@ def benchmark_callback(repo_path: Path, commit, bench_command=args.benchmark_com print_line(40) mx.run(shlex.split(cmd.strip()), nonZeroIsFatal=False) - send_email( - bisect_id, - email_to, - "Bisection job has finished successfully.\n{}\n".format(summary) - + "Note I'm just a script and I don't validate statistical significance of the above result.\n" - + "Please take a moment to also inspect the detailed results below.\n\n{}\n\n".format(visualization) - + os.environ.get('BUILD_URL', 'Unknown URL') - ) - def bisect_benchmark(argv): initial_branch = GIT.git_command(DIR, ['rev-parse', '--abbrev-ref', 'HEAD']).strip() initial_commit = GIT.git_command(DIR, ['log', '--format=%s', '-n', '1']).strip() - email_to = GIT.git_command(DIR, ['log', '--format=%cE', '-n', '1']).strip() bisect_id = f'{initial_branch}: {initial_commit}' try: - _bisect_benchmark(argv, bisect_id, email_to) + _bisect_benchmark(argv, bisect_id) finally: GIT.update_to_branch(DIR, initial_branch) - - -def send_email(bisect_id, email_to, content): - if 'BISECT_EMAIL_SMTP_SERVER' in os.environ: - import smtplib - from email.message import EmailMessage - - msg = EmailMessage() - msg['Subject'] = "Bisection result for {}".format(bisect_id) - msg['From'] = os.environ['BISECT_EMAIL_FROM'] - validate_to = os.environ['BISECT_EMAIL_TO_PATTERN'] - if not re.match(validate_to, email_to): - sys.exit("Email {} not allowed, aborting sending".format(email_to)) - msg['To'] = email_to - msg.set_content(content) - print(msg) - smtp = smtplib.SMTP(os.environ['BISECT_EMAIL_SMTP_SERVER']) - smtp.send_message(msg) - smtp.quit() From 59a4362a162d6ba37bcffa833564163357e53be2 Mon Sep 17 00:00:00 2001 From: Michael Simacek Date: Fri, 3 Jul 2026 15:41:10 +0200 Subject: [PATCH 5/5] Fall back to getting module name from globals --- .../builtins/modules/SysModuleBuiltins.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java index 4add7cf6f9..95ede68a5e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java @@ -112,6 +112,7 @@ import static com.oracle.graal.python.nodes.ErrorMessages.WARN_IGNORE_UNIMPORTABLE_BREAKPOINT_S; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___; import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___MODULE__; +import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___NAME__; import static com.oracle.graal.python.nodes.SpecialMethodNames.T___SIZEOF__; import static com.oracle.graal.python.nodes.StringLiterals.J_NEWLINE; import static com.oracle.graal.python.nodes.StringLiterals.T_BACKSLASHREPLACE; @@ -161,8 +162,8 @@ import com.oracle.graal.python.builtins.Python3Core; import com.oracle.graal.python.builtins.PythonBuiltinClassType; import com.oracle.graal.python.builtins.PythonBuiltins; -import com.oracle.graal.python.builtins.modules.SysModuleBuiltinsClinicProviders.GetFrameNodeClinicProviderGen; import com.oracle.graal.python.builtins.modules.SysModuleBuiltinsClinicProviders.GetFrameModuleNameNodeClinicProviderGen; +import com.oracle.graal.python.builtins.modules.SysModuleBuiltinsClinicProviders.GetFrameNodeClinicProviderGen; import com.oracle.graal.python.builtins.modules.SysModuleBuiltinsClinicProviders.SetDlopenFlagsClinicProviderGen; import com.oracle.graal.python.builtins.modules.io.BufferedReaderBuiltins; import com.oracle.graal.python.builtins.modules.io.BufferedWriterBuiltins; @@ -187,7 +188,6 @@ import com.oracle.graal.python.builtins.objects.exception.PBaseExceptionGroup; import com.oracle.graal.python.builtins.objects.frame.PFrame; import com.oracle.graal.python.builtins.objects.function.PArguments; -import com.oracle.graal.python.builtins.objects.function.PFunction; import com.oracle.graal.python.builtins.objects.function.PKeyword; import com.oracle.graal.python.builtins.objects.ints.PInt; import com.oracle.graal.python.builtins.objects.iterator.IteratorNodes; @@ -205,6 +205,7 @@ import com.oracle.graal.python.builtins.objects.tuple.StructSequence; import com.oracle.graal.python.builtins.objects.tuple.TupleBuiltins; import com.oracle.graal.python.lib.OsEnvironGetNode; +import com.oracle.graal.python.lib.PyDictGetItem; import com.oracle.graal.python.lib.PyExceptionGroupInstanceCheckNode; import com.oracle.graal.python.lib.PyExceptionInstanceCheckNode; import com.oracle.graal.python.lib.PyFloatAsDoubleNode; @@ -915,20 +916,27 @@ static Object counted(VirtualFrame frame, int depth, @Bind Node inliningTarget, @Cached AuditNode auditNode, @Cached ReadFrameNode readFrameNode, - @Cached PyObjectLookupAttr lookupAttrNode) { + @Cached PyObjectLookupAttr lookupAttrNode, + @Cached PyDictGetItem getItem) { auditNode.audit(frame, inliningTarget, T_SYS_GET_FRAME_MODULE_NAME, depth); int frameDepth = Math.max(depth, 0); - PFrame requested = readFrameNode.getFrameForReference(frame, PArguments.getCurrentFrameInfo(frame), ReadFrameNode.AllPythonFramesSelector.INSTANCE, frameDepth, 0); - if (requested == null) { + PFrame pFrame = readFrameNode.getFrameForReference(frame, PArguments.getCurrentFrameInfo(frame), ReadFrameNode.AllPythonFramesSelector.INSTANCE, frameDepth, 0); + if (pFrame == null) { return PNone.NONE; } - PFunction function = requested.getFunction(); - if (function == null) { - return PNone.NONE; + if (pFrame.getFunction() != null) { + Object moduleName = lookupAttrNode.execute(frame, inliningTarget, pFrame.getFunction(), T___MODULE__); + return moduleName != PNone.NO_VALUE ? moduleName : PNone.NONE; } - Object moduleName = lookupAttrNode.execute(frame, inliningTarget, function, T___MODULE__); - return moduleName != PNone.NO_VALUE ? moduleName : PNone.NONE; + /* + * Unlike CPython, we don't construct function objects for modules, so we have to try the function globals. + */ + if (pFrame.getGlobals() instanceof PDict globals) { + Object moduleName = getItem.execute(frame, inliningTarget, globals, T___NAME__); + return moduleName != null ? moduleName : PNone.NONE; + } + return PNone.NONE; } }