From f38a657ba6674fc3ce5009d9d0a0e221764ccf52 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 30 Aug 2020 20:36:40 +0300 Subject: [PATCH 1/5] Update README following PR 142 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5ebeab8c..188babf1 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ If seconds are too large, set `minimum_unit` to milliseconds or microseconds: >>> humanize.naturaldelta(delta, minimum_unit="milliseconds") '4 milliseconds' >>> humanize.naturaldelta(delta, minimum_unit="microseconds") -'4000 microseconds' +'4 milliseconds' ``` ```pycon >>> humanize.naturaltime(delta) @@ -112,7 +112,7 @@ If seconds are too large, set `minimum_unit` to milliseconds or microseconds: >>> humanize.naturaltime(delta, minimum_unit="milliseconds") '4 milliseconds ago' >>> humanize.naturaltime(delta, minimum_unit="microseconds") -'4000 microseconds ago' +'4 milliseconds ago' ``` ### File size humanization From 97cc6962465b659996134fbf102e7dea72d3fa95 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 30 Aug 2020 20:37:14 +0300 Subject: [PATCH 2/5] Link RTD's API reference and README's usage --- README.md | 4 ++++ docs/index.md | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 188babf1..2c98ab0d 100644 --- a/README.md +++ b/README.md @@ -208,3 +208,7 @@ Where `` is a locale abbreviation, eg. `en_GB`, `pt_BR` or just `ru etc. List the language at the top of this README. + +## API reference + +[https://python-humanize.readthedocs.io](https://python-humanize.readthedocs.io) diff --git a/docs/index.md b/docs/index.md index 4ea337ff..f75fa241 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,5 +7,5 @@ Welcome to the humanize API reference. * [Filesize](filesize) * [I18n](i18n) -Or see [README.md](https://github.com/jmoiron/humanize/blob/master/README.md) -for usage examples. +For usage examples see +[README.md](https://github.com/jmoiron/humanize/blob/master/README.md). From 307c04894698534c754ec8e65b376807c798fa56 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sun, 30 Aug 2020 22:15:34 +0300 Subject: [PATCH 3/5] Fix 'pydocstyle --convention google' warnings --- .pre-commit-config.yaml | 7 +++ setup.cfg | 3 + src/humanize/__init__.py | 1 + src/humanize/i18n.py | 3 +- src/humanize/time.py | 120 +++++++++++++++++++-------------------- 5 files changed, 70 insertions(+), 64 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e594cf37..e21eccf6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,3 +33,10 @@ repos: - id: check-merge-conflict - id: check-toml - id: check-yaml + + - repo: https://github.com/PyCQA/pydocstyle + rev: 5.1.1 + hooks: + - id: pydocstyle + args: ["--convention", "google"] + files: "src/" diff --git a/setup.cfg b/setup.cfg index 4a0d6ded..107d9e61 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,9 @@ [flake8] max_line_length = 88 +[pydocstyle] +convention = google + [tool:isort] known_third_party = freezegun,humanize,pkg_resources,pytest,setuptools force_grid_wrap = 0 diff --git a/src/humanize/__init__.py b/src/humanize/__init__.py index 34f0bb59..44d7c1d7 100644 --- a/src/humanize/__init__.py +++ b/src/humanize/__init__.py @@ -1,3 +1,4 @@ +"""Main package for humanize.""" import pkg_resources from humanize.filesize import naturalsize from humanize.i18n import activate, deactivate diff --git a/src/humanize/i18n.py b/src/humanize/i18n.py index 05438c38..086f75d4 100644 --- a/src/humanize/i18n.py +++ b/src/humanize/i18n.py @@ -1,3 +1,4 @@ +"""Activate, get and deactivate translations.""" import gettext as gettext_module import os.path from threading import local @@ -69,7 +70,7 @@ def gettext(message): def pgettext(msgctxt, message): - """'Particular gettext' function. + """Fetches a particular translation. It works with `msgctxt` .po modifiers and allows duplicate keys with different translations. diff --git a/src/humanize/time.py b/src/humanize/time.py index e5903862..f75e4dd8 100644 --- a/src/humanize/time.py +++ b/src/humanize/time.py @@ -1,7 +1,9 @@ #!/usr/bin/env python -"""Time humanizing functions. These are largely borrowed from Django's -`contrib.humanize`.""" +"""Time humanizing functions. + +These are largely borrowed from Django's `contrib.humanize`. +""" import datetime as dt import math @@ -42,8 +44,7 @@ def _now(): def abs_timedelta(delta): - """Return an "absolute" value for a timedelta, always representing a - time distance. + """Return an "absolute" value for a timedelta, always representing a time distance. Args: delta (datetime.timedelta): Input timedelta. @@ -207,9 +208,12 @@ def naturaltime(value, future=False, months=True, minimum_unit="seconds"): def naturalday(value, format="%b %d"): - """For date values that are tomorrow, today or yesterday compared to - present day returns representing string. Otherwise, returns a string - formatted according to `format`.""" + """Return a natural day. + + For date values that are tomorrow, today or yesterday compared to + present day return representing string. Otherwise, return a string + formatted according to `format`. + """ try: value = dt.date(value.year, value.month, value.day) except AttributeError: @@ -229,8 +233,7 @@ def naturalday(value, format="%b %d"): def naturaldate(value): - """Like `naturalday`, but append a year for dates more than about five months away. - """ + """Like `naturalday`, but append a year for dates more than ~five months away.""" try: value = dt.date(value.year, value.month, value.day) except AttributeError: @@ -246,35 +249,30 @@ def naturaldate(value): def _quotient_and_remainder(value, divisor, unit, minimum_unit, suppress): - """Divide `value` by `divisor` returning the quotient and - the remainder as follows: + """Divide `value` by `divisor` returning the quotient and remainder. - If `unit` is `minimum_unit`, makes the quotient a float number - and the remainder will be zero. The rational is that if unit - is the unit of the quotient, we cannot - represent the remainder because it would require a unit smaller - than the minimum_unit. + If `unit` is `minimum_unit`, makes the quotient a float number and the remainder + will be zero. The rational is that if `unit` is the unit of the quotient, we cannot + represent the remainder because it would require a unit smaller than the + `minimum_unit`. - >>> from humanize.time import _quotient_and_remainder, Unit - >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.DAYS, []) - (1.5, 0) + >>> from humanize.time import _quotient_and_remainder, Unit + >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.DAYS, []) + (1.5, 0) - If unit is in suppress, the quotient will be zero and the - remainder will be the initial value. The idea is that if we - cannot use unit, we are forced to use a lower unit so we cannot - do the division. + If unit is in `suppress`, the quotient will be zero and the remainder will be the + initial value. The idea is that if we cannot use `unit`, we are forced to use a + lower unit so we cannot do the division. - >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, [Unit.DAYS]) - (0, 36) + >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, [Unit.DAYS]) + (0, 36) - In other case return quotient and remainder as `divmod` would - do it. + In other case return quotient and remainder as `divmod` would do it. - >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, []) - (1, 12) + >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, []) + (1, 12) """ - if unit == minimum_unit: return (value / divisor, 0) elif unit in suppress: @@ -284,29 +282,27 @@ def _quotient_and_remainder(value, divisor, unit, minimum_unit, suppress): def _carry(value1, value2, ratio, unit, min_unit, suppress): - """Return a tuple with two values as follows: + """Return a tuple with two values. - If the unit is in suppress multiplies value1 - by ratio and add it to value2 (carry to right). - The idea is that if we cannot represent value1 we need - to represent it in a lower unit. + If the unit is in `suppress`, multiply `value1` by `ratio` and add it to `value2` + (carry to right). The idea is that if we cannot represent `value1` we need to + represent it in a lower unit. - >>> from humanize.time import _carry, Unit - >>> _carry(2, 6, 24, Unit.DAYS, Unit.SECONDS, [Unit.DAYS]) - (0, 54) + >>> from humanize.time import _carry, Unit + >>> _carry(2, 6, 24, Unit.DAYS, Unit.SECONDS, [Unit.DAYS]) + (0, 54) - If the unit is the minimum unit, value2 is divided - by ratio and added to value1 (carry to left). - We assume that value2 has a lower unit so we need to - carry it to value1. + If the unit is the minimum unit, `value2` is divided by `ratio` and added to + `value1` (carry to left). We assume that `value2` has a lower unit so we need to + carry it to `value1`. - >>> _carry(2, 6, 24, Unit.DAYS, Unit.DAYS, []) - (2.25, 0) + >>> _carry(2, 6, 24, Unit.DAYS, Unit.DAYS, []) + (2.25, 0) - Otherwise, just return the same input: + Otherwise, just return the same input: - >>> _carry(2, 6, 24, Unit.DAYS, Unit.SECONDS, []) - (2, 6) + >>> _carry(2, 6, 24, Unit.DAYS, Unit.SECONDS, []) + (2, 6) """ if unit == min_unit: return (value1 + value2 / ratio, 0) @@ -319,20 +315,20 @@ def _carry(value1, value2, ratio, unit, min_unit, suppress): def _suitable_minimum_unit(min_unit, suppress): """Return a minimum unit suitable that is not suppressed. - If not suppressed, return the same unit: + If not suppressed, return the same unit: - >>> from humanize.time import _suitable_minimum_unit, Unit - >>> _suitable_minimum_unit(Unit.HOURS, []) - + >>> from humanize.time import _suitable_minimum_unit, Unit + >>> _suitable_minimum_unit(Unit.HOURS, []) + - But if suppressed, find a unit greather than the original one - that is not suppressed: + But if suppressed, find a unit greather than the original one that is not + suppressed: - >>> _suitable_minimum_unit(Unit.HOURS, [Unit.HOURS]) - + >>> _suitable_minimum_unit(Unit.HOURS, [Unit.HOURS]) + - >>> _suitable_minimum_unit(Unit.HOURS, [Unit.HOURS, Unit.DAYS]) - + >>> _suitable_minimum_unit(Unit.HOURS, [Unit.HOURS, Unit.DAYS]) + """ if min_unit in suppress: for unit in Unit: @@ -347,12 +343,11 @@ def _suitable_minimum_unit(min_unit, suppress): def _suppress_lower_units(min_unit, suppress): - """Extend the suppressed units (if any) with all the units that are - lower than the minimum unit. + """Extend suppressed units (if any) with all units lower than the minimum unit. - >>> from humanize.time import _suppress_lower_units, Unit - >>> list(sorted(_suppress_lower_units(Unit.SECONDS, [Unit.DAYS]))) - [, , ] + >>> from humanize.time import _suppress_lower_units, Unit + >>> list(sorted(_suppress_lower_units(Unit.SECONDS, [Unit.DAYS]))) + [, , ] """ suppress = set(suppress) for u in Unit: @@ -411,7 +406,6 @@ def precisedelta(value, minimum_unit="seconds", suppress=(), format="%0.2f"): '1.50 minutes' ``` """ - date, delta = date_and_delta(value) if date is None: return value From e2b217f2407a4f16b99516caf8934a12b16d58de Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 10 Sep 2020 15:42:37 +0300 Subject: [PATCH 4/5] Add some missing returns/raises --- src/humanize/filesize.py | 3 +++ src/humanize/i18n.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/humanize/filesize.py b/src/humanize/filesize.py index 149e2c40..59c9f1f3 100644 --- a/src/humanize/filesize.py +++ b/src/humanize/filesize.py @@ -23,6 +23,9 @@ def naturalsize(value, binary=False, gnu=False, format="%.1f"): gnu (bool): If `True`, the binary argument is ignored and GNU-style (`ls -sh` style) prefixes are used (K, M) with the 2**10 definition. format (str): Custom formatter. + + Returns: + str: Human readable representation of a filesize. """ if gnu: suffix = suffixes["gnu"] diff --git a/src/humanize/i18n.py b/src/humanize/i18n.py index 086f75d4..0d71b7fa 100644 --- a/src/humanize/i18n.py +++ b/src/humanize/i18n.py @@ -36,6 +36,9 @@ def activate(locale, path=None): Returns: dict: Translations. + + Raises: + Exception: If humanize cannot find the locale folder. """ if path is None: path = _get_default_locale_path() From aca3e0450ec54757e91e1faf0df55884f4c46e4a Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 10 Sep 2020 15:47:26 +0300 Subject: [PATCH 5/5] Switch from flaky codecov-bash to codecov-action --- .github/workflows/test.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 741544ef..1ac0fee8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -62,9 +62,7 @@ jobs: tox -e py - name: Upload coverage - if: success() - run: | - curl --retry 8 -s https://codecov.io/bash -o codecov.sh - bash codecov.sh -F ${{ matrix.codecov-flag }} - env: - CODECOV_NAME: ${{ matrix.os }} Python ${{ matrix.python-version }} + uses: codecov/codecov-action@v1 + with: + flags: ${{ matrix.codecov-flag }} + name: ${{ matrix.os }} Python ${{ matrix.python-version }}