Skip to content

Commit 8fe6563

Browse files
committed
Fall back to non-localized message on Windows
Windows does not implement LC_MESSAGES, and since PEP 668 is mainly designed for Linux distributions, we simply take the easier way out until someone wants an equivalent on Windows.
1 parent 6750d84 commit 8fe6563

File tree

2 files changed

+71
-3
lines changed

2 files changed

+71
-3
lines changed

src/pip/_internal/exceptions.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,17 @@ def __init__(self, error: Optional[str]) -> None:
703703

704704
@staticmethod
705705
def _iter_externally_managed_error_keys() -> Iterator[str]:
706-
lang, _ = locale.getlocale(locale.LC_MESSAGES)
706+
# LC_MESSAGES is in POSIX, but not the C standard. The most common
707+
# platform that does not implement this category is Windows, where
708+
# using other categories for console message localization is equally
709+
# unreliable, so we fall back to the locale-less vendor message. This
710+
# can always be re-evaluated when a vendor proposes a new alternative.
711+
try:
712+
category = locale.LC_MESSAGES
713+
except AttributeError:
714+
lang: Optional[str] = None
715+
else:
716+
lang, _ = locale.getlocale(category)
707717
if lang is not None:
708718
yield f"Error-{lang}"
709719
for sep in ("-", "_"):

tests/unit/test_exceptions.py

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -492,9 +492,9 @@ def patch_locale(self, monkeypatch: pytest.MonkeyPatch) -> None:
492492
orig_getlocal = locale.getlocale
493493

494494
def fake_getlocale(category: int) -> Tuple[Optional[str], Optional[str]]:
495-
"""Fake getlocale() that always report zh_Hant."""
495+
"""Fake getlocale() that always reports zh_Hant for LC_MESSASGES."""
496496
result = orig_getlocal(category)
497-
if category == locale.LC_MESSAGES:
497+
if category == getattr(locale, "LC_MESSAGES", None):
498498
return "zh_Hant", result[1]
499499
return result
500500

@@ -541,6 +541,10 @@ def test_config_without_key(
541541
assert not caplog.records
542542
assert str(exc.context) == self.default_text
543543

544+
@pytest.mark.skipif(
545+
sys.platform == "win32",
546+
reason="Localization disabled on Windows",
547+
)
544548
@pytest.mark.parametrize(
545549
"config, expected",
546550
[
@@ -594,3 +598,57 @@ def test_config_canonical(
594598
exc = ExternallyManagedEnvironment.from_config(marker)
595599
assert not caplog.records
596600
assert str(exc.context) == expected
601+
602+
@pytest.mark.skipif(
603+
sys.platform != "win32",
604+
reason="Non-Windows should implement localization",
605+
)
606+
@pytest.mark.parametrize(
607+
"config",
608+
[
609+
pytest.param(
610+
"""\
611+
[externally-managed]
612+
Error = 最後
613+
Error-en = English
614+
Error-zh = 中文
615+
Error-zh_Hant = 繁體
616+
Error-zh_Hans = 简体
617+
""",
618+
id="full",
619+
),
620+
pytest.param(
621+
"""\
622+
[externally-managed]
623+
Error = 最後
624+
Error-en = English
625+
Error-zh = 中文
626+
Error-zh_Hans = 简体
627+
""",
628+
id="no-variant",
629+
),
630+
pytest.param(
631+
"""\
632+
[externally-managed]
633+
Error = 最後
634+
Error-en = English
635+
""",
636+
id="fallback",
637+
),
638+
],
639+
)
640+
def test_config_canonical_no_localization(
641+
self,
642+
caplog: pytest.LogCaptureFixture,
643+
marker: pathlib.Path,
644+
config: str,
645+
) -> None:
646+
marker.write_text(
647+
textwrap.dedent(config),
648+
encoding="utf8",
649+
)
650+
651+
with caplog.at_level(logging.WARNING, "pip._internal.exceptions"):
652+
exc = ExternallyManagedEnvironment.from_config(marker)
653+
assert not caplog.records
654+
assert str(exc.context) == "最後"

0 commit comments

Comments
 (0)