Skip to content

Commit 79a4d48

Browse files
committed
Merge remote-tracking branch 'upstream/master' into remove-deprecated-private-function-aliases
2 parents 79b5957 + 309e7fd commit 79a4d48

3 files changed

Lines changed: 48 additions & 32 deletions

File tree

RELEASING.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ scripts/generate-translation-binaries.sh
2222
pip install -U pip build keyring twine
2323
rm -rf build dist
2424
python -m build
25-
twine check dist/*
26-
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
25+
twine check --strict dist/* && twine upload --repository-url https://test.pypi.org/legacy/ dist/*
2726
```
2827

2928
- [ ] (Optional) Check **test** installation:
@@ -46,8 +45,7 @@ git tag -a 2.1.0 -m "Release 2.1.0"
4645
pip install -U pip build keyring twine
4746
rm -rf build dist
4847
python -m build
49-
twine check dist/*
50-
twine upload -r pypi dist/*
48+
twine check --strict dist/* && twine upload -r pypi dist/*
5149
```
5250

5351
* [ ] Check installation:

src/humanize/time.py

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77

88
import datetime as dt
99
import math
10+
import warnings
1011
from enum import Enum
1112
from functools import total_ordering
1213

1314
from .i18n import _gettext as _
1415
from .i18n import _ngettext
16+
from .number import intcomma
1517

1618
__all__ = [
1719
"naturaldelta",
@@ -23,7 +25,7 @@
2325

2426

2527
@total_ordering
26-
class _Unit(Enum):
28+
class Unit(Enum):
2729
MICROSECONDS = 0
2830
MILLISECONDS = 1
2931
SECONDS = 2
@@ -98,6 +100,8 @@ def naturaldelta(
98100
minimum_unit (str): The lowest unit that can be used.
99101
when (datetime.datetime): Point in time relative to which _value_ is
100102
interpreted. Defaults to the current time in the local timezone.
103+
Deprecated in version 3.14; If you need to construct a timedelta,
104+
do it inline as the first argument.
101105
102106
Returns:
103107
str: A natural representation of the amount of time elapsed.
@@ -114,8 +118,16 @@ def naturaldelta(
114118
115119
assert naturaldelta(later, when=now) == "30 minutes"
116120
"""
117-
tmp = _Unit[minimum_unit.upper()]
118-
if tmp not in (_Unit.SECONDS, _Unit.MILLISECONDS, _Unit.MICROSECONDS):
121+
if when:
122+
warnings.warn(
123+
"The `when` parameter of `naturaldelta()` is deprecated and will be "
124+
"removed in humanize 4.0. If you need to construct a timedelta, "
125+
"do it inline as the first argument.",
126+
DeprecationWarning,
127+
stacklevel=2,
128+
)
129+
tmp = Unit[minimum_unit.upper()]
130+
if tmp not in (Unit.SECONDS, Unit.MILLISECONDS, Unit.MICROSECONDS):
119131
raise ValueError(f"Minimum unit '{minimum_unit}' not supported")
120132
minimum_unit = tmp
121133

@@ -133,13 +145,13 @@ def naturaldelta(
133145

134146
if not years and days < 1:
135147
if seconds == 0:
136-
if minimum_unit == _Unit.MICROSECONDS and delta.microseconds < 1000:
148+
if minimum_unit == Unit.MICROSECONDS and delta.microseconds < 1000:
137149
return (
138150
_ngettext("%d microsecond", "%d microseconds", delta.microseconds)
139151
% delta.microseconds
140152
)
141-
elif minimum_unit == _Unit.MILLISECONDS or (
142-
minimum_unit == _Unit.MICROSECONDS
153+
elif minimum_unit == Unit.MILLISECONDS or (
154+
minimum_unit == Unit.MICROSECONDS
143155
and 1000 <= delta.microseconds < 1_000_000
144156
):
145157
milliseconds = delta.microseconds / 1000
@@ -189,7 +201,7 @@ def naturaldelta(
189201
else:
190202
return _ngettext("1 year, %d day", "1 year, %d days", days) % days
191203
else:
192-
return _ngettext("%d year", "%d years", years) % years
204+
return _ngettext("%s year", "%s years", years) % intcomma(years)
193205

194206

195207
def naturaltime(
@@ -284,20 +296,20 @@ def _quotient_and_remainder(value, divisor, unit, minimum_unit, suppress):
284296
represent the remainder because it would require a unit smaller than the
285297
`minimum_unit`.
286298
287-
>>> from humanize.time import _quotient_and_remainder, _Unit
288-
>>> _quotient_and_remainder(36, 24, _Unit.DAYS, _Unit.DAYS, [])
299+
>>> from humanize.time import _quotient_and_remainder, Unit
300+
>>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.DAYS, [])
289301
(1.5, 0)
290302
291303
If unit is in `suppress`, the quotient will be zero and the remainder will be the
292304
initial value. The idea is that if we cannot use `unit`, we are forced to use a
293305
lower unit so we cannot do the division.
294306
295-
>>> _quotient_and_remainder(36, 24, _Unit.DAYS, _Unit.HOURS, [_Unit.DAYS])
307+
>>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, [Unit.DAYS])
296308
(0, 36)
297309
298310
In other case return quotient and remainder as `divmod` would do it.
299311
300-
>>> _quotient_and_remainder(36, 24, _Unit.DAYS, _Unit.HOURS, [])
312+
>>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, [])
301313
(1, 12)
302314
303315
"""
@@ -316,20 +328,20 @@ def _carry(value1, value2, ratio, unit, min_unit, suppress):
316328
(carry to right). The idea is that if we cannot represent `value1` we need to
317329
represent it in a lower unit.
318330
319-
>>> from humanize.time import _carry, _Unit
320-
>>> _carry(2, 6, 24, _Unit.DAYS, _Unit.SECONDS, [_Unit.DAYS])
331+
>>> from humanize.time import _carry, Unit
332+
>>> _carry(2, 6, 24, Unit.DAYS, Unit.SECONDS, [Unit.DAYS])
321333
(0, 54)
322334
323335
If the unit is the minimum unit, `value2` is divided by `ratio` and added to
324336
`value1` (carry to left). We assume that `value2` has a lower unit so we need to
325337
carry it to `value1`.
326338
327-
>>> _carry(2, 6, 24, _Unit.DAYS, _Unit.DAYS, [])
339+
>>> _carry(2, 6, 24, Unit.DAYS, Unit.DAYS, [])
328340
(2.25, 0)
329341
330342
Otherwise, just return the same input:
331343
332-
>>> _carry(2, 6, 24, _Unit.DAYS, _Unit.SECONDS, [])
344+
>>> _carry(2, 6, 24, Unit.DAYS, Unit.SECONDS, [])
333345
(2, 6)
334346
"""
335347
if unit == min_unit:
@@ -345,21 +357,21 @@ def _suitable_minimum_unit(min_unit, suppress):
345357
346358
If not suppressed, return the same unit:
347359
348-
>>> from humanize.time import _suitable_minimum_unit, _Unit
349-
>>> _suitable_minimum_unit(_Unit.HOURS, []).name
360+
>>> from humanize.time import _suitable_minimum_unit, Unit
361+
>>> _suitable_minimum_unit(Unit.HOURS, []).name
350362
'HOURS'
351363
352364
But if suppressed, find a unit greather than the original one that is not
353365
suppressed:
354366
355-
>>> _suitable_minimum_unit(_Unit.HOURS, [_Unit.HOURS]).name
367+
>>> _suitable_minimum_unit(Unit.HOURS, [Unit.HOURS]).name
356368
'DAYS'
357369
358-
>>> _suitable_minimum_unit(_Unit.HOURS, [_Unit.HOURS, _Unit.DAYS]).name
370+
>>> _suitable_minimum_unit(Unit.HOURS, [Unit.HOURS, Unit.DAYS]).name
359371
'MONTHS'
360372
"""
361373
if min_unit in suppress:
362-
for unit in _Unit:
374+
for unit in Unit:
363375
if unit > min_unit and unit not in suppress:
364376
return unit
365377

@@ -373,12 +385,12 @@ def _suitable_minimum_unit(min_unit, suppress):
373385
def _suppress_lower_units(min_unit, suppress):
374386
"""Extend suppressed units (if any) with all units lower than the minimum unit.
375387
376-
>>> from humanize.time import _suppress_lower_units, _Unit
377-
>>> [x.name for x in sorted(_suppress_lower_units(_Unit.SECONDS, [_Unit.DAYS]))]
388+
>>> from humanize.time import _suppress_lower_units, Unit
389+
>>> [x.name for x in sorted(_suppress_lower_units(Unit.SECONDS, [Unit.DAYS]))]
378390
['MICROSECONDS', 'MILLISECONDS', 'DAYS']
379391
"""
380392
suppress = set(suppress)
381-
for u in _Unit:
393+
for u in Unit:
382394
if u == min_unit:
383395
break
384396
suppress.add(u)
@@ -457,11 +469,11 @@ def precisedelta(value, minimum_unit="seconds", suppress=(), format="%0.2f") ->
457469
if date is None:
458470
return value
459471

460-
suppress = [_Unit[s.upper()] for s in suppress]
472+
suppress = [Unit[s.upper()] for s in suppress]
461473

462474
# Find a suitable minimum unit (it can be greater the one that the
463475
# user gave us if it is suppressed).
464-
min_unit = _Unit[minimum_unit.upper()]
476+
min_unit = Unit[minimum_unit.upper()]
465477
min_unit = _suitable_minimum_unit(min_unit, suppress)
466478
del minimum_unit
467479

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

477489
MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS, MONTHS, YEARS = list(
478-
_Unit
490+
Unit
479491
)
480492

481493
# Given DAYS compute YEARS and the remainder of DAYS as follows:
@@ -524,12 +536,16 @@ def precisedelta(value, minimum_unit="seconds", suppress=(), format="%0.2f") ->
524536
]
525537

526538
texts = []
527-
for unit, fmt in zip(reversed(_Unit), fmts):
539+
for unit, fmt in zip(reversed(Unit), fmts):
528540
singular_txt, plural_txt, value = fmt
529541
if value > 0 or (not texts and unit == min_unit):
530542
fmt_txt = _ngettext(singular_txt, plural_txt, value)
531543
if unit == min_unit and math.modf(value)[0] > 0:
532544
fmt_txt = fmt_txt.replace("%d", format)
545+
elif unit == YEARS:
546+
fmt_txt = fmt_txt.replace("%d", "%s")
547+
texts.append(fmt_txt % intcomma(value))
548+
continue
533549

534550
texts.append(fmt_txt % value)
535551

tests/test_time.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ def test_naturaldelta_nomonths(test_input, expected):
118118
(dt.timedelta(days=65), "2 months"),
119119
(dt.timedelta(days=9), "9 days"),
120120
(dt.timedelta(days=365), "a year"),
121+
(dt.timedelta(days=365 * 1_141), "1,141 years"),
121122
("NaN", "NaN"),
122123
],
123124
)
@@ -446,6 +447,7 @@ def test_naturaltime_minimum_unit_explicit(minimum_unit, seconds, expected):
446447
(3600 * 24 * 2, "seconds", "2 days"),
447448
(3600 * 24 * 365, "seconds", "1 year"),
448449
(3600 * 24 * 365 * 2, "seconds", "2 years"),
450+
(3600 * 24 * 365 * 1_963, "seconds", "1,963 years"),
449451
],
450452
)
451453
def test_precisedelta_one_unit_enough(val, min_unit, expected):
@@ -643,7 +645,7 @@ def test_precisedelta_bogus_call():
643645

644646

645647
def test_time_unit():
646-
years, minutes = time._Unit["YEARS"], time._Unit["MINUTES"]
648+
years, minutes = time.Unit["YEARS"], time.Unit["MINUTES"]
647649
assert minutes < years
648650
assert years > minutes
649651
assert minutes == minutes

0 commit comments

Comments
 (0)