summaryrefslogtreecommitdiff
path: root/venv/lib/python3.11/site-packages/litestar/utils/helpers.py
blob: c25fe35f25d5f41c1d5905a16a3218afdebf0890 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
from __future__ import annotations

from enum import Enum
from functools import partial
from typing import TYPE_CHECKING, TypeVar, cast
from urllib.parse import quote

from litestar.utils.typing import get_origin_or_inner_type

if TYPE_CHECKING:
    from collections.abc import Container

    from litestar.types import MaybePartial

__all__ = (
    "get_enum_string_value",
    "get_name",
    "unwrap_partial",
    "url_quote",
    "unique_name_for_scope",
)

T = TypeVar("T")


def get_name(value: object) -> str:
    """Get the ``__name__`` of an object.

    Args:
        value: An arbitrary object.

    Returns:
        A name string.
    """

    name = getattr(value, "__name__", None)
    if name is not None:
        return cast("str", name)

    # On Python 3.8 and 3.9, Foo[int] does not have the __name__ attribute.
    if origin := get_origin_or_inner_type(value):
        return cast("str", origin.__name__)

    return type(value).__name__


def get_enum_string_value(value: Enum | str) -> str:
    """Return the string value of a string enum.

    See: https://github.com/litestar-org/litestar/pull/633#issuecomment-1286519267

    Args:
        value: An enum or string.

    Returns:
        A string.
    """
    return value.value if isinstance(value, Enum) else value  # type: ignore[no-any-return]


def unwrap_partial(value: MaybePartial[T]) -> T:
    """Unwraps a partial, returning the underlying callable.

    Args:
        value: A partial function.

    Returns:
        Callable
    """
    from litestar.utils.sync import AsyncCallable

    return cast("T", value.func if isinstance(value, (partial, AsyncCallable)) else value)


def url_quote(value: str | bytes) -> str:
    """Quote a URL.

    Args:
        value: A URL.

    Returns:
        A quoted URL.
    """
    return quote(value, safe="/#%[]=:;$&()+,!?*@'~")


def unique_name_for_scope(base_name: str, scope: Container[str]) -> str:
    """Create a name derived from ``base_name`` that's unique within ``scope``"""
    i = 0
    while True:
        if (unique_name := f"{base_name}_{i}") not in scope:
            return unique_name
        i += 1


def get_exception_group() -> type[BaseException]:
    """Get the exception group class with version compatibility."""
    try:
        return cast("type[BaseException]", ExceptionGroup)  # type:ignore[name-defined]
    except NameError:
        from exceptiongroup import ExceptionGroup as _ExceptionGroup  # pyright: ignore

        return cast("type[BaseException]", _ExceptionGroup)