Repository: Rapptz/discord.py
File: discord/ext/commands/converter.py (Python)

Code before:
            if annotation not in (int, float, str):
                raise TypeError(f'expected int, float, or str as range type, received {annotation!r} instead')

            if annotation in (str, int):
                cast = int
            else:
                cast = float

            return cls(
                annotation=annotation,
                min=cast(min) if min is not None else None,
                max=cast(max) if max is not None else None,
            )


def _convert_to_bool(argument: str) -> bool:
    lowered = argument.lower()
    if lowered in ('yes', 'y', 'true', 't', '1', 'enable', 'on'):
        return True
    elif lowered in ('no', 'n', 'false', 'f', '0', 'disable', 'off'):
        return False
    else:
        raise BadBoolArgument(lowered)


_TIMESTAMP_PATTERN: re.Pattern[str] = re.compile(r'<t:(\d+):[tTdDfFsSR]>')


def _convert_from_timestamp(argument: str) -> datetime.datetime:
    match = _TIMESTAMP_PATTERN.match(argument)
    if not match:
        raise BadDatetimeArgument(argument)
    dt = datetime.datetime.fromtimestamp(int(match[1]))

    return dt.replace(tzinfo=datetime.timezone.utc)


_GenericAlias = type(List[T])  # type: ignore


def is_generic_type(tp: Any, *, _GenericAlias: type = _GenericAlias) -> bool:
    return isinstance(tp, type) and issubclass(tp, Generic) or isinstance(tp, _GenericAlias)


CONVERTER_MAPPING: Dict[type, Any] = {
    discord.Object: ObjectConverter,
    discord.Member: MemberConverter,
    discord.User: UserConverter,
    discord.Message: MessageConverter,
    discord.PartialMessage: PartialMessageConverter,
    discord.TextChannel: TextChannelConverter,

Review comment (suggestion):
Not keen on re-creating the same constant for both transformer and converter, but I wasn't sure where else I could put this to import from outside of `utils`.

Code after:

        def __repr__(self) -> str:
            return f'{self.__class__.__name__}[{self.annotation.__name__}, {self.min}, {self.max}]'

        def __class_getitem__(cls, obj) -> Range:
            if not isinstance(obj, tuple):
                raise TypeError(f'expected tuple for arguments, received {obj.__class__.__name__} instead')

            if len(obj) == 2:
                obj = (*obj, None)
            elif len(obj) != 3:
                raise TypeError('Range accepts either two or three arguments with the first being the type of range.')

            annotation, min, max = obj

            if min is None and max is None:
                raise TypeError('Range must not be empty')

            if min is not None and max is not None:
                # At this point max and min are both not none
                if type(min) != type(max):
                    raise TypeError('Both min and max in Range must be the same type')

            if annotation not in (int, float, str):
                raise TypeError(f'expected int, float, or str as range type, received {annotation!r} instead')

            if annotation in (str, int):
                cast = int
            else:
                cast = float

            return cls(
                annotation=annotation,
                min=cast(min) if min is not None else None,
                max=cast(max) if max is not None else None,
            )


def _convert_to_bool(argument: str) -> bool:
    lowered = argument.lower()
    if lowered in ('yes', 'y', 'true', 't', '1', 'enable', 'on'):
        return True
    elif lowered in ('no', 'n', 'false', 'f', '0', 'disable', 'off'):
        return False
    else:
        raise BadBoolArgument(lowered)


_GenericAlias = type(List[T])  # type: ignore