@@ -664,28 +664,38 @@ def get_annotations(
664
664
if eval_str and format != Format .VALUE :
665
665
raise ValueError ("eval_str=True is only supported with format=Format.VALUE" )
666
666
667
- # For VALUE format, we look at __annotations__ directly.
668
- if format != Format .VALUE :
669
- annotate = get_annotate_function (obj )
670
- if annotate is not None :
671
- ann = call_annotate_function (annotate , format , owner = obj )
672
- if not isinstance (ann , dict ):
673
- raise ValueError (f"{ obj !r} .__annotate__ returned a non-dict" )
674
- return dict (ann )
675
-
676
- if isinstance (obj , type ):
677
- try :
678
- ann = _BASE_GET_ANNOTATIONS (obj )
679
- except AttributeError :
680
- # For static types, the descriptor raises AttributeError.
681
- return {}
682
- else :
683
- ann = getattr (obj , "__annotations__" , None )
684
- if ann is None :
685
- return {}
686
-
687
- if not isinstance (ann , dict ):
688
- raise ValueError (f"{ obj !r} .__annotations__ is neither a dict nor None" )
667
+ match format :
668
+ case Format .VALUE :
669
+ # For VALUE, we only look at __annotations__
670
+ ann = _get_dunder_annotations (obj )
671
+ case Format .FORWARDREF :
672
+ # For FORWARDREF, we use __annotations__ if it exists
673
+ try :
674
+ ann = _get_dunder_annotations (obj )
675
+ except NameError :
676
+ pass
677
+ else :
678
+ return dict (ann )
679
+
680
+ # But if __annotations__ threw a NameError, we try calling __annotate__
681
+ ann = _get_and_call_annotate (obj , format )
682
+ if ann is not None :
683
+ return ann
684
+
685
+ # If that didn't work either, we have a very weird object: evaluating
686
+ # __annotations__ threw NameError and there is no __annotate__. In that case,
687
+ # we fall back to trying __annotations__ again.
688
+ return dict (_get_dunder_annotations (obj ))
689
+ case Format .SOURCE :
690
+ # For SOURCE, we try to call __annotate__
691
+ ann = _get_and_call_annotate (obj , format )
692
+ if ann is not None :
693
+ return ann
694
+ # But if we didn't get it, we use __annotations__ instead.
695
+ ann = _get_dunder_annotations (obj )
696
+ return ann
697
+ case _:
698
+ raise ValueError (f"Unsupported format { format !r} " )
689
699
690
700
if not ann :
691
701
return {}
@@ -750,3 +760,30 @@ def get_annotations(
750
760
for key , value in ann .items ()
751
761
}
752
762
return return_value
763
+
764
+
765
+ def _get_and_call_annotate (obj , format ):
766
+ annotate = get_annotate_function (obj )
767
+ if annotate is not None :
768
+ ann = call_annotate_function (annotate , format , owner = obj )
769
+ if not isinstance (ann , dict ):
770
+ raise ValueError (f"{ obj !r} .__annotate__ returned a non-dict" )
771
+ return dict (ann )
772
+ return None
773
+
774
+
775
+ def _get_dunder_annotations (obj ):
776
+ if isinstance (obj , type ):
777
+ try :
778
+ ann = _BASE_GET_ANNOTATIONS (obj )
779
+ except AttributeError :
780
+ # For static types, the descriptor raises AttributeError.
781
+ return {}
782
+ else :
783
+ ann = getattr (obj , "__annotations__" , None )
784
+ if ann is None :
785
+ return {}
786
+
787
+ if not isinstance (ann , dict ):
788
+ raise ValueError (f"{ obj !r} .__annotations__ is neither a dict nor None" )
789
+ return dict (ann )
0 commit comments