From a2ebb7e20b4897ee7b7bf4676a5ac3e6c0f27f47 Mon Sep 17 00:00:00 2001 From: Anish Nyayachavadi <55898433+anishnya@users.noreply.github.com> Date: Sat, 18 Dec 2021 14:18:51 -0500 Subject: [PATCH] Dehumanize Support for Slavic Locales (#1077) --- arrow/arrow.py | 2 +- arrow/constants.py | 13 +++++++++ arrow/locales.py | 11 ++++++- tests/test_arrow.py | 71 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 2 deletions(-) diff --git a/arrow/arrow.py b/arrow/arrow.py index fef66c10..d7504456 100644 --- a/arrow/arrow.py +++ b/arrow/arrow.py @@ -1384,7 +1384,7 @@ def dehumanize(self, input_string: str, locale: str = "en_us") -> "Arrow": search_string = search_string.format(r"\d+") # Create search pattern and find within string - pattern = re.compile(fr"{search_string}") + pattern = re.compile(fr"(^|\b|\d){search_string}") match = pattern.search(input_string) # If there is no match continue to next iteration diff --git a/arrow/constants.py b/arrow/constants.py index 008e8b7a..d26bc0d8 100644 --- a/arrow/constants.py +++ b/arrow/constants.py @@ -73,7 +73,20 @@ "zh-hk", "nl", "nl-nl", + "be", + "be-by", + "pl", + "pl-pl", + "ru", + "ru-ru", "af", + "bg", + "bg-bg", + "ua", + "uk", + "uk-ua", + "mk", + "mk-mk", "de", "de-de", "de-ch", diff --git a/arrow/locales.py b/arrow/locales.py index 2698074c..6b1627e7 100644 --- a/arrow/locales.py +++ b/arrow/locales.py @@ -172,7 +172,16 @@ def describe_multi( humanized = " ".join(parts) if not only_distance: - humanized = self._format_relative(humanized, *timeframes[-1]) + # Needed to determine the correct relative string to use + timeframe_value = 0 + + for _unit_name, unit_value in timeframes: + if trunc(unit_value) != 0: + timeframe_value = trunc(unit_value) + break + + # Note it doesn't matter the timeframe unit we use on the call, only the value + humanized = self._format_relative(humanized, "seconds", timeframe_value) return humanized diff --git a/tests/test_arrow.py b/tests/test_arrow.py index 7cb3b510..a2f08813 100644 --- a/tests/test_arrow.py +++ b/tests/test_arrow.py @@ -2373,7 +2373,20 @@ def locale_list_no_weeks() -> List[str]: "zh-hk", "nl", "nl-nl", + "be", + "be-by", + "pl", + "pl-pl", + "ru", + "ru-ru", "af", + "bg", + "bg-bg", + "ua", + "uk", + "uk-ua", + "mk", + "mk-mk", "de", "de-de", "de-ch", @@ -2485,6 +2498,12 @@ def locale_list_with_weeks() -> List[str]: "zh-hk", "nl", "nl-nl", + "pl", + "pl-pl", + "ru", + "ru-ru", + "mk", + "mk-mk", "de", "de-de", "de-ch", @@ -2520,6 +2539,27 @@ def locale_list_with_weeks() -> List[str]: return tested_langs +@pytest.fixture(scope="class") +def slavic_locales() -> List[str]: + tested_langs = [ + "be", + "be-by", + "pl", + "pl-pl", + "ru", + "ru-ru", + "bg", + "bg-bg", + "ua", + "uk", + "uk-ua", + "mk", + "mk-mk", + ] + + return tested_langs + + class TestArrowDehumanize: def test_now(self, locale_list_no_weeks: List[str]): @@ -2883,6 +2923,37 @@ def test_no_units_modified(self, locale_list_no_weeks: List[str]): with pytest.raises(ValueError): arw.dehumanize(empty_future_string, locale=lang) + def test_slavic_locales(self, slavic_locales: List[str]): + + # Relevant units for Slavic locale plural logic + units = [ + 0, + 1, + 2, + 5, + 21, + 22, + 25, + ] + + # Only need to test on seconds as logic holds for all slavic plural units + for lang in slavic_locales: + for unit in units: + arw = arrow.Arrow(2000, 2, 18, 1, 50, 30) + + past = arw.shift(minutes=-1 * unit, days=-1) + future = arw.shift(minutes=unit, days=1) + + past_string = past.humanize( + arw, locale=lang, granularity=["minute", "day"] + ) + future_string = future.humanize( + arw, locale=lang, granularity=["minute", "day"] + ) + + assert arw.dehumanize(past_string, locale=lang) == past + assert arw.dehumanize(future_string, locale=lang) == future + class TestArrowIsBetween: def test_start_before_end(self):