Skip to content

Commit a0602c7

Browse files
authored
Defer imports for faster overall import time: 5 ms -> 3 ms (#238)
2 parents bad1093 + aaef964 commit a0602c7

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

src/humanize/number.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
from __future__ import annotations
44

5-
import math
6-
75
from .i18n import _gettext as _
86
from .i18n import _ngettext, decimal_separator, thousands_separator
97
from .i18n import _ngettext_noop as NS_
@@ -25,6 +23,8 @@
2523

2624
def _format_not_finite(value: float) -> str:
2725
"""Utility function to handle infinite and nan cases."""
26+
import math
27+
2828
if math.isnan(value):
2929
return "NaN"
3030
if math.isinf(value) and value < 0:
@@ -71,6 +71,8 @@ def ordinal(value: NumberOrString, gender: str = "male") -> str:
7171
Returns:
7272
str: Ordinal string.
7373
"""
74+
import math
75+
7476
try:
7577
if not math.isfinite(float(value)):
7678
return _format_not_finite(float(value))
@@ -142,6 +144,8 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str:
142144
Returns:
143145
str: String containing commas every three digits.
144146
"""
147+
import math
148+
145149
thousands_sep = thousands_separator()
146150
decimal_sep = decimal_separator()
147151
try:
@@ -226,6 +230,8 @@ def intword(value: NumberOrString, format: str = "%.1f") -> str:
226230
str: Friendly text representation as a string, unless the value passed could not
227231
be coaxed into an `int`.
228232
"""
233+
import math
234+
229235
try:
230236
if not math.isfinite(float(value)):
231237
return _format_not_finite(float(value))
@@ -293,6 +299,8 @@ def apnumber(value: NumberOrString) -> str:
293299
returns a string unless the value was not `int`-able, then `str(value)`
294300
is returned.
295301
"""
302+
import math
303+
296304
try:
297305
if not math.isfinite(float(value)):
298306
return _format_not_finite(float(value))
@@ -354,6 +362,8 @@ def fractional(value: NumberOrString) -> str:
354362
Returns:
355363
str: Fractional number as a string.
356364
"""
365+
import math
366+
357367
try:
358368
number = float(value)
359369
if not math.isfinite(number):
@@ -408,6 +418,8 @@ def scientific(value: NumberOrString, precision: int = 2) -> str:
408418
Returns:
409419
str: Number in scientific notation z.wq x 10ⁿ.
410420
"""
421+
import math
422+
411423
exponents = {
412424
"0": "⁰",
413425
"1": "¹",
@@ -491,6 +503,8 @@ def clamp(
491503
will be prepended with a token indicating as such.
492504
493505
"""
506+
import math
507+
494508
if value is None:
495509
return None
496510

@@ -554,6 +568,8 @@ def metric(value: float, unit: str = "", precision: int = 3) -> str:
554568
Returns:
555569
str:
556570
"""
571+
import math
572+
557573
if not math.isfinite(value):
558574
return _format_not_finite(value)
559575
exponent = int(math.floor(math.log10(abs(value)))) if value != 0 else 0

src/humanize/time.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
from __future__ import annotations
77

8-
import datetime as dt
9-
import math
108
from enum import Enum
119
from functools import total_ordering
1210

@@ -16,6 +14,7 @@
1614

1715
TYPE_CHECKING = False
1816
if TYPE_CHECKING:
17+
import datetime as dt
1918
from collections.abc import Iterable
2019
from typing import Any
2120

@@ -46,6 +45,8 @@ def __lt__(self, other: Any) -> Any:
4645

4746

4847
def _now() -> dt.datetime:
48+
import datetime as dt
49+
4950
return dt.datetime.now()
5051

5152

@@ -69,6 +70,8 @@ def _date_and_delta(value: Any, *, now: dt.datetime | None = None) -> tuple[Any,
6970
7071
If that's not possible, return `(None, value)`.
7172
"""
73+
import datetime as dt
74+
7275
if not now:
7376
now = _now()
7477
if isinstance(value, dt.datetime):
@@ -123,6 +126,8 @@ def naturaldelta(
123126
124127
assert naturaldelta(later - now) == "30 minutes"
125128
"""
129+
import datetime as dt
130+
126131
tmp = Unit[minimum_unit.upper()]
127132
if tmp not in (Unit.SECONDS, Unit.MILLISECONDS, Unit.MICROSECONDS):
128133
msg = f"Minimum unit '{minimum_unit}' not supported"
@@ -246,6 +251,8 @@ def naturaltime(
246251
Returns:
247252
str: A natural representation of the input in a resolution that makes sense.
248253
"""
254+
import datetime as dt
255+
249256
value = _convert_aware_datetime(value)
250257
when = _convert_aware_datetime(when)
251258

@@ -271,6 +278,8 @@ def _convert_aware_datetime(
271278
value: dt.datetime | dt.timedelta | float | None,
272279
) -> Any:
273280
"""Convert aware datetime to naive datetime and pass through any other type."""
281+
import datetime as dt
282+
274283
if isinstance(value, dt.datetime) and value.tzinfo is not None:
275284
value = dt.datetime.fromtimestamp(value.timestamp())
276285
return value
@@ -284,6 +293,8 @@ def naturalday(value: dt.date | dt.datetime, format: str = "%b %d") -> str:
284293
formatted according to `format`.
285294
286295
"""
296+
import datetime as dt
297+
287298
try:
288299
value = dt.date(value.year, value.month, value.day)
289300
except AttributeError:
@@ -308,6 +319,8 @@ def naturalday(value: dt.date | dt.datetime, format: str = "%b %d") -> str:
308319

309320
def naturaldate(value: dt.date | dt.datetime) -> str:
310321
"""Like `naturalday`, but append a year for dates more than ~five months away."""
322+
import datetime as dt
323+
311324
try:
312325
value = dt.date(value.year, value.month, value.day)
313326
except AttributeError:
@@ -594,6 +607,8 @@ def precisedelta(
594607
if fmt_value > 0 or (not texts and unit == min_unit):
595608
_fmt_value = 2 if 1 < fmt_value < 2 else int(fmt_value)
596609
fmt_txt = _ngettext(singular_txt, plural_txt, _fmt_value)
610+
import math
611+
597612
if unit == min_unit and math.modf(fmt_value)[0] > 0:
598613
fmt_txt = fmt_txt.replace("%d", format)
599614
elif unit == YEARS:

0 commit comments

Comments
 (0)