mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-09-05 01:16:21 +00:00
Refactor transformers to use instances instead of classmethods
This should allow them to be easier to use for users without requiring a lot of metaprogramming hackery if you want to involve state.
This commit is contained in:
@ -116,18 +116,24 @@ def required_pos_arguments(func: Callable[..., Any]) -> int:
|
||||
return sum(p.default is p.empty for p in sig.parameters.values())
|
||||
|
||||
|
||||
def make_converter_transformer(converter: Any, parameter: Parameter) -> Type[app_commands.Transformer]:
|
||||
try:
|
||||
module = converter.__module__
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if module is not None and (module.startswith('discord.') and not module.endswith('converter')):
|
||||
converter = CONVERTER_MAPPING.get(converter, converter)
|
||||
class ConverterTransformer(app_commands.Transformer):
|
||||
def __init__(self, converter: Any, parameter: Parameter) -> None:
|
||||
super().__init__()
|
||||
self.converter: Any = converter
|
||||
self.parameter: Parameter = parameter
|
||||
|
||||
async def transform(cls, interaction: discord.Interaction, value: str) -> Any:
|
||||
try:
|
||||
module = converter.__module__
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
if module is not None and (module.startswith('discord.') and not module.endswith('converter')):
|
||||
self.converter = CONVERTER_MAPPING.get(converter, converter)
|
||||
|
||||
async def transform(self, interaction: discord.Interaction, value: str) -> Any:
|
||||
ctx = interaction._baton
|
||||
ctx.current_parameter = parameter
|
||||
converter = self.converter
|
||||
ctx.current_parameter = self.parameter
|
||||
ctx.current_argument = value
|
||||
try:
|
||||
if inspect.isclass(converter) and issubclass(converter, Converter):
|
||||
@ -142,27 +148,34 @@ def make_converter_transformer(converter: Any, parameter: Parameter) -> Type[app
|
||||
except Exception as exc:
|
||||
raise ConversionError(converter, exc) from exc # type: ignore
|
||||
|
||||
return type('ConverterTransformer', (app_commands.Transformer,), {'transform': classmethod(transform)})
|
||||
|
||||
class CallableTransformer(app_commands.Transformer):
|
||||
def __init__(self, func: Callable[[str], Any]) -> None:
|
||||
super().__init__()
|
||||
self.func: Callable[[str], Any] = func
|
||||
|
||||
def make_callable_transformer(func: Callable[[str], Any]) -> Type[app_commands.Transformer]:
|
||||
async def transform(cls, interaction: discord.Interaction, value: str) -> Any:
|
||||
async def transform(self, interaction: discord.Interaction, value: str) -> Any:
|
||||
try:
|
||||
return func(value)
|
||||
return self.func(value)
|
||||
except CommandError:
|
||||
raise
|
||||
except Exception as exc:
|
||||
raise BadArgument(f'Converting to "{func.__name__}" failed') from exc
|
||||
|
||||
return type('CallableTransformer', (app_commands.Transformer,), {'transform': classmethod(transform)})
|
||||
raise BadArgument(f'Converting to "{self.func.__name__}" failed') from exc
|
||||
|
||||
|
||||
def make_greedy_transformer(converter: Any, parameter: Parameter) -> Type[app_commands.Transformer]:
|
||||
async def transform(cls, interaction: discord.Interaction, value: str) -> Any:
|
||||
class GreedyTransformer(app_commands.Transformer):
|
||||
def __init__(self, converter: Any, parameter: Parameter) -> None:
|
||||
super().__init__()
|
||||
self.converter: Any = converter
|
||||
self.parameter: Parameter = parameter
|
||||
|
||||
async def transform(self, interaction: discord.Interaction, value: str) -> Any:
|
||||
view = StringView(value)
|
||||
result = []
|
||||
ctx = interaction._baton
|
||||
ctx.current_parameter = parameter
|
||||
ctx.current_parameter = parameter = self.parameter
|
||||
converter = self.converter
|
||||
|
||||
while True:
|
||||
view.skip_ws()
|
||||
ctx.current_argument = arg = view.get_quoted_word()
|
||||
@ -175,8 +188,6 @@ def make_greedy_transformer(converter: Any, parameter: Parameter) -> Type[app_co
|
||||
|
||||
return result
|
||||
|
||||
return type('GreedyTransformer', (app_commands.Transformer,), {'transform': classmethod(transform)})
|
||||
|
||||
|
||||
def replace_parameter(
|
||||
param: inspect.Parameter,
|
||||
@ -203,7 +214,7 @@ def replace_parameter(
|
||||
if inner is discord.Attachment:
|
||||
raise TypeError('discord.Attachment with Greedy is not supported in hybrid commands')
|
||||
|
||||
param = param.replace(annotation=make_greedy_transformer(inner, original))
|
||||
param = param.replace(annotation=GreedyTransformer(inner, original))
|
||||
elif is_flag(converter):
|
||||
callback.__hybrid_command_flag__ = (param.name, converter)
|
||||
descriptions = {}
|
||||
@ -233,14 +244,14 @@ def replace_parameter(
|
||||
app_commands.rename(**renames)(callback)
|
||||
|
||||
elif is_converter(converter) or converter in CONVERTER_MAPPING:
|
||||
param = param.replace(annotation=make_converter_transformer(converter, original))
|
||||
param = param.replace(annotation=ConverterTransformer(converter, original))
|
||||
elif origin is Union:
|
||||
if len(args) == 2 and args[-1] is _NoneType:
|
||||
# Special case Optional[X] where X is a single type that can optionally be a converter
|
||||
inner = args[0]
|
||||
is_inner_transformer = is_transformer(inner)
|
||||
if is_converter(inner) and not is_inner_transformer:
|
||||
param = param.replace(annotation=Optional[make_converter_transformer(inner, original)]) # type: ignore
|
||||
param = param.replace(annotation=Optional[ConverterTransformer(inner, original)]) # type: ignore
|
||||
else:
|
||||
raise
|
||||
elif origin:
|
||||
@ -250,7 +261,7 @@ def replace_parameter(
|
||||
param_count = required_pos_arguments(converter)
|
||||
if param_count != 1:
|
||||
raise
|
||||
param = param.replace(annotation=make_callable_transformer(converter))
|
||||
param = param.replace(annotation=CallableTransformer(converter))
|
||||
|
||||
return param
|
||||
|
||||
|
Reference in New Issue
Block a user