Skip to content

Commit

Permalink
Merge pull request #252 from hugovk/dont-deprecate-Unit
Browse files Browse the repository at this point in the history
hugovk authored Jan 30, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents 35201aa + 1bedec1 commit 309e7fd
Showing 2 changed files with 28 additions and 66 deletions.
92 changes: 27 additions & 65 deletions src/humanize/time.py
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
import datetime as dt
import math
import warnings
from enum import Enum, EnumMeta
from enum import Enum
from functools import total_ordering

from .i18n import _gettext as _
@@ -25,7 +25,7 @@


@total_ordering
class _Unit(Enum):
class Unit(Enum):
MICROSECONDS = 0
MILLISECONDS = 1
SECONDS = 2
@@ -41,44 +41,6 @@ def __lt__(self, other):
return NotImplemented


class _UnitMeta(EnumMeta):
"""Metaclass for an enum that emits deprecation warnings when accessed."""

def __getattribute__(self, name):
# Temporarily comment out to avoid warning during 'import humanize'
# warnings.warn(
# "`Unit` has been deprecated. "
# "The enum is still available as the private member `_Unit`.",
# DeprecationWarning,
# )
return EnumMeta.__getattribute__(_Unit, name)

def __getitem__(cls, name):
warnings.warn(
"`Unit` has been deprecated. "
"The enum is still available as the private member `_Unit`.",
DeprecationWarning,
)
return _Unit.__getitem__(name)

def __call__(
cls, value, names=None, *, module=None, qualname=None, type=None, start=1
):
warnings.warn(
"`Unit` has been deprecated. "
"The enum is still available as the private member `_Unit`.",
DeprecationWarning,
)
return _Unit.__call__(
value, names, module=module, qualname=qualname, type=type, start=start
)


class Unit(Enum, metaclass=_UnitMeta):
# Temporary alias for _Unit to allow backwards-compatible usage.
pass


def _now():
return dt.datetime.now()

@@ -200,8 +162,8 @@ def naturaldelta(
DeprecationWarning,
stacklevel=2,
)
tmp = _Unit[minimum_unit.upper()]
if tmp not in (_Unit.SECONDS, _Unit.MILLISECONDS, _Unit.MICROSECONDS):
tmp = Unit[minimum_unit.upper()]
if tmp not in (Unit.SECONDS, Unit.MILLISECONDS, Unit.MICROSECONDS):
raise ValueError(f"Minimum unit '{minimum_unit}' not supported")
minimum_unit = tmp

