https://github.com/python/cpython/commit/368a26777a9915326b4857402a8ab595d9837f95
commit: 368a26777a9915326b4857402a8ab595d9837f95
branch: main
author: Hugo van Kemenade <[email protected]>
committer: hugovk <[email protected]>
date: 2026-03-10T13:38:48+02:00
summary:

gh-142927: Detect system theme in flame graph like in heatmap (#144885)

files:
A Lib/profiling/sampling/_shared_assets/base.js
M Lib/profiling/sampling/_flamegraph_assets/flamegraph.js
M Lib/profiling/sampling/_flamegraph_assets/flamegraph_template.html
M Lib/profiling/sampling/_heatmap_assets/heatmap.js
M Lib/profiling/sampling/_heatmap_assets/heatmap_shared.js
M Lib/profiling/sampling/heatmap_collector.py
M Lib/profiling/sampling/stack_collector.py

diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js 
b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js
index 1a51802ffefac7..a2b21da2970064 100644
--- a/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js
+++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph.js
@@ -83,18 +83,7 @@ function resolveStringIndices(node) {
 // ============================================================================
 
 function toggleTheme() {
-  const html = document.documentElement;
-  const current = html.getAttribute('data-theme') || 'light';
-  const next = current === 'light' ? 'dark' : 'light';
-  html.setAttribute('data-theme', next);
-  localStorage.setItem('flamegraph-theme', next);
-
-  // Update theme button icon
-  const btn = document.getElementById('theme-btn');
-  if (btn) {
-    btn.querySelector('.icon-moon').style.display = next === 'dark' ? 'none' : 
'';
-    btn.querySelector('.icon-sun').style.display = next === 'dark' ? '' : 
'none';
-  }
+  toggleAndSaveTheme();
 
   // Re-render flamegraph with new theme colors
   if (window.flamegraphData && normalData) {
@@ -154,17 +143,9 @@ function toggleSection(sectionId) {
   }
 }
 
+// Restore theme from localStorage, or use browser preference
 function restoreUIState() {
-  // Restore theme
-  const savedTheme = localStorage.getItem('flamegraph-theme');
-  if (savedTheme) {
-    document.documentElement.setAttribute('data-theme', savedTheme);
-    const btn = document.getElementById('theme-btn');
-    if (btn) {
-      btn.querySelector('.icon-moon').style.display = savedTheme === 'dark' ? 
'none' : '';
-      btn.querySelector('.icon-sun').style.display = savedTheme === 'dark' ? 
'' : 'none';
-    }
-  }
+  applyTheme(getPreferredTheme());
 
   // Restore sidebar state
   const savedSidebar = localStorage.getItem('flamegraph-sidebar');
@@ -1242,23 +1223,6 @@ function generateInvertedFlamegraph(data) {
   return invertedRoot;
 }
 
-function updateToggleUI(toggleId, isOn) {
-  const toggle = document.getElementById(toggleId);
-  if (toggle) {
-    const track = toggle.querySelector('.toggle-track');
-    const labels = toggle.querySelectorAll('.toggle-label');
-    if (isOn) {
-      track.classList.add('on');
-      labels[0].classList.remove('active');
-      labels[1].classList.add('active');
-    } else {
-      track.classList.remove('on');
-      labels[0].classList.add('active');
-      labels[1].classList.remove('active');
-    }
-  }
-}
-
 function toggleInvert() {
   isInverted = !isInverted;
   updateToggleUI('toggle-invert', isInverted);
diff --git a/Lib/profiling/sampling/_flamegraph_assets/flamegraph_template.html 
b/Lib/profiling/sampling/_flamegraph_assets/flamegraph_template.html
index 195a555d68e98b..07b15a5a2b48c7 100644
--- a/Lib/profiling/sampling/_flamegraph_assets/flamegraph_template.html
+++ b/Lib/profiling/sampling/_flamegraph_assets/flamegraph_template.html
@@ -1,5 +1,5 @@
 <!doctype html>
-<html lang="en" data-theme="light">
+<html lang="en">
   <head>
     <meta charset="UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap.js 
b/Lib/profiling/sampling/_heatmap_assets/heatmap.js
index 53928b7b20fb11..2da1103b82a52a 100644
--- a/Lib/profiling/sampling/_heatmap_assets/heatmap.js
+++ b/Lib/profiling/sampling/_heatmap_assets/heatmap.js
@@ -203,23 +203,6 @@ function applyLineColors() {
 // Toggle Controls
 // ============================================================================
 
-function updateToggleUI(toggleId, isOn) {
-    const toggle = document.getElementById(toggleId);
-    if (toggle) {
-        const track = toggle.querySelector('.toggle-track');
-        const labels = toggle.querySelectorAll('.toggle-label');
-        if (isOn) {
-            track.classList.add('on');
-            labels[0].classList.remove('active');
-            labels[1].classList.add('active');
-        } else {
-            track.classList.remove('on');
-            labels[0].classList.add('active');
-            labels[1].classList.remove('active');
-        }
-    }
-}
-
 function toggleColdCode() {
     coldCodeHidden = !coldCodeHidden;
     applyHotFilter();
diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap_shared.js 
b/Lib/profiling/sampling/_heatmap_assets/heatmap_shared.js
index 84b13ca0a9682b..fb761335876b0f 100644
--- a/Lib/profiling/sampling/_heatmap_assets/heatmap_shared.js
+++ b/Lib/profiling/sampling/_heatmap_assets/heatmap_shared.js
@@ -43,33 +43,6 @@ function intensityToColor(intensity) {
 // Theme Support
 // ============================================================================
 
-// Get the preferred theme from localStorage or browser preference
-function getPreferredTheme() {
-    const saved = localStorage.getItem('heatmap-theme');
-    if (saved) return saved;
-    return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' 
: 'light';
-}
-
-// Apply theme and update UI. Returns the applied theme.
-function applyTheme(theme) {
-    document.documentElement.setAttribute('data-theme', theme);
-    const btn = document.getElementById('theme-btn');
-    if (btn) {
-        btn.querySelector('.icon-moon').style.display = theme === 'dark' ? 
'none' : '';
-        btn.querySelector('.icon-sun').style.display = theme === 'dark' ? '' : 
'none';
-    }
-    return theme;
-}
-
-// Toggle theme and save preference. Returns the new theme.
-function toggleAndSaveTheme() {
-    const current = document.documentElement.getAttribute('data-theme') || 
'light';
-    const next = current === 'light' ? 'dark' : 'light';
-    applyTheme(next);
-    localStorage.setItem('heatmap-theme', next);
-    return next;
-}
-
 // Restore theme from localStorage, or use browser preference
 function restoreUIState() {
     applyTheme(getPreferredTheme());
diff --git a/Lib/profiling/sampling/_shared_assets/base.js 
b/Lib/profiling/sampling/_shared_assets/base.js
new file mode 100644
index 00000000000000..da8b5851c85f62
--- /dev/null
+++ b/Lib/profiling/sampling/_shared_assets/base.js
@@ -0,0 +1,58 @@
+// Tachyon Profiler - Shared JavaScript
+// Common utilities shared between flamegraph and heatmap views
+
+// ============================================================================
+// Theme Support
+// ============================================================================
+
+// Storage key for theme preference
+const THEME_STORAGE_KEY = 'tachyon-theme';
+
+// Get the preferred theme from localStorage or system preference
+function getPreferredTheme() {
+  const saved = localStorage.getItem(THEME_STORAGE_KEY);
+  if (saved) return saved;
+  return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 
'light';
+}
+
+// Apply theme and update UI
+function applyTheme(theme) {
+  document.documentElement.setAttribute('data-theme', theme);
+  const btn = document.getElementById('theme-btn');
+  if (btn) {
+    const moonIcon = btn.querySelector('.icon-moon');
+    const sunIcon = btn.querySelector('.icon-sun');
+    if (moonIcon) moonIcon.style.display = theme === 'dark' ? 'none' : '';
+    if (sunIcon) sunIcon.style.display = theme === 'dark' ? '' : 'none';
+  }
+}
+
+// Toggle theme and save preference. Returns the new theme.
+function toggleAndSaveTheme() {
+  const current = document.documentElement.getAttribute('data-theme') || 
'light';
+  const next = current === 'light' ? 'dark' : 'light';
+  applyTheme(next);
+  localStorage.setItem(THEME_STORAGE_KEY, next);
+  return next;
+}
+
+// ============================================================================
+// Toggle Switch UI
+// ============================================================================
+
+function updateToggleUI(toggleId, isOn) {
+  const toggle = document.getElementById(toggleId);
+  if (toggle) {
+    const track = toggle.querySelector('.toggle-track');
+    const labels = toggle.querySelectorAll('.toggle-label');
+    if (isOn) {
+      track.classList.add('on');
+      labels[0].classList.remove('active');
+      labels[1].classList.add('active');
+    } else {
+      track.classList.remove('on');
+      labels[0].classList.add('active');
+      labels[1].classList.remove('active');
+    }
+  }
+}
diff --git a/Lib/profiling/sampling/heatmap_collector.py 
b/Lib/profiling/sampling/heatmap_collector.py
index b6d9ff79e8ceec..ea1beec70d39f8 100644
--- a/Lib/profiling/sampling/heatmap_collector.py
+++ b/Lib/profiling/sampling/heatmap_collector.py
@@ -204,7 +204,9 @@ def _load_templates(self):
             self.file_css = css_content
 
             # Load JS
-            shared_js = (assets_dir / 
"heatmap_shared.js").read_text(encoding="utf-8")
+            base_js = (template_dir / "_shared_assets" / 
"base.js").read_text(encoding="utf-8")
+            heatmap_shared_js = (assets_dir / 
"heatmap_shared.js").read_text(encoding="utf-8")
+            shared_js = f"{base_js}\n{heatmap_shared_js}"
             self.index_js = f"{shared_js}\n{(assets_dir / 
'heatmap_index.js').read_text(encoding='utf-8')}"
             self.file_js = f"{shared_js}\n{(assets_dir / 
'heatmap.js').read_text(encoding='utf-8')}"
 
diff --git a/Lib/profiling/sampling/stack_collector.py 
b/Lib/profiling/sampling/stack_collector.py
index 5a3497a5408414..931bc2c487b55b 100644
--- a/Lib/profiling/sampling/stack_collector.py
+++ b/Lib/profiling/sampling/stack_collector.py
@@ -377,7 +377,9 @@ def _create_flamegraph_html(self, data):
 
         html_template = (template_dir / "_flamegraph_assets" / 
"flamegraph_template.html").read_text(encoding="utf-8")
         css_content = get_combined_css("flamegraph")
-        js_content = (template_dir /  "_flamegraph_assets" / 
"flamegraph.js").read_text(encoding="utf-8")
+        base_js = (template_dir / "_shared_assets" / 
"base.js").read_text(encoding="utf-8")
+        component_js = (template_dir / "_flamegraph_assets" / 
"flamegraph.js").read_text(encoding="utf-8")
+        js_content = f"{base_js}\n{component_js}"
 
         # Inline first-party CSS/JS
         html_template = html_template.replace(

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to