diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index f338589..0000000 --- a/.coveragerc +++ /dev/null @@ -1,11 +0,0 @@ -# .coveragerc to control coverage.py - -[report] -# Regexes for lines to exclude from consideration -exclude_also = - # Don't complain if non-runnable code isn't run: - if TYPE_CHECKING: - -[run] -disable_warnings = - no-sysmon diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 42d4542..7a28ea0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,8 +1,8 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.2 + rev: v0.12.10 hooks: - - id: ruff + - id: ruff-check args: [--exit-non-zero-on-fix] - repo: https://github.com/psf/black-pre-commit-mirror @@ -11,7 +11,7 @@ repos: - id: black - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: check-added-large-files - id: check-case-conflict @@ -27,7 +27,7 @@ repos: exclude: \.github/ISSUE_TEMPLATE\.md|\.github/PULL_REQUEST_TEMPLATE\.md - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.33.2 + rev: 0.33.3 hooks: - id: check-github-workflows - id: check-renovate @@ -38,7 +38,7 @@ repos: - id: actionlint - repo: https://github.com/woodruffw/zizmor-pre-commit - rev: v1.11.0 + rev: v1.12.1 hooks: - id: zizmor @@ -53,7 +53,7 @@ repos: - id: validate-pyproject - repo: https://github.com/tox-dev/tox-ini-fmt - rev: 1.5.0 + rev: 1.6.0 hooks: - id: tox-ini-fmt diff --git a/pyproject.toml b/pyproject.toml index 46e0e15..d332764 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,7 +65,7 @@ fix = true lint.select = [ "C4", # flake8-comprehensions "D", # pydocstyle - "E", # pycodestyle + "E", # pycodestyle errors "EM", # flake8-errmsg "F", # pyflakes "I", # isort @@ -73,25 +73,29 @@ lint.select = [ "ISC", # flake8-implicit-str-concat "LOG", # flake8-logging "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PT", # flake8-pytest-style "PYI", # flake8-pyi "RUF022", # unsorted-dunder-all "RUF100", # unused noqa (yesqa) "UP", # pyupgrade - "W", # pycodestyle + "W", # pycodestyle warnings "YTT", # flake8-2020 ] lint.ignore = [ - "E203", # Whitespace before ':' - "E221", # Multiple spaces before operator - "E226", # Missing whitespace around arithmetic operator - "E241", # Multiple spaces after ',' - "UP038", # Makes code slower and more verbose + "E203", # Whitespace before ':' + "E221", # Multiple spaces before operator + "E226", # Missing whitespace around arithmetic operator + "E241", # Multiple spaces after ',' + "PIE790", # flake8-pie: unnecessary-placeholder + "UP038", # Makes code slower and more verbose ] lint.per-file-ignores."tests/*" = [ "D", ] lint.flake8-import-conventions.aliases.datetime = "dt" lint.flake8-import-conventions.banned-from = [ "datetime" ] +lint.flake8-pytest-style.parametrize-names-type = "csv" lint.isort.known-first-party = [ "humanize" ] lint.isort.required-imports = [ "from __future__ import annotations" ] lint.pydocstyle.convention = "google" @@ -103,11 +107,16 @@ max_supported_python = "3.14" addopts = "--color=yes" filterwarnings = [ "error", - # https://github.com/dateutil/dateutil/issues/1314 - "ignore:datetime.datetime.utcfromtimestamp:DeprecationWarning:dateutil.tz.tz", ] testpaths = [ "tests" ] +[tool.coverage.report] +# Regexes for lines to exclude from consideration +exclude_also = [ + # Don't complain if non-runnable code isn't run: + "if __name__ == .__main__.:", +] + [tool.mypy] pretty = true strict = true diff --git a/tests/test_i18n.py b/tests/test_i18n.py index ab9f419..d4204f2 100644 --- a/tests/test_i18n.py +++ b/tests/test_i18n.py @@ -89,15 +89,15 @@ def test_naturaldelta() -> None: @pytest.mark.parametrize( - ("locale", "number", "expected_result"), - ( + "locale, number, expected_result", + [ ("es_ES", 1000000, "1.0 millón"), ("es_ES", 3500000, "3.5 millones"), ("es_ES", 1000000000, "1.0 billón"), ("es_ES", 1200000000, "1.2 billones"), ("es_ES", 1000000000000, "1.0 trillón"), ("es_ES", 6700000000000, "6.7 trillones"), - ), + ], ) def test_intword_plurals(locale: str, number: int, expected_result: str) -> None: try: @@ -111,8 +111,8 @@ def test_intword_plurals(locale: str, number: int, expected_result: str) -> None @pytest.mark.parametrize( - ("locale", "expected_result"), - ( + "locale, expected_result", + [ ("ar", "5خامس"), ("ar_SA", "5خامس"), ("fr", "5e"), @@ -120,7 +120,7 @@ def test_intword_plurals(locale: str, number: int, expected_result: str) -> None ("pt", "5º"), ("pt_BR", "5º"), ("pt_PT", "5º"), - ), + ], ) def test_langauge_codes(locale: str, expected_result: str) -> None: try: @@ -134,8 +134,8 @@ def test_langauge_codes(locale: str, expected_result: str) -> None: @pytest.mark.parametrize( - ("locale", "number", "gender", "expected_result"), - ( + "locale, number, gender, expected_result", + [ ("fr_FR", 1, "male", "1er"), ("fr_FR", 1, "female", "1ère"), ("fr_FR", 2, "male", "2e"), @@ -143,7 +143,7 @@ def test_langauge_codes(locale: str, expected_result: str) -> None: ("es_ES", 5, "female", "5ª"), ("it_IT", 3, "male", "3º"), ("it_IT", 8, "female", "8ª"), - ), + ], ) def test_ordinal_genders( locale: str, number: int, gender: str, expected_result: str @@ -187,9 +187,8 @@ def test_default_locale_path_null__spec__( i18n = importlib.import_module("humanize.i18n") monkeypatch.setattr(i18n, "__spec__", None) - with pytest.raises(Exception) as excinfo: + with pytest.raises(Exception, match=self.expected_msg): i18n.activate("ru_RU") - assert str(excinfo.value) == self.expected_msg def test_default_locale_path_undefined__spec__( self, monkeypatch: pytest.MonkeyPatch @@ -197,9 +196,8 @@ def test_default_locale_path_undefined__spec__( i18n = importlib.import_module("humanize.i18n") monkeypatch.delattr(i18n, "__spec__") - with pytest.raises(Exception) as excinfo: + with pytest.raises(Exception, match=self.expected_msg): i18n.activate("ru_RU") - assert str(excinfo.value) == self.expected_msg @freeze_time("2020-02-02") def test_en_locale(self) -> None: diff --git a/tests/test_time.py b/tests/test_time.py index 70ea10c..70c2bd5 100644 --- a/tests/test_time.py +++ b/tests/test_time.py @@ -106,17 +106,9 @@ def test_naturaldelta_nomonths(test_input: dt.timedelta, expected: str) -> None: (dt.timedelta(days=365 * 2 + 35), "2 years"), (dt.timedelta(seconds=1), "a second"), (dt.timedelta(seconds=30), "30 seconds"), - (dt.timedelta(minutes=1, seconds=30), "a minute"), - (dt.timedelta(minutes=2), "2 minutes"), - (dt.timedelta(hours=1, minutes=30, seconds=30), "an hour"), - (dt.timedelta(hours=23, minutes=50, seconds=50), "23 hours"), - (dt.timedelta(days=1), "a day"), - (dt.timedelta(days=500), "1 year, 4 months"), - (dt.timedelta(days=365 * 2 + 35), "2 years"), # regression tests for bugs in post-release humanize (dt.timedelta(days=10000), "27 years"), (dt.timedelta(days=365 + 35), "1 year, 1 month"), - (30, "30 seconds"), (dt.timedelta(days=365 * 2 + 65), "2 years"), (dt.timedelta(days=365 + 4), "1 year, 4 days"), (dt.timedelta(days=35), "a month"), @@ -763,10 +755,13 @@ def test_precisedelta_suppress_units( def test_precisedelta_bogus_call() -> None: assert humanize.precisedelta(None) == "None" - with pytest.raises(ValueError): + with pytest.raises( + ValueError, + match="Minimum unit is suppressed and no suitable replacement was found", + ): humanize.precisedelta(1, minimum_unit="years", suppress=["years"]) - with pytest.raises(ValueError): + with pytest.raises(ValueError, match="Minimum unit 'years' not supported"): humanize.naturaldelta(1, minimum_unit="years") diff --git a/tox.ini b/tox.ini index 2af59ef..bb7e6c1 100644 --- a/tox.ini +++ b/tox.ini @@ -12,8 +12,6 @@ extras = tests pass_env = FORCE_COLOR -set_env = - COVERAGE_CORE = sysmon commands = {envpython} -m pytest \ --cov humanize \