From fdc71695dc2c5413101df9c7eb54a19cbd3df379 Mon Sep 17 00:00:00 2001 From: Rapptz Date: Wed, 22 Aug 2018 23:03:07 -0400 Subject: [PATCH] [commands] Use eval instead of get_type_hints to resolve typehints The previous usage of `typing.get_type_hints` caused issues as it would incorrectly decide to convert annotations into their equivalent `typing` form -- which is not what we want to happen here. Due to some use-cases about how setting `Command.callback` work and the amount of moving parts that have changed due to this patch, it is probably better to refactor the way it is set so users can have this use-case handled transparently for them. --- discord/ext/commands/core.py | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/discord/ext/commands/core.py b/discord/ext/commands/core.py index 5cab60031..22882f4ea 100644 --- a/discord/ext/commands/core.py +++ b/discord/ext/commands/core.py @@ -174,21 +174,7 @@ class Command: self.description = inspect.cleandoc(kwargs.get('description', '')) self.hidden = kwargs.get('hidden', False) - signature = inspect.signature(callback) - annotations = typing.get_type_hints(callback) - - self.params = signature.parameters.copy() - - # PEP-563 allows postponing evaluation of annotations with a __future__ - # import. When postponed, Parameter.annotation will be a string and must - # be replaced with the real class from typing.get_type_hints() for the - # converters to work later on - for key, value in self.params.items(): - if isinstance(value.annotation, str) and key in annotations: - self.params[key] = value.replace(annotation=annotations[key]) - self.checks = kwargs.get('checks', []) - self.module = callback.__module__ self.ignore_extra = kwargs.get('ignore_extra', True) self.instance = None self.parent = None @@ -196,6 +182,25 @@ class Command: self._before_invoke = None self._after_invoke = None + @property + def callback(self): + return self._callback + + @callback.setter + def callback(self, function): + self._callback = function + self.module = function.__module__ + + signature = inspect.signature(function) + self.params = signature.parameters.copy() + + # PEP-563 allows postponing evaluation of annotations with a __future__ + # import. When postponed, Parameter.annotation will be a string and must + # be replaced with the real value for the converters to work later on + for key, value in self.params.items(): + if isinstance(value.annotation, str): + self.params[key] = value.replace(annotation=eval(value.annotation, function.__globals__)) + async def dispatch_error(self, ctx, error): ctx.command_failed = True cog = self.instance