From 9d63c6ce016c610c2d24d3fa9a26c392d1904cca Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 1 Dec 2024 23:56:10 +0800 Subject: [PATCH 01/10] Add utility function _is_ascii --- pygmt/helpers/utils.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index 32fad37e4ff..c8b8cf58dd6 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -145,6 +145,29 @@ def _validate_data_input( raise GMTInvalidInput(msg) +def _is_ascii(argstr: str) -> bool: + """ + Check if a string only contains ASCII characters. + + Parameters + ---------- + argstr + The string to be checked. + + Returns + ------- + ``True`` if the string only contains ASCII characters. Otherwise, return ``False``. + + Examples + -------- + >>> _is_ascii("123ABC+-?!") + True + >>> _is_ascii("12AB±β①②") + False + """ + return all(32 <= ord(c) <= 126 for c in argstr) + + def _check_encoding(argstr: str) -> Encoding: """ Check the charset encoding of a string. @@ -178,7 +201,7 @@ def _check_encoding(argstr: str) -> Encoding: 'ISOLatin1+' """ # Return "ascii" if the string only contains ASCII characters. - if all(32 <= ord(c) <= 126 for c in argstr): + if _is_ascii(argstr): return "ascii" # Loop through all supported encodings and check if all characters in the string # are in the charset of the encoding. If all characters are in the charset, return @@ -375,7 +398,7 @@ def non_ascii_to_octal(argstr: str, encoding: Encoding = "ISOLatin1+") -> str: '12AB\\340\\341\\342\\343\\344\\345@~\\142@~@%34%\\254@%%@%34%\\255@%%' """ # noqa: RUF002 # Return the input string if it only contains ASCII characters. - if encoding == "ascii" or all(32 <= ord(c) <= 126 for c in argstr): + if encoding == "ascii" or _is_ascii(argstr): return argstr # Dictionary mapping non-ASCII characters to octal codes From 89ac19ac22a7dc2ffc0cf29506e3a9516f29921d Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 2 Dec 2024 00:03:33 +0800 Subject: [PATCH 02/10] Handling apostrophe and backtick --- pygmt/helpers/utils.py | 54 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index c8b8cf58dd6..7ca524a1da1 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -168,6 +168,41 @@ def _is_ascii(argstr: str) -> bool: return all(32 <= ord(c) <= 126 for c in argstr) +def _has_apostrophe_or_backtick(argstr: str) -> bool: + """ + Check if a string contains apostrophe (') or backtick (`). + + For typographical reasons, apostrophe (') and backtick (`) are mapped to left and + right single quotation marks (‘ and ’) in Adobe ISOLatin1+ encoding. To ensure what + you type is what you get (https://github.com/GenericMappingTools/pygmt/issues/3476), + they need special handling in the ``_check_encoding`` and ``non_ascii_to_octal`` + functions. More specifically, a string that contains ASCII characters without + apostrophe (') and backtick (`) will be considered as "ascii" encoding. + + Parameters + ---------- + argstr + The string to be checked. + + Returns + ------- + ``True`` if the string contains apostrophe (') or backtick (`). Otherwise, return + ``False``. + + Examples + -------- + >>> _has_apostrophe_or_backtick("12AB±β①②") + False + >>> _has_apostrophe_or_backtick("12AB`") + True + >>> _has_apostrophe_or_backtick("12AB'") + True + >>> _has_apostrophe_or_backtick("12AB'`") + True + """ # noqa: RUF002 + return "'" in argstr or "`" in argstr + + def _check_encoding(argstr: str) -> Encoding: """ Check the charset encoding of a string. @@ -200,8 +235,9 @@ def _check_encoding(argstr: str) -> Encoding: >>> _check_encoding("123AB中文") # Characters not in any charset encoding 'ISOLatin1+' """ - # Return "ascii" if the string only contains ASCII characters. - if _is_ascii(argstr): + # Return "ascii" if the string only contains ASCII characters, excluding apostrophe + # (') and backtick (`). + if _is_ascii(argstr) and not _has_apostrophe_or_backtick(argstr): return "ascii" # Loop through all supported encodings and check if all characters in the string # are in the charset of the encoding. If all characters are in the charset, return @@ -397,8 +433,11 @@ def non_ascii_to_octal(argstr: str, encoding: Encoding = "ISOLatin1+") -> str: >>> non_ascii_to_octal("12ABāáâãäåβ①②", encoding="ISO-8859-4") '12AB\\340\\341\\342\\343\\344\\345@~\\142@~@%34%\\254@%%@%34%\\255@%%' """ # noqa: RUF002 - # Return the input string if it only contains ASCII characters. - if encoding == "ascii" or _is_ascii(argstr): + # Return the input string if it only contains ASCII characters, excluding apostrophe + # (') and backtick (`). + if encoding == "ascii" or ( + _is_ascii(argstr) and not _has_apostrophe_or_backtick(argstr) + ): return argstr # Dictionary mapping non-ASCII characters to octal codes @@ -412,8 +451,13 @@ def non_ascii_to_octal(argstr: str, encoding: Encoding = "ISOLatin1+") -> str: # ISOLatin1+ or ISO-8859-x charset. mapping.update({c: f"\\{i:03o}" for i, c in charset[encoding].items()}) - # Remove any printable characters + # Remove any printable characters. mapping = {k: v for k, v in mapping.items() if k not in string.printable} + + if encoding == "ISOLatin1+": + # Map apostrophe (') and backtick (`) to correct octal codes. + # See _has_apostrophe_or_backtick() for explanations. + mapping.update({"'": "\\234", "`": "\\221"}) return argstr.translate(str.maketrans(mapping)) From 3e3117be345c5560bc0dc044df35613a619991ee Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 2 Dec 2024 00:04:03 +0800 Subject: [PATCH 03/10] Add a doctest for non_ascii_to_octal --- pygmt/helpers/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index 7ca524a1da1..0154551a7de 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -432,6 +432,8 @@ def non_ascii_to_octal(argstr: str, encoding: Encoding = "ISOLatin1+") -> str: 'ABC \\261120\\260 DEF @~\\141@~ @%34%\\252@%%' >>> non_ascii_to_octal("12ABāáâãäåβ①②", encoding="ISO-8859-4") '12AB\\340\\341\\342\\343\\344\\345@~\\142@~@%34%\\254@%%@%34%\\255@%%' + >>> non_ascii_to_octal("'‘’\"“”") + '\\234\\140\\047"\\216\\217' """ # noqa: RUF002 # Return the input string if it only contains ASCII characters, excluding apostrophe # (') and backtick (`). From f5b358ac85c3398ac304e4aecf1a27cff96e22f5 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 2 Dec 2024 00:04:43 +0800 Subject: [PATCH 04/10] Split the long build_arg_list doctest into multiple doctests --- pygmt/helpers/utils.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index 0154551a7de..08fec4bb5de 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -505,16 +505,12 @@ def build_arg_list( # noqa: PLR0912 ['-A', '-D0', '-E200', '-F', '-G1/2/3/4'] >>> build_arg_list(dict(A="1/2/3/4", B=["xaf", "yaf", "WSen"], C=("1p", "2p"))) ['-A1/2/3/4', '-BWSen', '-Bxaf', '-Byaf', '-C1p', '-C2p'] - >>> print( - ... build_arg_list( - ... dict( - ... B=["af", "WSne+tBlank Space"], - ... F='+t"Empty Spaces"', - ... l="'Void Space'", - ... ) - ... ) - ... ) - ['-BWSne+tBlank Space', '-Baf', '-F+t"Empty Spaces"', "-l'Void Space'"] + >>> build_arg_list(dict(B=["af", "WSne+tBlank Space"])) + ['-BWSne+tBlank Space', '-Baf'] + >>> build_arg_list(dict(F='+t"Empty Spaces"')) + ['-F+t"Empty Spaces"'] + >>> build_arg_list(dict(l="'Void Space'")) + ['-l\\234Void Space\\234', '--PS_CHAR_ENCODING=ISOLatin1+'] >>> print( ... build_arg_list( ... dict(A="0", B=True, C="rainbow"), From 75da591bba99fee3713d302b7346cb27e891c99e Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 2 Dec 2024 00:12:58 +0800 Subject: [PATCH 05/10] Update test_text_quotation_marks --- .../tests/baseline/test_text_quotation_marks.png.dvc | 4 ++-- pygmt/tests/test_text.py | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/pygmt/tests/baseline/test_text_quotation_marks.png.dvc b/pygmt/tests/baseline/test_text_quotation_marks.png.dvc index 2a1cf6296d3..e38fe9b2ebb 100644 --- a/pygmt/tests/baseline/test_text_quotation_marks.png.dvc +++ b/pygmt/tests/baseline/test_text_quotation_marks.png.dvc @@ -1,5 +1,5 @@ outs: -- md5: 90d08c5a11c606abed51b84eafcdea04 - size: 1662 +- md5: f3ddc9b50f3da1facdbcd32261db3bd6 + size: 2965 hash: md5 path: test_text_quotation_marks.png diff --git a/pygmt/tests/test_text.py b/pygmt/tests/test_text.py index 22b446302b8..f213b58f40e 100644 --- a/pygmt/tests/test_text.py +++ b/pygmt/tests/test_text.py @@ -447,13 +447,17 @@ def test_text_nonascii(encoding): @pytest.mark.mpl_image_compare def test_text_quotation_marks(): """ - Test typesetting quotation marks. + Test typesetting single and double quotation marks. - See https://github.com/GenericMappingTools/pygmt/issues/3104. + See https://github.com/GenericMappingTools/pygmt/issues/3104 and + https://github.com/GenericMappingTools/pygmt/issues/3476. """ + quotations = "` ' ‘ ’ \" “ ”" # noqa: RUF001 fig = Figure() - fig.basemap(projection="X4c/2c", region=[0, 4, 0, 2], frame=0) - fig.text(x=2, y=1, text='\\234 ‘ ’ " “ ”', font="20p") # noqa: RUF001 + fig.basemap( + projection="X4c/2c", region=[0, 4, 0, 2], frame=["S", f"x+l{quotations}"] + ) + fig.text(x=2, y=1, text=quotations, font="20p") return fig From 06b10607570aacb57870f83da26a5cd5eeeade99 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 6 Dec 2024 23:28:31 +0800 Subject: [PATCH 06/10] Typo --- pygmt/helpers/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index 08fec4bb5de..2eb945be176 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -177,7 +177,7 @@ def _has_apostrophe_or_backtick(argstr: str) -> bool: you type is what you get (https://github.com/GenericMappingTools/pygmt/issues/3476), they need special handling in the ``_check_encoding`` and ``non_ascii_to_octal`` functions. More specifically, a string that contains ASCII characters without - apostrophe (') and backtick (`) will be considered as "ascii" encoding. + apostrophe (') and backtick (`) will not be considered as "ascii" encoding. Parameters ---------- From 782cf08878ed3777a7b94f676ba82a0c22575fa5 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 21 Dec 2024 13:58:54 +0800 Subject: [PATCH 07/10] Rename _is_ascii to _is_printable_ascii --- pygmt/helpers/utils.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index 2eb945be176..f8ee450ca80 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -145,9 +145,12 @@ def _validate_data_input( raise GMTInvalidInput(msg) -def _is_ascii(argstr: str) -> bool: +def _is_printable_ascii(argstr: str) -> bool: """ - Check if a string only contains ASCII characters. + Check if a string only contains printable ASCII characters. + + Printable ASCII characters are defined as the characters in the range of 32 to 126 + in the ASCII table. Parameters ---------- @@ -156,13 +159,14 @@ def _is_ascii(argstr: str) -> bool: Returns ------- - ``True`` if the string only contains ASCII characters. Otherwise, return ``False``. + ``True`` if the string only contains printable ASCII characters. Otherwise, return + ``False``. Examples -------- - >>> _is_ascii("123ABC+-?!") + >>> _is_printable_ascii("123ABC+-?!") True - >>> _is_ascii("12AB±β①②") + >>> _is_printable_ascii("12AB±β①②") False """ return all(32 <= ord(c) <= 126 for c in argstr) @@ -176,7 +180,7 @@ def _has_apostrophe_or_backtick(argstr: str) -> bool: right single quotation marks (‘ and ’) in Adobe ISOLatin1+ encoding. To ensure what you type is what you get (https://github.com/GenericMappingTools/pygmt/issues/3476), they need special handling in the ``_check_encoding`` and ``non_ascii_to_octal`` - functions. More specifically, a string that contains ASCII characters without + functions. More specifically, a string that contains printable ASCII characters with apostrophe (') and backtick (`) will not be considered as "ascii" encoding. Parameters @@ -235,9 +239,9 @@ def _check_encoding(argstr: str) -> Encoding: >>> _check_encoding("123AB中文") # Characters not in any charset encoding 'ISOLatin1+' """ - # Return "ascii" if the string only contains ASCII characters, excluding apostrophe - # (') and backtick (`). - if _is_ascii(argstr) and not _has_apostrophe_or_backtick(argstr): + # Return "ascii" if the string only contains printable ASCII characters, excluding + # apostrophe (') and backtick (`). + if _is_printable_ascii(argstr) and not _has_apostrophe_or_backtick(argstr): return "ascii" # Loop through all supported encodings and check if all characters in the string # are in the charset of the encoding. If all characters are in the charset, return @@ -435,10 +439,10 @@ def non_ascii_to_octal(argstr: str, encoding: Encoding = "ISOLatin1+") -> str: >>> non_ascii_to_octal("'‘’\"“”") '\\234\\140\\047"\\216\\217' """ # noqa: RUF002 - # Return the input string if it only contains ASCII characters, excluding apostrophe - # (') and backtick (`). + # Return the input string if it only contains printable ASCII characters, excluding + # apostrophe (') and backtick (`). if encoding == "ascii" or ( - _is_ascii(argstr) and not _has_apostrophe_or_backtick(argstr) + _is_printable_ascii(argstr) and not _has_apostrophe_or_backtick(argstr) ): return argstr From 37ecc0e06afa9530f158e89f3f9d56071ebed65d Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 9 Feb 2025 15:53:19 +0800 Subject: [PATCH 08/10] Add the private _is_printable_ascii function to simplify codes --- pygmt/helpers/utils.py | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index e32f5bbe03f..e522f893579 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -145,6 +145,35 @@ def _validate_data_input( raise GMTInvalidInput(msg) +def _is_printable_ascii(argstr: str) -> bool: + """ + Check if a string only contains printable ASCII characters. + + Here, printable ASCII characters are defined as the characters in the range of 32 to + 126 in the ASCII table. It's different from the ``string.printable`` constant that + it doesn't include the control characters that are considered whitespace (tab, + linefeed, return, formfeed, and vertical tab). + + Parameters + ---------- + argstr + The string to be checked. + + Returns + ------- + ``True`` if the string only contains printable ASCII characters. Otherwise, return + ``False``. + + Examples + -------- + >>> _is_printable_ascii("123ABC+-?!") + True + >>> _is_printable_ascii("12AB±β①②") + False + """ + return all(32 <= ord(c) <= 126 for c in argstr) + + def _check_encoding(argstr: str) -> Encoding: """ Check the charset encoding of a string. @@ -177,8 +206,8 @@ def _check_encoding(argstr: str) -> Encoding: >>> _check_encoding("123AB中文") # Characters not in any charset encoding 'ISOLatin1+' """ - # Return "ascii" if the string only contains ASCII characters. - if all(32 <= ord(c) <= 126 for c in argstr): + # Return "ascii" if the string only contains printable ASCII characters. + if _is_printable_ascii(argstr): return "ascii" # Loop through all supported encodings and check if all characters in the string # are in the charset of the encoding. If all characters are in the charset, return @@ -374,8 +403,8 @@ def non_ascii_to_octal(argstr: str, encoding: Encoding = "ISOLatin1+") -> str: >>> non_ascii_to_octal("12ABāáâãäåβ①②", encoding="ISO-8859-4") '12AB\\340\\341\\342\\343\\344\\345@~\\142@~@%34%\\254@%%@%34%\\255@%%' """ # noqa: RUF002 - # Return the input string if it only contains ASCII characters. - if encoding == "ascii" or all(32 <= ord(c) <= 126 for c in argstr): + # Return the input string if it only contains printable ASCII characters. + if encoding == "ascii" or _is_printable_ascii(argstr): return argstr # Dictionary mapping non-ASCII characters to octal codes @@ -389,7 +418,7 @@ def non_ascii_to_octal(argstr: str, encoding: Encoding = "ISOLatin1+") -> str: # ISOLatin1+ or ISO-8859-x charset. mapping.update({c: f"\\{i:03o}" for i, c in charset[encoding].items()}) - # Remove any printable characters + # Remove any printable characters. mapping = {k: v for k, v in mapping.items() if k not in string.printable} return argstr.translate(str.maketrans(mapping)) From fe3cdcde90cbc3f126445a1708f218cdd772f8ae Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 20 Feb 2025 16:45:08 +0800 Subject: [PATCH 09/10] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yvonne Fröhlich <94163266+yvonnefroehlich@users.noreply.github.com> --- pygmt/helpers/utils.py | 6 +++--- pygmt/tests/test_text.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index cd96fec6cae..8d08731787b 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -174,15 +174,15 @@ def _is_printable_ascii(argstr: str) -> bool: return all(32 <= ord(c) <= 126 for c in argstr) -def _has_apostrophe_or_backtick(argstr: str) -> bool: +def _contains_apostrophe_or_backtick(argstr: str) -> bool: """ Check if a string contains apostrophe (') or backtick (`). For typographical reasons, apostrophe (') and backtick (`) are mapped to left and - right single quotation marks (‘ and ’) in Adobe ISOLatin1+ encoding. To ensure what + right single quotation marks (‘ and ’) in Adobe ISOLatin1+ encoding. To ensure that what you type is what you get (https://github.com/GenericMappingTools/pygmt/issues/3476), they need special handling in the ``_check_encoding`` and ``non_ascii_to_octal`` - functions. More specifically, a string that contains printable ASCII characters with + functions. More specifically, a string containing printable ASCII characters with apostrophe (') and backtick (`) will not be considered as "ascii" encoding. Parameters diff --git a/pygmt/tests/test_text.py b/pygmt/tests/test_text.py index 72e82f86399..b77c9ff36e1 100644 --- a/pygmt/tests/test_text.py +++ b/pygmt/tests/test_text.py @@ -466,7 +466,7 @@ def test_text_nonascii(encoding): @pytest.mark.mpl_image_compare def test_text_quotation_marks(): """ - Test typesetting single and double quotation marks. + Test typesetting backtick, apostrophe, and single and double quotation marks. See https://github.com/GenericMappingTools/pygmt/issues/3104 and https://github.com/GenericMappingTools/pygmt/issues/3476. From 045548c84654e4886c85727bf1c1fd6ca6a9c6f7 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 20 Feb 2025 16:53:51 +0800 Subject: [PATCH 10/10] Fix names --- pygmt/helpers/utils.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py index 8d08731787b..da9b4ad026a 100644 --- a/pygmt/helpers/utils.py +++ b/pygmt/helpers/utils.py @@ -179,11 +179,11 @@ def _contains_apostrophe_or_backtick(argstr: str) -> bool: Check if a string contains apostrophe (') or backtick (`). For typographical reasons, apostrophe (') and backtick (`) are mapped to left and - right single quotation marks (‘ and ’) in Adobe ISOLatin1+ encoding. To ensure that what - you type is what you get (https://github.com/GenericMappingTools/pygmt/issues/3476), - they need special handling in the ``_check_encoding`` and ``non_ascii_to_octal`` - functions. More specifically, a string containing printable ASCII characters with - apostrophe (') and backtick (`) will not be considered as "ascii" encoding. + right single quotation marks (‘ and ’) in Adobe ISOLatin1+ encoding. To ensure that + what you type is what you get (issue #3476), they need special handling in the + ``_check_encoding`` and ``non_ascii_to_octal`` functions. More specifically, a + string containing printable ASCII characters with apostrophe (') and backtick (`) + will not be considered as "ascii" encoding. Parameters ---------- @@ -197,13 +197,13 @@ def _contains_apostrophe_or_backtick(argstr: str) -> bool: Examples -------- - >>> _has_apostrophe_or_backtick("12AB±β①②") + >>> _contains_apostrophe_or_backtick("12AB±β①②") False - >>> _has_apostrophe_or_backtick("12AB`") + >>> _contains_apostrophe_or_backtick("12AB`") True - >>> _has_apostrophe_or_backtick("12AB'") + >>> _contains_apostrophe_or_backtick("12AB'") True - >>> _has_apostrophe_or_backtick("12AB'`") + >>> _contains_apostrophe_or_backtick("12AB'`") True """ # noqa: RUF002 return "'" in argstr or "`" in argstr @@ -243,7 +243,7 @@ def _check_encoding(argstr: str) -> Encoding: """ # Return "ascii" if the string only contains printable ASCII characters, excluding # apostrophe (') and backtick (`). - if _is_printable_ascii(argstr) and not _has_apostrophe_or_backtick(argstr): + if _is_printable_ascii(argstr) and not _contains_apostrophe_or_backtick(argstr): return "ascii" # Loop through all supported encodings and check if all characters in the string # are in the charset of the encoding. If all characters are in the charset, return @@ -444,7 +444,7 @@ def non_ascii_to_octal(argstr: str, encoding: Encoding = "ISOLatin1+") -> str: # Return the input string if it only contains printable ASCII characters, excluding # apostrophe (') and backtick (`). if encoding == "ascii" or ( - _is_printable_ascii(argstr) and not _has_apostrophe_or_backtick(argstr) + _is_printable_ascii(argstr) and not _contains_apostrophe_or_backtick(argstr) ): return argstr @@ -464,7 +464,7 @@ def non_ascii_to_octal(argstr: str, encoding: Encoding = "ISOLatin1+") -> str: if encoding == "ISOLatin1+": # Map apostrophe (') and backtick (`) to correct octal codes. - # See _has_apostrophe_or_backtick() for explanations. + # See _contains_apostrophe_or_backtick() for explanations. mapping.update({"'": "\\234", "`": "\\221"}) return argstr.translate(str.maketrans(mapping))