From aec299d8c928d44dee3ba822514d93a58a69972a 2024-05-01 15:15:43 From: Christopher Covington Date: 2024-05-01 15:15:43 Subject: [PATCH] Display Greek small letter mu `%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..12f62b2 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 + units = [u"s", u"ms",u'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"] + u'μ'.encode(sys.stdout.encoding) + units = [u"s", u"ms",u'μ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..c2cad41 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -529,6 +529,12 @@ def test_time_local_ns(): assert ip.user_ns["myvar"] == 1 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():