From 810faec9748b5256d6e0cfa243f5db1e3a740cf9 2024-05-07 08:22:23 From: M Bussonnier Date: 2024-05-07 08:22:23 Subject: [PATCH] Display Greek small letter mu (#14426) `%time foo()` output is often copied into code comments to explain performance improvements. The `\xb5` Latin Extended micro sign and the `\u03bc` Greek small letter mu have different codes but often look identical. Output mu to align with: * [The International System of Units (SI) brochure]( https://www.bipm.org/documents/20126/41483022/SI-Brochure-9-EN.pdf ), such as Table 7 SI prefixes * NFKC normalized [Python code](https://peps.python.org/pep-3131/ ) and [domain names](https://unicode.org/reports/tr36/). For example: ```sh python -c 'print("""class C: \xb5=1 print(hex(ord(dir(C)[-1])))""")' | tee /dev/fd/2 | python - ``` ```python class C: µ=1 print(hex(ord(dir(C)[-1]))) ``` `0x3bc` * Section 2.5 Duplicated Characters of [Unicode Technical Report 25]( https://www.unicode.org/reports/tr25/) > ...U+03BC μ is the preferred character in a Unicode context. * Ruff confusable mapping [updates]( https://github.com/astral-sh/ruff/pull/4430/files ), currently in the "preview" stage Add a unit test for UTF-8 display and https://bugs.launchpad.net/ipython/+bug/348466 ASCII fallback. --- diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index f3688f4..bf33ea3 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -1592,17 +1592,17 @@ def _format_time(timespan, precision=3): break return " ".join(time) - - # Unfortunately the unicode 'micro' symbol can cause problems in - # certain terminals. + + # Unfortunately characters outside of range(128) can cause problems in + # certain terminals. # See bug: https://bugs.launchpad.net/ipython/+bug/348466 # Try to prevent crashes by being more secure than it needs to # E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set. - units = [u"s", u"ms",u'us',"ns"] # the save value - if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding: + units = ["s", "ms", "us", "ns"] # the safe value + if hasattr(sys.stdout, "encoding") and sys.stdout.encoding: try: - u'\xb5'.encode(sys.stdout.encoding) - units = [u"s", u"ms",u'\xb5s',"ns"] + "μ".encode(sys.stdout.encoding) + units = ["s", "ms", "μs", "ns"] except: pass scaling = [1, 1e3, 1e6, 1e9] diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index da998fa..c757b9c 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -530,6 +530,14 @@ def test_time_local_ns(): del ip.user_ns["myvar"] +def test_time_microseconds_display(): + """Ensure ASCII is used when necessary""" + with mock.patch("sys.stdout", io.TextIOWrapper(StringIO(), encoding="utf-8")): + assert execution._format_time(0.000001) == "1 \u03bcs" + with mock.patch("sys.stdout", io.TextIOWrapper(StringIO(), encoding="ascii")): + assert execution._format_time(0.000001) == "1 us" + + # Test %%capture magic. Added to test issue #13926 def test_capture(): ip = get_ipython()