Skip to content

Commit

Permalink
Defer imports for faster overall import time: 5 ms -> 3 ms (#238)
Browse files Browse the repository at this point in the history
  • Loading branch information
hugovk authored Feb 14, 2025
2 parents bad1093 + aaef964 commit a0602c7
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 4 deletions.
20 changes: 18 additions & 2 deletions src/humanize/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

from __future__ import annotations

import math

from .i18n import _gettext as _
from .i18n import _ngettext, decimal_separator, thousands_separator
from .i18n import _ngettext_noop as NS_
Expand All @@ -25,6 +23,8 @@

def _format_not_finite(value: float) -> str:
"""Utility function to handle infinite and nan cases."""
import math

if math.isnan(value):
return "NaN"
if math.isinf(value) and value < 0:
Expand Down Expand Up @@ -71,6 +71,8 @@ def ordinal(value: NumberOrString, gender: str = "male") -> str:
Returns:
str: Ordinal string.
"""
import math

try:
if not math.isfinite(float(value)):
return _format_not_finite(float(value))
Expand Down Expand Up @@ -142,6 +144,8 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str:
Returns:
str: String containing commas every three digits.
"""
import math

thousands_sep = thousands_separator()
decimal_sep = decimal_separator()
try:
Expand Down Expand Up @@ -226,6 +230,8 @@ def intword(value: NumberOrString, format: str = "%.1f") -> str:
str: Friendly text representation as a string, unless the value passed could not
be coaxed into an `int`.
"""
import math

try:
if not math.isfinite(float(value)):
return _format_not_finite(float(value))
Expand Down Expand Up @@ -293,6 +299,8 @@ def apnumber(value: NumberOrString) -> str:
returns a string unless the value was not `int`-able, then `str(value)`
is returned.
"""
import math

try:
if not math.isfinite(float(value)):
return _format_not_finite(float(value))
Expand Down Expand Up @@ -354,6 +362,8 @@ def fractional(value: NumberOrString) -> str:
Returns:
str: Fractional number as a string.
"""
import math

try:
number = float(value)
if not math.isfinite(number):
Expand Down Expand Up @@ -408,6 +418,8 @@ def scientific(value: NumberOrString, precision: int = 2) -> str:
Returns:
str: Number in scientific notation z.wq x 10ⁿ.
"""
import math

exponents = {
"0": "⁰",
"1": "¹",
Expand Down Expand Up @@ -491,6 +503,8 @@ def clamp(
will be prepended with a token indicating as such.
"""
import math

if value is None:
return None

Expand Down Expand Up @@ -554,6 +568,8 @@ def metric(value: float, unit: str = "", precision: int = 3) -> str:
Returns:
str:
"""
import math

if not math.isfinite(value):
return _format_not_finite(value)
exponent = int(math.floor(math.log10(abs(value)))) if value != 0 else 0
Expand Down
19 changes: 17 additions & 2 deletions src/humanize/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

from __future__ import annotations

import datetime as dt
import math
from enum import Enum
from functools import total_ordering

Expand All @@ -16,6 +14,7 @@

TYPE_CHECKING = False
if TYPE_CHECKING:
import datetime as dt
from collections.abc import Iterable
from typing import Any

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


def _now() -> dt.datetime:
import datetime as dt

return dt.datetime.now()


Expand All @@ -69,6 +70,8 @@ def _date_and_delta(value: Any, *, now: dt.datetime | None = None) -> tuple[Any,
If that's not possible, return `(None, value)`.
"""
import datetime as dt

if not now:
now = _now()
if isinstance(value, dt.datetime):
Expand Down Expand Up @@ -123,6 +126,8 @@ def naturaldelta(
assert naturaldelta(later - now) == "30 minutes"
"""
import datetime as dt

tmp = Unit[minimum_unit.upper()]
if tmp not in (Unit.SECONDS, Unit.MILLISECONDS, Unit.MICROSECONDS):
msg = f"Minimum unit '{minimum_unit}' not supported"
Expand Down Expand Up @@ -246,6 +251,8 @@ def naturaltime(
Returns:
str: A natural representation of the input in a resolution that makes sense.
"""
import datetime as dt

value = _convert_aware_datetime(value)
when = _convert_aware_datetime(when)

Expand All @@ -271,6 +278,8 @@ def _convert_aware_datetime(
value: dt.datetime | dt.timedelta | float | None,
) -> Any:
"""Convert aware datetime to naive datetime and pass through any other type."""
import datetime as dt

if isinstance(value, dt.datetime) and value.tzinfo is not None:
value = dt.datetime.fromtimestamp(value.timestamp())
return value
Expand All @@ -284,6 +293,8 @@ def naturalday(value: dt.date | dt.datetime, format: str = "%b %d") -> str:
formatted according to `format`.
"""
import datetime as dt

try:
value = dt.date(value.year, value.month, value.day)
except AttributeError:
Expand All @@ -308,6 +319,8 @@ def naturalday(value: dt.date | dt.datetime, format: str = "%b %d") -> str:

def naturaldate(value: dt.date | dt.datetime) -> str:
"""Like `naturalday`, but append a year for dates more than ~five months away."""
import datetime as dt

try:
value = dt.date(value.year, value.month, value.day)
except AttributeError:
Expand Down Expand Up @@ -594,6 +607,8 @@ def precisedelta(
if fmt_value > 0 or (not texts and unit == min_unit):
_fmt_value = 2 if 1 < fmt_value < 2 else int(fmt_value)
fmt_txt = _ngettext(singular_txt, plural_txt, _fmt_value)
import math

if unit == min_unit and math.modf(fmt_value)[0] > 0:
fmt_txt = fmt_txt.replace("%d", format)
elif unit == YEARS:
Expand Down

0 comments on commit a0602c7

Please sign in to comment.