From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 22 Dec 2025 14:15:57 +0000 (+0200) Subject: gh-142927: Tachyon: Comma separate thousands and fix singular/plurals (#142934) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ff7f62eb2333ac2a2ce2726ba1763bf2fa1956e2;p=thirdparty%2FPython%2Fcpython.git gh-142927: Tachyon: Comma separate thousands and fix singular/plurals (#142934) --- diff --git a/Lib/profiling/sampling/_format_utils.py b/Lib/profiling/sampling/_format_utils.py new file mode 100644 index 000000000000..237a4f4186bf --- /dev/null +++ b/Lib/profiling/sampling/_format_utils.py @@ -0,0 +1,5 @@ +import locale + + +def fmt(value: int | float, decimals: int = 1) -> str: + return locale.format_string(f'%.{decimals}f', value, grouping=True) diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap.js b/Lib/profiling/sampling/_heatmap_assets/heatmap.js index 90b5b111d36a..53928b7b20fb 100644 --- a/Lib/profiling/sampling/_heatmap_assets/heatmap.js +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap.js @@ -577,10 +577,12 @@ function populateBytecodePanel(panel, button) { else if (specPct >= 33) specClass = 'medium'; // Build specialization summary + const instruction_word = instructions.length === 1 ? 'instruction' : 'instructions'; + const sample_word = totalSamples === 1 ? 'sample' : 'samples'; let html = `
${specPct}% specialized - (${specializedCount}/${instructions.length} instructions, ${specializedSamples.toLocaleString()}/${totalSamples.toLocaleString()} samples) + (${specializedCount}/${instructions.length} ${instruction_word}, ${specializedSamples.toLocaleString()}/${totalSamples.toLocaleString()} ${sample_word})
`; html += '
' + diff --git a/Lib/profiling/sampling/cli.py b/Lib/profiling/sampling/cli.py index 554167e43f5e..aacec645c347 100644 --- a/Lib/profiling/sampling/cli.py +++ b/Lib/profiling/sampling/cli.py @@ -2,6 +2,7 @@ import argparse import importlib.util +import locale import os import selectors import socket @@ -634,6 +635,16 @@ def _validate_args(args, parser): def main(): """Main entry point for the CLI.""" + # Set locale for number formatting, restore on exit + old_locale = locale.setlocale(locale.LC_ALL, None) + locale.setlocale(locale.LC_ALL, "") + try: + _main() + finally: + locale.setlocale(locale.LC_ALL, old_locale) + + +def _main(): # Create the main parser parser = argparse.ArgumentParser( description=_HELP_DESCRIPTION, diff --git a/Lib/profiling/sampling/heatmap_collector.py b/Lib/profiling/sampling/heatmap_collector.py index e6701901aa38..d9dabd664b32 100644 --- a/Lib/profiling/sampling/heatmap_collector.py +++ b/Lib/profiling/sampling/heatmap_collector.py @@ -5,6 +5,7 @@ import collections import html import importlib.resources import json +import locale import math import os import platform @@ -15,6 +16,7 @@ from pathlib import Path from typing import Dict, List, Tuple from ._css_utils import get_combined_css +from ._format_utils import fmt from .collector import normalize_location, extract_lineno from .stack_collector import StackTraceCollector @@ -343,7 +345,7 @@ class _HtmlRenderer:
{icon} {type_names[module_type]} - ({tree.count} {file_word}, {tree.samples:,} {sample_word}) + ({tree.count} {file_word}, {tree.samples:n} {sample_word})
''' @@ -390,7 +392,7 @@ class _HtmlRenderer: parts.append(f'{indent} ▶') parts.append(f'{indent} 📁 {html.escape(name)}') parts.append(f'{indent} ' - f'({node.count} {file_word}, {node.samples:,} {sample_word})') + f'({node.count} {file_word}, {node.samples:n} {sample_word})') parts.append(f'{indent}
') parts.append(f'{indent}