77
88import datetime as dt
99import math
10- from enum import Enum
10+ import warnings
11+ from enum import Enum , EnumMeta
1112from functools import total_ordering
1213
1314from .i18n import gettext as _
2324
2425
2526@total_ordering
26- class Unit (Enum ):
27+ class _Unit (Enum ):
2728 MICROSECONDS = 0
2829 MILLISECONDS = 1
2930 SECONDS = 2
@@ -39,11 +40,48 @@ def __lt__(self, other):
3940 return NotImplemented
4041
4142
43+ class _UnitMeta (EnumMeta ):
44+ """Metaclass for an enum that emits deprecation warnings when accessed."""
45+
46+ def __getattribute__ (self , name ):
47+ warnings .warn (
48+ "`Unit` has been deprecated. "
49+ "The enum is still available as the private member `_Unit`." ,
50+ DeprecationWarning ,
51+ )
52+ return EnumMeta .__getattribute__ (_Unit , name )
53+
54+ def __getitem__ (cls , name ):
55+ warnings .warn (
56+ "`Unit` has been deprecated. "
57+ "The enum is still available as the private member `_Unit`." ,
58+ DeprecationWarning ,
59+ )
60+ return _Unit .__getitem__ (name )
61+
62+ def __call__ (
63+ cls , value , names = None , * , module = None , qualname = None , type = None , start = 1
64+ ):
65+ warnings .warn (
66+ "`Unit` has been deprecated. "
67+ "The enum is still available as the private member `_Unit`." ,
68+ DeprecationWarning ,
69+ )
70+ return _Unit .__call__ (
71+ value , names , module = module , qualname = qualname , type = type , start = start
72+ )
73+
74+
75+ class Unit (Enum , metaclass = _UnitMeta ):
76+ # Temporary alias for _Unit to allow backwards-compatible usage.
77+ pass
78+
79+
4280def _now ():
4381 return dt .datetime .now ()
4482
4583
46- def abs_timedelta (delta ):
84+ def _abs_timedelta (delta ):
4785 """Return an "absolute" value for a timedelta, always representing a time distance.
4886
4987 Args:
@@ -58,7 +96,27 @@ def abs_timedelta(delta):
5896 return delta
5997
6098
61- def date_and_delta (value , * , now = None ):
99+ def abs_timedelta (delta ):
100+ """Return an "absolute" value for a timedelta, always representing a time distance.
101+
102+ Args:
103+ delta (datetime.timedelta): Input timedelta.
104+
105+ Returns:
106+ datetime.timedelta: Absolute timedelta.
107+
108+ WARNING: This function has been deprecated. It is still available as the private
109+ member `_abs_timedelta`.
110+ """
111+ warnings .warn (
112+ "`abs_timedelta` has been deprecated. "
113+ "It is still available as the private member `_abs_timedelta`." ,
114+ DeprecationWarning ,
115+ )
116+ return _abs_timedelta (delta )
117+
118+
119+ def _date_and_delta (value , * , now = None ):
62120 """Turn a value into a date and a timedelta which represents how long ago it was.
63121
64122 If that's not possible, return `(None, value)`.
@@ -78,7 +136,23 @@ def date_and_delta(value, *, now=None):
78136 date = now - delta
79137 except (ValueError , TypeError ):
80138 return None , value
81- return date , abs_timedelta (delta )
139+ return date , _abs_timedelta (delta )
140+
141+
142+ def date_and_delta (delta ):
143+ """Turn a value into a date and a timedelta which represents how long ago it was.
144+
145+ If that's not possible, return `(None, value)`.
146+
147+ WARNING: This function has been deprecated. It is still available as the private
148+ member `_date_and_delta`.
149+ """
150+ warnings .warn (
151+ "`date_and_delta` has been deprecated. "
152+ "It is still available as the private member `_date_and_delta`." ,
153+ DeprecationWarning ,
154+ )
155+ return _date_and_delta (delta )
82156
83157
84158def naturaldelta (
@@ -114,12 +188,12 @@ def naturaldelta(
114188
115189 assert naturaldelta(later, when=now) == "30 minutes"
116190 """
117- tmp = Unit [minimum_unit .upper ()]
118- if tmp not in (Unit .SECONDS , Unit .MILLISECONDS , Unit .MICROSECONDS ):
191+ tmp = _Unit [minimum_unit .upper ()]
192+ if tmp not in (_Unit .SECONDS , _Unit .MILLISECONDS , _Unit .MICROSECONDS ):
119193 raise ValueError (f"Minimum unit '{ minimum_unit } ' not supported" )
120194 minimum_unit = tmp
121195
122- date , delta = date_and_delta (value , now = when )
196+ date , delta = _date_and_delta (value , now = when )
123197 if date is None :
124198 return value
125199
@@ -133,13 +207,13 @@ def naturaldelta(
133207
134208 if not years and days < 1 :
135209 if seconds == 0 :
136- if minimum_unit == Unit .MICROSECONDS and delta .microseconds < 1000 :
210+ if minimum_unit == _Unit .MICROSECONDS and delta .microseconds < 1000 :
137211 return (
138212 ngettext ("%d microsecond" , "%d microseconds" , delta .microseconds )
139213 % delta .microseconds
140214 )
141- elif minimum_unit == Unit .MILLISECONDS or (
142- minimum_unit == Unit .MICROSECONDS
215+ elif minimum_unit == _Unit .MILLISECONDS or (
216+ minimum_unit == _Unit .MICROSECONDS
143217 and 1000 <= delta .microseconds < 1_000_000
144218 ):
145219 milliseconds = delta .microseconds / 1000
@@ -218,7 +292,7 @@ def naturaltime(
218292 str: A natural representation of the input in a resolution that makes sense.
219293 """
220294 now = when or _now ()
221- date , delta = date_and_delta (value , now = now )
295+ date , delta = _date_and_delta (value , now = now )
222296 if date is None :
223297 return value
224298 # determine tense by value only if datetime/timedelta were passed
@@ -270,7 +344,7 @@ def naturaldate(value) -> str:
270344 except (OverflowError , ValueError ):
271345 # Date arguments out of range
272346 return value
273- delta = abs_timedelta (value - dt .date .today ())
347+ delta = _abs_timedelta (value - dt .date .today ())
274348 if delta .days >= 5 * 365 / 12 :
275349 return naturalday (value , "%b %d %Y" )
276350 return naturalday (value )
@@ -284,20 +358,20 @@ def _quotient_and_remainder(value, divisor, unit, minimum_unit, suppress):
284358 represent the remainder because it would require a unit smaller than the
285359 `minimum_unit`.
286360
287- >>> from humanize.time import _quotient_and_remainder, Unit
288- >>> _quotient_and_remainder(36, 24, Unit .DAYS, Unit .DAYS, [])
361+ >>> from humanize.time import _quotient_and_remainder, _Unit
362+ >>> _quotient_and_remainder(36, 24, _Unit .DAYS, _Unit .DAYS, [])
289363 (1.5, 0)
290364
291365 If unit is in `suppress`, the quotient will be zero and the remainder will be the
292366 initial value. The idea is that if we cannot use `unit`, we are forced to use a
293367 lower unit so we cannot do the division.
294368
295- >>> _quotient_and_remainder(36, 24, Unit .DAYS, Unit .HOURS, [Unit .DAYS])
369+ >>> _quotient_and_remainder(36, 24, _Unit .DAYS, _Unit .HOURS, [_Unit .DAYS])
296370 (0, 36)
297371
298372 In other case return quotient and remainder as `divmod` would do it.
299373
300- >>> _quotient_and_remainder(36, 24, Unit .DAYS, Unit .HOURS, [])
374+ >>> _quotient_and_remainder(36, 24, _Unit .DAYS, _Unit .HOURS, [])
301375 (1, 12)
302376
303377 """
@@ -316,20 +390,20 @@ def _carry(value1, value2, ratio, unit, min_unit, suppress):
316390 (carry to right). The idea is that if we cannot represent `value1` we need to
317391 represent it in a lower unit.
318392
319- >>> from humanize.time import _carry, Unit
320- >>> _carry(2, 6, 24, Unit .DAYS, Unit .SECONDS, [Unit .DAYS])
393+ >>> from humanize.time import _carry, _Unit
394+ >>> _carry(2, 6, 24, _Unit .DAYS, _Unit .SECONDS, [_Unit .DAYS])
321395 (0, 54)
322396
323397 If the unit is the minimum unit, `value2` is divided by `ratio` and added to
324398 `value1` (carry to left). We assume that `value2` has a lower unit so we need to
325399 carry it to `value1`.
326400
327- >>> _carry(2, 6, 24, Unit .DAYS, Unit .DAYS, [])
401+ >>> _carry(2, 6, 24, _Unit .DAYS, _Unit .DAYS, [])
328402 (2.25, 0)
329403
330404 Otherwise, just return the same input:
331405
332- >>> _carry(2, 6, 24, Unit .DAYS, Unit .SECONDS, [])
406+ >>> _carry(2, 6, 24, _Unit .DAYS, _Unit .SECONDS, [])
333407 (2, 6)
334408 """
335409 if unit == min_unit :
@@ -345,21 +419,21 @@ def _suitable_minimum_unit(min_unit, suppress):
345419
346420 If not suppressed, return the same unit:
347421
348- >>> from humanize.time import _suitable_minimum_unit, Unit
349- >>> _suitable_minimum_unit(Unit .HOURS, []).name
422+ >>> from humanize.time import _suitable_minimum_unit, _Unit
423+ >>> _suitable_minimum_unit(_Unit .HOURS, []).name
350424 'HOURS'
351425
352426 But if suppressed, find a unit greather than the original one that is not
353427 suppressed:
354428
355- >>> _suitable_minimum_unit(Unit .HOURS, [Unit .HOURS]).name
429+ >>> _suitable_minimum_unit(_Unit .HOURS, [_Unit .HOURS]).name
356430 'DAYS'
357431
358- >>> _suitable_minimum_unit(Unit .HOURS, [Unit .HOURS, Unit .DAYS]).name
432+ >>> _suitable_minimum_unit(_Unit .HOURS, [_Unit .HOURS, _Unit .DAYS]).name
359433 'MONTHS'
360434 """
361435 if min_unit in suppress :
362- for unit in Unit :
436+ for unit in _Unit :
363437 if unit > min_unit and unit not in suppress :
364438 return unit
365439
@@ -373,12 +447,12 @@ def _suitable_minimum_unit(min_unit, suppress):
373447def _suppress_lower_units (min_unit , suppress ):
374448 """Extend suppressed units (if any) with all units lower than the minimum unit.
375449
376- >>> from humanize.time import _suppress_lower_units, Unit
377- >>> [x.name for x in sorted(_suppress_lower_units(Unit .SECONDS, [Unit .DAYS]))]
450+ >>> from humanize.time import _suppress_lower_units, _Unit
451+ >>> [x.name for x in sorted(_suppress_lower_units(_Unit .SECONDS, [_Unit .DAYS]))]
378452 ['MICROSECONDS', 'MILLISECONDS', 'DAYS']
379453 """
380454 suppress = set (suppress )
381- for u in Unit :
455+ for u in _Unit :
382456 if u == min_unit :
383457 break
384458 suppress .add (u )
@@ -453,15 +527,15 @@ def precisedelta(value, minimum_unit="seconds", suppress=(), format="%0.2f") ->
453527
454528 ```
455529 """
456- date , delta = date_and_delta (value )
530+ date , delta = _date_and_delta (value )
457531 if date is None :
458532 return value
459533
460- suppress = [Unit [s .upper ()] for s in suppress ]
534+ suppress = [_Unit [s .upper ()] for s in suppress ]
461535
462536 # Find a suitable minimum unit (it can be greater the one that the
463537 # user gave us if it is suppressed).
464- min_unit = Unit [minimum_unit .upper ()]
538+ min_unit = _Unit [minimum_unit .upper ()]
465539 min_unit = _suitable_minimum_unit (min_unit , suppress )
466540 del minimum_unit
467541
@@ -475,7 +549,7 @@ def precisedelta(value, minimum_unit="seconds", suppress=(), format="%0.2f") ->
475549 usecs = delta .microseconds
476550
477551 MICROSECONDS , MILLISECONDS , SECONDS , MINUTES , HOURS , DAYS , MONTHS , YEARS = list (
478- Unit
552+ _Unit
479553 )
480554
481555 # Given DAYS compute YEARS and the remainder of DAYS as follows:
@@ -524,7 +598,7 @@ def precisedelta(value, minimum_unit="seconds", suppress=(), format="%0.2f") ->
524598 ]
525599
526600 texts = []
527- for unit , fmt in zip (reversed (Unit ), fmts ):
601+ for unit , fmt in zip (reversed (_Unit ), fmts ):
528602 singular_txt , plural_txt , value = fmt
529603 if value > 0 or (not texts and unit == min_unit ):
530604 fmt_txt = ngettext (singular_txt , plural_txt , value )
0 commit comments