test_localization.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import codecs
  2. import locale
  3. import os
  4. import pytest
  5. from pandas._config.localization import (
  6. can_set_locale,
  7. get_locales,
  8. set_locale,
  9. )
  10. import pandas as pd
  11. _all_locales = get_locales()
  12. _current_locale = locale.setlocale(locale.LC_ALL) # getlocale() is wrong, see GH#46595
  13. # Don't run any of these tests if we have no locales.
  14. pytestmark = pytest.mark.skipif(not _all_locales, reason="Need locales")
  15. _skip_if_only_one_locale = pytest.mark.skipif(
  16. len(_all_locales) <= 1, reason="Need multiple locales for meaningful test"
  17. )
  18. def _get_current_locale(lc_var: int = locale.LC_ALL) -> str:
  19. # getlocale is not always compliant with setlocale, use setlocale. GH#46595
  20. return locale.setlocale(lc_var)
  21. @pytest.mark.parametrize("lc_var", (locale.LC_ALL, locale.LC_CTYPE, locale.LC_TIME))
  22. def test_can_set_current_locale(lc_var):
  23. # Can set the current locale
  24. before_locale = _get_current_locale(lc_var)
  25. assert can_set_locale(before_locale, lc_var=lc_var)
  26. after_locale = _get_current_locale(lc_var)
  27. assert before_locale == after_locale
  28. @pytest.mark.parametrize("lc_var", (locale.LC_ALL, locale.LC_CTYPE, locale.LC_TIME))
  29. def test_can_set_locale_valid_set(lc_var):
  30. # Can set the default locale.
  31. before_locale = _get_current_locale(lc_var)
  32. assert can_set_locale("", lc_var=lc_var)
  33. after_locale = _get_current_locale(lc_var)
  34. assert before_locale == after_locale
  35. @pytest.mark.parametrize("lc_var", (locale.LC_ALL, locale.LC_CTYPE, locale.LC_TIME))
  36. def test_can_set_locale_invalid_set(lc_var):
  37. # Cannot set an invalid locale.
  38. before_locale = _get_current_locale(lc_var)
  39. assert not can_set_locale("non-existent_locale", lc_var=lc_var)
  40. after_locale = _get_current_locale(lc_var)
  41. assert before_locale == after_locale
  42. @pytest.mark.parametrize(
  43. "lang,enc",
  44. [
  45. ("it_CH", "UTF-8"),
  46. ("en_US", "ascii"),
  47. ("zh_CN", "GB2312"),
  48. ("it_IT", "ISO-8859-1"),
  49. ],
  50. )
  51. @pytest.mark.parametrize("lc_var", (locale.LC_ALL, locale.LC_CTYPE, locale.LC_TIME))
  52. def test_can_set_locale_no_leak(lang, enc, lc_var):
  53. # Test that can_set_locale does not leak even when returning False. See GH#46595
  54. before_locale = _get_current_locale(lc_var)
  55. can_set_locale((lang, enc), locale.LC_ALL)
  56. after_locale = _get_current_locale(lc_var)
  57. assert before_locale == after_locale
  58. def test_can_set_locale_invalid_get(monkeypatch):
  59. # see GH#22129
  60. # In some cases, an invalid locale can be set,
  61. # but a subsequent getlocale() raises a ValueError.
  62. def mock_get_locale():
  63. raise ValueError()
  64. with monkeypatch.context() as m:
  65. m.setattr(locale, "getlocale", mock_get_locale)
  66. assert not can_set_locale("")
  67. def test_get_locales_at_least_one():
  68. # see GH#9744
  69. assert len(_all_locales) > 0
  70. @_skip_if_only_one_locale
  71. def test_get_locales_prefix():
  72. first_locale = _all_locales[0]
  73. assert len(get_locales(prefix=first_locale[:2])) > 0
  74. @_skip_if_only_one_locale
  75. @pytest.mark.parametrize(
  76. "lang,enc",
  77. [
  78. ("it_CH", "UTF-8"),
  79. ("en_US", "ascii"),
  80. ("zh_CN", "GB2312"),
  81. ("it_IT", "ISO-8859-1"),
  82. ],
  83. )
  84. def test_set_locale(lang, enc):
  85. before_locale = _get_current_locale()
  86. enc = codecs.lookup(enc).name
  87. new_locale = lang, enc
  88. if not can_set_locale(new_locale):
  89. msg = "unsupported locale setting"
  90. with pytest.raises(locale.Error, match=msg):
  91. with set_locale(new_locale):
  92. pass
  93. else:
  94. with set_locale(new_locale) as normalized_locale:
  95. new_lang, new_enc = normalized_locale.split(".")
  96. new_enc = codecs.lookup(enc).name
  97. normalized_locale = new_lang, new_enc
  98. assert normalized_locale == new_locale
  99. # Once we exit the "with" statement, locale should be back to what it was.
  100. after_locale = _get_current_locale()
  101. assert before_locale == after_locale
  102. def test_encoding_detected():
  103. system_locale = os.environ.get("LC_ALL")
  104. system_encoding = system_locale.split(".")[-1] if system_locale else "utf-8"
  105. assert (
  106. codecs.lookup(pd.options.display.encoding).name
  107. == codecs.lookup(system_encoding).name
  108. )