diff --git a/discord/ext/commands/converter.py b/discord/ext/commands/converter.py index fab826db7..1f1828b19 100644 --- a/discord/ext/commands/converter.py +++ b/discord/ext/commands/converter.py @@ -905,6 +905,13 @@ def get_converter(param: inspect.Parameter) -> Any: return converter +_GenericAlias = type(List[T]) + + +def is_generic_type(tp: Any, *, _GenericAlias: Type = _GenericAlias) -> bool: + return isinstance(tp, type) and issubclass(tp, Generic) or isinstance(tp, _GenericAlias) # type: ignore + + CONVERTER_MAPPING: Dict[Type[Any], Any] = { discord.Object: ObjectConverter, discord.Member: MemberConverter, @@ -996,9 +1003,6 @@ async def run_converters(ctx: Context, converter, argument: str, param: inspect. """ origin = getattr(converter, '__origin__', None) - if origin is not None and issubclass(converter, Generic): # type: ignore - converter = origin - if origin is Union: errors = [] _NoneType = type(None) @@ -1045,4 +1049,11 @@ async def run_converters(ctx: Context, converter, argument: str, param: inspect. # if we're here, then we failed to match all the literals raise BadLiteralArgument(param, literal_args, errors) + # This must be the last if-clause in the chain of origin checking + # Nearly every type is a generic type within the typing library + # So care must be taken to make sure a more specialised origin handle + # isn't overwritten by the widest if clause + if origin is not None and is_generic_type(converter): + converter = origin + return await _actual_conversion(ctx, converter, argument, param)