@@ -219,13 +181,13 @@ def naturaldelta(

if not years and days < 1:
if seconds == 0:
if minimum_unit == _Unit.MICROSECONDS and delta.microseconds < 1000:
if minimum_unit == Unit.MICROSECONDS and delta.microseconds < 1000:
return (
_ngettext("%d microsecond", "%d microseconds", delta.microseconds)
% delta.microseconds
)
elif minimum_unit == _Unit.MILLISECONDS or (
minimum_unit == _Unit.MICROSECONDS
elif minimum_unit == Unit.MILLISECONDS or (
minimum_unit == Unit.MICROSECONDS
and 1000 <= delta.microseconds < 1_000_000
):
milliseconds = delta.microseconds / 1000
@@ -370,20 +332,20 @@ def _quotient_and_remainder(value, divisor, unit, minimum_unit, suppress):
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, [])
>>> 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.
>>> _quotient_and_remainder(36, 24, _Unit.DAYS, _Unit.HOURS, [_Unit.DAYS])
>>> _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.
>>> _quotient_and_remainder(36, 24, _Unit.DAYS, _Unit.HOURS, [])
>>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, [])
(1, 12)
"""
@@ -402,20 +364,20 @@ def _carry(value1, value2, ratio, unit, min_unit, suppress):
(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])
>>> 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`.
>>> _carry(2, 6, 24, _Unit.DAYS, _Unit.DAYS, [])
>>> _carry(2, 6, 24, Unit.DAYS, Unit.DAYS, [])
(2.25, 0)
Otherwise, just return the same input:
>>> _carry(2, 6, 24, _Unit.DAYS, _Unit.SECONDS, [])
>>> _carry(2, 6, 24, Unit.DAYS, Unit.SECONDS, [])
(2, 6)
"""
if unit == min_unit:
@@ -431,21 +393,21 @@ def _suitable_minimum_unit(min_unit, suppress):
If not suppressed, return the same unit:
>>> from humanize.time import _suitable_minimum_unit, _Unit
>>> _suitable_minimum_unit(_Unit.HOURS, []).name
>>> from humanize.time import _suitable_minimum_unit, Unit
>>> _suitable_minimum_unit(Unit.HOURS, []).name
'HOURS'
But if suppressed, find a unit greather than the original one that is not
suppressed:
>>> _suitable_minimum_unit(_Unit.HOURS, [_Unit.HOURS]).name
>>> _suitable_minimum_unit(Unit.HOURS, [Unit.HOURS]).name
'DAYS'
>>> _suitable_minimum_unit(_Unit.HOURS, [_Unit.HOURS, _Unit.DAYS]).name
>>> _suitable_minimum_unit(Unit.HOURS, [Unit.HOURS, Unit.DAYS]).name
'MONTHS'
"""
if min_unit in suppress:
for unit in _Unit:
for unit in Unit:
if unit > min_unit and unit not in suppress:
return unit

@@ -459,12 +421,12 @@ def _suitable_minimum_unit(min_unit, suppress):
def _suppress_lower_units(min_unit, suppress):
"""Extend suppressed units (if any) with all units lower than the minimum unit.
>>> from humanize.time import _suppress_lower_units, _Unit
>>> [x.name for x in sorted(_suppress_lower_units(_Unit.SECONDS, [_Unit.DAYS]))]
>>> from humanize.time import _suppress_lower_units, Unit
>>> [x.name for x in sorted(_suppress_lower_units(Unit.SECONDS, [Unit.DAYS]))]
['MICROSECONDS', 'MILLISECONDS', 'DAYS']
"""
suppress = set(suppress)
for u in _Unit:
for u in Unit:
if u == min_unit:
break
suppress.add(u)
@@ -543,11 +505,11 @@ def precisedelta(value, minimum_unit="seconds", suppress=(), format="%0.2f") ->
if date is None:
return value

suppress = [_Unit[s.upper()] for s in suppress]
suppress = [Unit[s.upper()] for s in suppress]

# Find a suitable minimum unit (it can be greater the one that the
# user gave us if it is suppressed).
min_unit = _Unit[minimum_unit.upper()]
min_unit = Unit[minimum_unit.upper()]
min_unit = _suitable_minimum_unit(min_unit, suppress)
del minimum_unit

@@ -561,7 +523,7 @@ def precisedelta(value, minimum_unit="seconds", suppress=(), format="%0.2f") ->
usecs = delta.microseconds

MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS, MONTHS, YEARS = list(
_Unit
Unit
)

# Given DAYS compute YEARS and the remainder of DAYS as follows:
@@ -610,7 +572,7 @@ def precisedelta(value, minimum_unit="seconds", suppress=(), format="%0.2f") ->
]

texts = []
for unit, fmt in zip(reversed(_Unit), fmts):
for unit, fmt in zip(reversed(Unit), fmts):
singular_txt, plural_txt, value = fmt
if value > 0 or (not texts and unit == min_unit):
fmt_txt = _ngettext(singular_txt, plural_txt, value)
2 changes: 1 addition & 1 deletion tests/test_time.py
Original file line number Diff line number Diff line change
@@ -645,7 +645,7 @@ def test_precisedelta_bogus_call():


def test_time_unit():
years, minutes = time._Unit["YEARS"], time._Unit["MINUTES"]
years, minutes = time.Unit["YEARS"], time.Unit["MINUTES"]
assert minutes < years
assert years > minutes
assert minutes == minutes

0 comments on commit 309e7fd

Please sign in to comment.