From 1a050711af1070cc28484d546c68cc1ec6fd67f5 Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Sat, 27 Nov 2021 14:30:29 +0000 Subject: [PATCH 1/4] address type errors in 'cleo._utils' --- cleo/_utils.py | 57 +++++++++++++++++++++++++++----------------------- pyproject.toml | 1 - 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/cleo/_utils.py b/cleo/_utils.py index 527a6f91..9efc165c 100644 --- a/cleo/_utils.py +++ b/cleo/_utils.py @@ -2,8 +2,8 @@ import math +from dataclasses import dataclass from html.parser import HTMLParser -from typing import Any from pylev import levenshtein @@ -13,22 +13,22 @@ def __init__(self) -> None: super().__init__(convert_charrefs=False) self.reset() - self.fed = [] + self.fed: list[str] = [] - def handle_data(self, d) -> None: + def handle_data(self, d: str) -> None: self.fed.append(d) - def handle_entityref(self, name) -> None: + def handle_entityref(self, name: str) -> None: self.fed.append("&%s;" % name) - def handle_charref(self, name) -> None: + def handle_charref(self, name: str) -> None: self.fed.append("&#%s;" % name) def get_data(self) -> str: return "".join(self.fed) -def _strip(value) -> str: +def _strip(value: str) -> str: s = TagStripper() s.feed(value) s.close() @@ -36,8 +36,7 @@ def _strip(value) -> str: return s.get_data() -def strip_tags(value: Any) -> str: - value = str(value) +def strip_tags(value: str) -> str: while "<" in value and ">" in value: new_value = _strip(value) if value.count("<") == new_value.count("<"): @@ -82,25 +81,31 @@ def find_similar_names(name: str, names: list[str]) -> list[str]: return suggested_names -_TIME_FORMATS = [ - (0, "< 1 sec"), - (2, "1 sec"), - (59, "secs", 1), - (60, "1 min"), - (3600, "mins", 60), - (5400, "1 hr"), - (86400, "hrs", 3600), - (129600, "1 day"), - (604800, "days", 86400), +@dataclass +class TimeFormat: + threshold: int + alias: str + divisor: int | None = None + + def apply(self, secs: float) -> str: + if self.divisor: + return f"{math.ceil(secs / self.divisor)} {self.alias}" + return self.alias + + +_TIME_FORMATS: list[TimeFormat] = [ + TimeFormat(0, "< 1 sec"), + TimeFormat(2, "1 sec"), + TimeFormat(59, "secs", 1), + TimeFormat(60, "1 min"), + TimeFormat(3600, "mins", 60), + TimeFormat(5400, "1 hr"), + TimeFormat(86400, "hrs", 3600), + TimeFormat(129600, "1 day"), + TimeFormat(604800, "days", 86400), ] def format_time(secs: float) -> str: - for fmt in _TIME_FORMATS: - if secs > fmt[0]: - continue - - if len(fmt) == 2: - return fmt[1] - - return f"{math.ceil(secs / fmt[2])} {fmt[1]}" + format = next(fmt for fmt in _TIME_FORMATS if secs < fmt.threshold) + return format.apply(secs) diff --git a/pyproject.toml b/pyproject.toml index d2fa0169..66187398 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,6 @@ files = "cleo, tests" [[tool.mypy.overrides]] module = [ - "cleo._utils", "cleo.application", "cleo.descriptors.application_description", "cleo.descriptors.descriptor", From 786bc3f1bb1248d014cccdbf31cbf13ab4bc142f Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Fri, 3 Jun 2022 06:05:17 +0100 Subject: [PATCH 2/4] add 'time_format' test --- cleo/_utils.py | 2 +- pyproject.toml | 1 + tests/test_utils.py | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/test_utils.py diff --git a/cleo/_utils.py b/cleo/_utils.py index 9efc165c..dfdcb6e3 100644 --- a/cleo/_utils.py +++ b/cleo/_utils.py @@ -107,5 +107,5 @@ def apply(self, secs: float) -> str: def format_time(secs: float) -> str: - format = next(fmt for fmt in _TIME_FORMATS if secs < fmt.threshold) + format = next(fmt for fmt in _TIME_FORMATS if secs <= fmt.threshold) return format.apply(secs) diff --git a/pyproject.toml b/pyproject.toml index 66187398..e3ec845b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,6 +92,7 @@ module = [ "tests.test_parser", "tests.testers.*", "tests.ui.*", + "tests.test_utils", ] ignore_errors = true diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 00000000..a0d56e19 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,14 @@ +from cleo._utils import format_time +import pytest + + +@pytest.mark.parametrize("input_secs,expected", [ + (0.1, "< 1 sec"), + (1.0, "1 sec"), + (2.0, "2 secs"), + (59.0, "59 secs"), + (60.0, "1 min"), + (120.0, "2 mins"), +]) +def test_format_time(input_secs: float, expected: str) -> None: + assert format_time(input_secs) == expected From 627c04d8820f08f05163818304742e73fae85eb2 Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Fri, 3 Jun 2022 06:12:31 +0100 Subject: [PATCH 3/4] fixup --- pyproject.toml | 2 +- tests/test_utils.py | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e3ec845b..c40018e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ known_first_party = "cleo" [tool.mypy] strict = true files = "cleo, tests" +show_error_codes = true # The following whitelist is used to allow for incremental adoption # of Mypy. Modules should be removed from this whitelist as and when @@ -92,7 +93,6 @@ module = [ "tests.test_parser", "tests.testers.*", "tests.ui.*", - "tests.test_utils", ] ignore_errors = true diff --git a/tests/test_utils.py b/tests/test_utils.py index a0d56e19..dbf5fd21 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,14 +1,20 @@ -from cleo._utils import format_time +from __future__ import annotations + import pytest +from cleo._utils import format_time + -@pytest.mark.parametrize("input_secs,expected", [ - (0.1, "< 1 sec"), - (1.0, "1 sec"), - (2.0, "2 secs"), - (59.0, "59 secs"), - (60.0, "1 min"), - (120.0, "2 mins"), -]) +@pytest.mark.parametrize( # type: ignore[misc] + "input_secs,expected", + [ + (0.1, "< 1 sec"), + (1.0, "1 sec"), + (2.0, "2 secs"), + (59.0, "59 secs"), + (60.0, "1 min"), + (120.0, "2 mins"), + ], +) def test_format_time(input_secs: float, expected: str) -> None: assert format_time(input_secs) == expected From 1885fb63c2ce2320499677061b4c8055cdc51b43 Mon Sep 17 00:00:00 2001 From: Bartek Sokorski Date: Mon, 5 Sep 2022 00:52:01 +0200 Subject: [PATCH 4/4] Fix bug and add more test cases --- src/cleo/_utils.py | 19 ++++++++++--------- tests/test_utils.py | 9 +++++++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/cleo/_utils.py b/src/cleo/_utils.py index c654d238..e0960996 100644 --- a/src/cleo/_utils.py +++ b/src/cleo/_utils.py @@ -71,9 +71,8 @@ def find_similar_names(name: str, names: list[str]) -> list[str]: distance_by_name = { k: v for k, v in distance_by_name.items() if v[0] < 2 * threshold } - # Display results with shortest distance first - return sorted(distance_by_name, key=distance_by_name.get) + return sorted(distance_by_name, key=lambda x: distance_by_name[x]) @dataclass @@ -89,18 +88,20 @@ def apply(self, secs: float) -> str: _TIME_FORMATS: list[TimeFormat] = [ - TimeFormat(0, "< 1 sec"), + TimeFormat(1, "< 1 sec"), TimeFormat(2, "1 sec"), - TimeFormat(59, "secs", 1), - TimeFormat(60, "1 min"), + TimeFormat(60, "secs", 1), + TimeFormat(61, "1 min"), TimeFormat(3600, "mins", 60), - TimeFormat(5400, "1 hr"), + TimeFormat(5401, "1 hr"), TimeFormat(86400, "hrs", 3600), - TimeFormat(129600, "1 day"), - TimeFormat(604800, "days", 86400), + TimeFormat(129601, "1 day"), + TimeFormat(604801, "days", 86400), ] def format_time(secs: float) -> str: - format = next(fmt for fmt in _TIME_FORMATS if secs <= fmt.threshold) + format = next( + (fmt for fmt in _TIME_FORMATS if secs < fmt.threshold), _TIME_FORMATS[-1] + ) return format.apply(secs) diff --git a/tests/test_utils.py b/tests/test_utils.py index 0b72fe72..999e0d6e 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -6,8 +6,8 @@ from cleo._utils import format_time -@pytest.mark.parametrize( # type: ignore[misc] - "input_secs,expected", +@pytest.mark.parametrize( + ["input_secs", "expected"], [ (0.1, "< 1 sec"), (1.0, "1 sec"), @@ -15,6 +15,11 @@ (59.0, "59 secs"), (60.0, "1 min"), (120.0, "2 mins"), + (3600.0, "1 hr"), + (7200.0, "2 hrs"), + (129600.0, "1 day"), + (129601.0, "2 days"), + (700000.0, "9 days"), ], ) def test_format_time(input_secs: float, expected: str) -> None: