aboutsummaryrefslogtreecommitdiff
path: root/discord
diff options
context:
space:
mode:
authorNadir Chowdhury <[email protected]>2021-04-07 04:24:23 +0100
committerGitHub <[email protected]>2021-04-06 23:24:23 -0400
commit7a34de1570f77b76e78d4309296ea6d16b99a760 (patch)
tree896b4db3ac17f0e13c8b218ef3cfc0f3901c7581 /discord
parentUse non-underscore TypeVar in enum code (diff)
downloaddiscord.py-7a34de1570f77b76e78d4309296ea6d16b99a760.tar.xz
discord.py-7a34de1570f77b76e78d4309296ea6d16b99a760.zip
[commands] Use typing.get_type_hints to resolve ForwardRefs
Diffstat (limited to 'discord')
-rw-r--r--discord/ext/commands/core.py31
1 files changed, 25 insertions, 6 deletions
diff --git a/discord/ext/commands/core.py b/discord/ext/commands/core.py
index cc48a2ce..09661d9c 100644
--- a/discord/ext/commands/core.py
+++ b/discord/ext/commands/core.py
@@ -27,6 +27,7 @@ import functools
import inspect
import typing
import datetime
+import sys
import discord
@@ -299,17 +300,35 @@ class Command(_BaseCommand):
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 = value.replace(annotation=eval(value.annotation, function.__globals__))
+ # see: https://bugs.python.org/issue41341
+ resolve = self._recursive_resolve if sys.version_info < (3, 9) else self._return_resolved
+
+ try:
+ type_hints = {k: resolve(v) for k, v in typing.get_type_hints(function).items()}
+ except NameError as e:
+ raise NameError(f'unresolved forward reference: {e.args[0]}') from None
+ for key, value in self.params.items():
+ # coalesce the forward references
+ self.params[key] = value = value.replace(annotation=type_hints.get(key))
# fail early for when someone passes an unparameterized Greedy type
if value.annotation is converters.Greedy:
raise TypeError('Unparameterized Greedy[...] is disallowed in signature.')
+ def _return_resolved(self, type, **kwargs):
+ return type
+
+ def _recursive_resolve(self, type, *, globals=None):
+ if not isinstance(type, typing.ForwardRef):
+ return type
+
+ resolved = eval(type.__forward_arg__, globals)
+ args = typing.get_args(resolved)
+ for index, arg in enumerate(args):
+ inner_resolve_result = self._recursive_resolve(arg, globals=globals)
+ resolved[index] = inner_resolve_result
+ return resolved
+
def add_check(self, func):
"""Adds a check to the command.