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]