diff --git a/src/hamcrest/core/__init__.py b/src/hamcrest/core/__init__.py index d71b14b7..081ca55e 100644 --- a/src/hamcrest/core/__init__.py +++ b/src/hamcrest/core/__init__.py @@ -1,5 +1,6 @@ from hamcrest.core.assert_that import assert_that from hamcrest.core.core import * +from hamcrest.core.locale import set_locale, get_locale __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" diff --git a/src/hamcrest/core/assert_that.py b/src/hamcrest/core/assert_that.py index c8882bb5..a7320067 100644 --- a/src/hamcrest/core/assert_that.py +++ b/src/hamcrest/core/assert_that.py @@ -1,8 +1,9 @@ import warnings from typing import Optional, TypeVar, cast, overload +from hamcrest.core.locale import get_locale from hamcrest.core.matcher import Matcher -from hamcrest.core.string_description import StringDescription +from hamcrest.core.localized_description import LocalizedDescription __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" @@ -64,10 +65,10 @@ def assert_that(actual, matcher=None, reason=""): def _assert_match(actual: T, matcher: Matcher[T], reason: str) -> None: if not matcher.matches(actual): - description = StringDescription() - description.append_text(reason).append_text("\nExpected: ").append_description_of( - matcher - ).append_text("\n but: ") + description = LocalizedDescription(locale=get_locale()) + description.append_text(reason).append_text("\n") \ + .append_text("Expected: ").append_description_of(matcher) \ + .append_text("\n").append_text(" but: ") matcher.describe_mismatch(actual, description) description.append_text("\n") raise AssertionError(description) diff --git a/src/hamcrest/core/base_matcher.py b/src/hamcrest/core/base_matcher.py index c1c01ea4..07bb5081 100644 --- a/src/hamcrest/core/base_matcher.py +++ b/src/hamcrest/core/base_matcher.py @@ -2,7 +2,7 @@ from hamcrest.core.description import Description from hamcrest.core.matcher import Matcher -from hamcrest.core.string_description import tostring +from hamcrest.core.localized_description import tostring __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" diff --git a/src/hamcrest/core/locale.py b/src/hamcrest/core/locale.py new file mode 100644 index 00000000..7d4afceb --- /dev/null +++ b/src/hamcrest/core/locale.py @@ -0,0 +1,41 @@ +__author__ = "Majority Judgment" +__copyright__ = "Copyright 2011 hamcrest.org" +__license__ = "BSD, see License.txt" + + +_locale = "en_US" + + +def set_locale(new_locale): + global _locale # :(|) + _locale = new_locale + + +def get_locale(): + global _locale # :(|) + return _locale + + +class LocaleLazyLoader(object): + + # FIXME + # locales = dict() + locales = { + 'fr_FR': { + 'Butterfly': 'Papillon', + 'ENGLISH DESCRIPTION': 'DESCRIPTION FRANÇAISE', + + 'Assertion failed': "Échec d'une assertion", + 'Expected: ': 'Attendu⋅e: ', + ' but: ': ' mais: ', + 'was ': "obtenu⋅e ", + }, + } + + def get_locale_map(self, locale): + if locale not in self.locales: + self.locales[locale] = dict() + return self.locales[locale] + + +locale_loader = LocaleLazyLoader() diff --git a/src/hamcrest/core/localized_description.py b/src/hamcrest/core/localized_description.py new file mode 100644 index 00000000..6feecd4f --- /dev/null +++ b/src/hamcrest/core/localized_description.py @@ -0,0 +1,40 @@ +from typing import Any, Iterable + +from hamcrest.core.description import Description +from hamcrest.core.locale import get_locale, locale_loader +from hamcrest.core.selfdescribing import SelfDescribing +from hamcrest.core.string_description import StringDescription + +__author__ = "Majority Judgment" +__copyright__ = "Copyright 2011 hamcrest.org" +__license__ = "BSD, see License.txt" + + +def tostring(selfdescribing: SelfDescribing) -> str: + """Returns the description of a + :py:class:`~hamcrest.core.selfdescribing.SelfDescribing` object as a + localized string. + + :param selfdescribing: The object to be described. + :returns: The description of the object. + """ + return str(LocalizedDescription().append_description_of(selfdescribing)) + + +class LocalizedDescription(StringDescription): + """Implementation of a localized :py:class:`~hamcrest.core.description.Description` + implementations. + """ + + def __init__(self, locale=None) -> None: + super().__init__() + if locale is None: + locale = get_locale() + self.locale = locale + self.locale_map = locale_loader.get_locale_map(self.locale) + + def append_text(self, text: str) -> Description: + if text in self.locale_map: + text = self.locale_map[text] + self.append(text) + return self diff --git a/src/hamcrest/library/integration/match_equality.py b/src/hamcrest/library/integration/match_equality.py index 33494ef2..8c422343 100644 --- a/src/hamcrest/library/integration/match_equality.py +++ b/src/hamcrest/library/integration/match_equality.py @@ -2,7 +2,7 @@ from hamcrest.core.helpers.wrap_matcher import wrap_matcher from hamcrest.core.matcher import Matcher -from hamcrest.core.string_description import tostring +from hamcrest.core.localized_description import tostring __author__ = "Chris Rose" __copyright__ = "Copyright 2011 hamcrest.org" diff --git a/src/hamcrest/library/object/hasproperty.py b/src/hamcrest/library/object/hasproperty.py index b27036dc..445eb7d2 100644 --- a/src/hamcrest/library/object/hasproperty.py +++ b/src/hamcrest/library/object/hasproperty.py @@ -6,8 +6,8 @@ from hamcrest.core.core.allof import AllOf from hamcrest.core.description import Description from hamcrest.core.helpers.wrap_matcher import wrap_matcher as wrap_shortcut +from hamcrest.core.localized_description import LocalizedDescription from hamcrest.core.matcher import Matcher -from hamcrest.core.string_description import StringDescription __author__ = "Chris Rose" __copyright__ = "Copyright 2011 hamcrest.org" @@ -54,7 +54,7 @@ def describe_mismatch(self, item: object, mismatch_description: Description) -> self.value_matcher.describe_mismatch(value, mismatch_description) def __str__(self): - d = StringDescription() + d = LocalizedDescription() self.describe_to(d) return str(d) @@ -178,7 +178,7 @@ def has_properties(*keys_valuematchers, **kv_args): base_dict[key] = wrap_shortcut(value) if len(base_dict) > 1: - description = StringDescription().append_text("an object with properties ") + description = LocalizedDescription().append_text("an object with properties ") for i, (property_name, property_value_matcher) in enumerate(sorted(base_dict.items())): description.append_description_of(property_name).append_text( " matching " diff --git a/tests/hamcrest_unit_test/localized_description_test.py b/tests/hamcrest_unit_test/localized_description_test.py new file mode 100644 index 00000000..57a99ba7 --- /dev/null +++ b/tests/hamcrest_unit_test/localized_description_test.py @@ -0,0 +1,61 @@ +import re +import unittest +import pytest + +from hamcrest.core.selfdescribing import SelfDescribing +from hamcrest.core.string_description import * +from hamcrest.core.localized_description import * + + +__author__ = "Majority Judgment" +__copyright__ = "Copyright 2011 hamcrest.org" +__license__ = "BSD, see License.txt" + + +class FakeSelfDescribing(SelfDescribing): + def describe_to(self, description): + description.append_text("ENGLISH DESCRIPTION") + + +class LocalizedDescriptionTest(unittest.TestCase): + def setUp(self): + self.description = LocalizedDescription(locale='fr_FR') + + def testLetsSelfDescribingObjectDescribeItself(self): + self.description.append_description_of(FakeSelfDescribing()) + self.assertEqual("DESCRIPTION FRANÇAISE", str(self.description)) + + def testNoL10nWhenDescribesStringInQuotes(self): + self.description.append_description_of("Butterfly") + self.assertEqual("'Butterfly'", str(self.description)) + + def testNoL10nWhenSelfDescribingObjectInAngleBrackets(self): + self.description.append_description_of(42) + self.assertEqual("<42>", str(self.description)) + + def testShouldNotAddAngleBracketsIfObjectDescriptionAlreadyHasThem(self): + self.description.append_description_of(object()) + expected = re.compile("") + self.assertTrue(expected.match(str(self.description))) + + def testDescribeUnicodeStringAsUnicode(self): + self.description.append_description_of("\u05d0") + self.assertEqual("'\u05d0'", str(self.description)) + + +# below is a set of things that should append without error to string +# descriptions +@pytest.mark.parametrize("valid_input", (b"bytes", "unicode")) +def test_description_append_valid_input(valid_input): + desc = LocalizedDescription() + desc.append(valid_input) + str(desc) + + +def test_description_append_invalid_input(): + desc = LocalizedDescription() + desc.append(chr(239)) + + +if __name__ == "__main__": + unittest.main()