From c342db853486ef6e26d72b10bf901e951c4b4d8e Mon Sep 17 00:00:00 2001 From: Rapptz Date: Wed, 12 Nov 2025 20:17:43 -0500 Subject: [PATCH] [commands] Fix flag annotations in 3.14 using annotationlib Fix #10349 --- discord/ext/commands/flags.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/discord/ext/commands/flags.py b/discord/ext/commands/flags.py index 09d925232..10d036f8a 100644 --- a/discord/ext/commands/flags.py +++ b/discord/ext/commands/flags.py @@ -50,6 +50,25 @@ if TYPE_CHECKING: from .context import Context from .parameters import Parameter +try: + from annotationlib import call_annotate_function, get_annotate_from_class_namespace # type: ignore + + def get_annotations_from_namespace(namespace: Dict[str, Any]) -> Dict[str, Any]: + # In Python 3.14, classes no longer get `__annotations__` and instead a function + # under __annotate__ is used instead that that takes a format argument on how to + # receive those annotations. + # Format 1 is full value, Format 3 is value and ForwardRef for undefined ones + # So format 3 is the one we're typically used to + annotate = get_annotate_from_class_namespace(namespace) + if annotate is not None: + return call_annotate_function(annotate, 3) # type: ignore + return namespace.get('__annotations__', {}) + +except ImportError: + + def get_annotations_from_namespace(namespace: Dict[str, Any]) -> Dict[str, Any]: + return namespace.get('__annotations__', {}) + @dataclass class Flag: @@ -177,15 +196,7 @@ def validate_flag_name(name: str, forbidden: Set[str]) -> None: def get_flags(namespace: Dict[str, Any], globals: Dict[str, Any], locals: Dict[str, Any]) -> Dict[str, Flag]: - annotations = namespace.get('__annotations__', {}) - if '__annotate__' in namespace: - # In Python 3.14, classes no longer get `__annotations__` and instead a function - # under __annotate__ is used instead that that takes a format argument on how to - # receive those annotations. - # Format 1 is full value, Format 3 is value and ForwardRef for undefined ones - # So format 3 is the one we're typically used to - annotations = namespace['__annotate__'](3) - + annotations = get_annotations_from_namespace(namespace) case_insensitive = namespace['__commands_flag_case_insensitive__'] flags: Dict[str, Flag] = {} cache: Dict[str, Any] = {}