Skip to content

Defer imports for faster overall import time: 19 ms -> 5 ms #234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ repos:
- id: debug-statements
- id: end-of-file-fixer
- id: forbid-submodules
- id: requirements-txt-fixer
- id: trailing-whitespace
exclude: \.github/ISSUE_TEMPLATE\.md|\.github/PULL_REQUEST_TEMPLATE\.md

Expand Down
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mkdocs==1.6.1
mkdocs-include-markdown-plugin
mkdocs-material
mkdocstrings[python]==0.27.0
mkdocs-include-markdown-plugin
pygments
pymdown-extensions==10.14.3
4 changes: 4 additions & 0 deletions requirements-mypy.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mypy==1.15.0
pytest
types-freezegun
types-setuptools
2 changes: 1 addition & 1 deletion src/humanize/i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

import gettext as gettext_module
from threading import local
from typing import TYPE_CHECKING

TYPE_CHECKING = False
if TYPE_CHECKING:
import os
import pathlib
Expand Down
4 changes: 3 additions & 1 deletion src/humanize/lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

from __future__ import annotations

from typing import Any
TYPE_CHECKING = False
if TYPE_CHECKING:
from typing import Any

__all__ = ["natural_list"]

Expand Down
16 changes: 10 additions & 6 deletions src/humanize/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@
from __future__ import annotations

import math
import re
import sys
from typing import TYPE_CHECKING

from .i18n import _gettext as _
from .i18n import _ngettext, decimal_separator, thousands_separator
from .i18n import _ngettext_noop as NS_
from .i18n import _pgettext as P_

TYPE_CHECKING = False
if TYPE_CHECKING:
import sys

if sys.version_info >= (3, 10):
from typing import TypeAlias
else:
from typing_extensions import TypeAlias

# This type can be better defined by typing.SupportsInt, typing.SupportsFloat
# but that's a Python 3.8 only typing option.
NumberOrString: TypeAlias = "float | str"
# This type can be better defined by typing.SupportsFloat
# but that's a Python 3.8 only typing option.
NumberOrString: TypeAlias = float | str


def _format_not_finite(value: float) -> str:
Expand Down Expand Up @@ -165,6 +165,8 @@ def intcomma(value: NumberOrString, ndigits: int | None = None) -> str:
else:
orig = str(value)
orig = orig.replace(".", decimal_sep)
import re

while True:
new = re.sub(r"^(-?\d+)(\d{3})", rf"\g<1>{thousands_sep}\g<2>", orig)
if orig == new:
Expand Down Expand Up @@ -429,6 +431,8 @@ def scientific(value: NumberOrString, precision: int = 2) -> str:
n = fmt.format(value)
part1, part2 = n.split("e")
# Remove redundant leading '+' or '0's (preserving the last '0' for 10⁰).
import re

part2 = re.sub(r"^\+?(\-?)0*(.+)$", r"\1\2", part2)

new_part2 = []
Expand Down
24 changes: 12 additions & 12 deletions src/humanize/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@

from __future__ import annotations

import collections.abc
import datetime as dt
import math
import typing
from enum import Enum
from functools import total_ordering
from typing import Any

from .i18n import _gettext as _
from .i18n import _ngettext
from .number import intcomma

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

__all__ = [
"naturaldate",
"naturalday",
Expand All @@ -37,7 +39,7 @@ class Unit(Enum):
MONTHS = 6
YEARS = 7

def __lt__(self, other: typing.Any) -> typing.Any:
def __lt__(self, other: Any) -> Any:
if self.__class__ is other.__class__:
return self.value < other.value
return NotImplemented
Expand All @@ -62,9 +64,7 @@ def _abs_timedelta(delta: dt.timedelta) -> dt.timedelta:
return delta


def _date_and_delta(
value: typing.Any, *, now: dt.datetime | None = None
) -> tuple[typing.Any, typing.Any]:
def _date_and_delta(value: Any, *, now: dt.datetime | None = None) -> tuple[Any, Any]:
"""Turn a value into a date and a timedelta which represents how long ago it was.

If that's not possible, return `(None, value)`.
Expand Down Expand Up @@ -327,7 +327,7 @@ def _quotient_and_remainder(
divisor: float,
unit: Unit,
minimum_unit: Unit,
suppress: collections.abc.Iterable[Unit],
suppress: Iterable[Unit],
) -> tuple[float, float]:
"""Divide `value` by `divisor` returning the quotient and remainder.

Expand Down Expand Up @@ -368,7 +368,7 @@ def _carry(
ratio: float,
unit: Unit,
min_unit: Unit,
suppress: typing.Iterable[Unit],
suppress: Iterable[Unit],
) -> tuple[float, float]:
"""Return a tuple with two values.

Expand Down Expand Up @@ -401,7 +401,7 @@ def _carry(
return value1, value2


def _suitable_minimum_unit(min_unit: Unit, suppress: typing.Iterable[Unit]) -> Unit:
def _suitable_minimum_unit(min_unit: Unit, suppress: Iterable[Unit]) -> Unit:
"""Return a minimum unit suitable that is not suppressed.

If not suppressed, return the same unit:
Expand Down Expand Up @@ -430,7 +430,7 @@ def _suitable_minimum_unit(min_unit: Unit, suppress: typing.Iterable[Unit]) -> U
return min_unit


def _suppress_lower_units(min_unit: Unit, suppress: typing.Iterable[Unit]) -> set[Unit]:
def _suppress_lower_units(min_unit: Unit, suppress: Iterable[Unit]) -> set[Unit]:
"""Extend suppressed units (if any) with all units lower than the minimum unit.

>>> from humanize.time import _suppress_lower_units, Unit
Expand All @@ -449,7 +449,7 @@ def _suppress_lower_units(min_unit: Unit, suppress: typing.Iterable[Unit]) -> se
def precisedelta(
value: dt.timedelta | int | None,
minimum_unit: str = "seconds",
suppress: typing.Iterable[str] = (),
suppress: Iterable[str] = (),
format: str = "%0.2f",
) -> str:
"""Return a precise representation of a timedelta.
Expand Down
5 changes: 1 addition & 4 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@ commands =

[testenv:mypy]
deps =
mypy==1.12
pytest
types-freezegun
types-setuptools
-r requirements-mypy.txt
commands =
mypy . {posargs}

Expand Down
Loading