@@ -92,11 +92,28 @@ def __init__(
9292    def  __init_subclass__ (cls , / , * args , ** kwds ):
9393        raise  TypeError ("Cannot subclass ForwardRef" )
9494
95-     def  evaluate (self , * , globals = None , locals = None , type_params = None , owner = None ):
95+     def  evaluate (
96+         self ,
97+         * ,
98+         globals = None ,
99+         locals = None ,
100+         type_params = None ,
101+         owner = None ,
102+         format = Format .VALUE ,
103+     ):
96104        """Evaluate the forward reference and return the value. 
97105
98106        If the forward reference cannot be evaluated, raise an exception. 
99107        """ 
108+         match  format :
109+             case  Format .STRING :
110+                 return  self .__forward_arg__ 
111+             case  Format .VALUE :
112+                 is_forwardref_format  =  False 
113+             case  Format .FORWARDREF :
114+                 is_forwardref_format  =  True 
115+             case  _:
116+                 raise  NotImplementedError (format )
100117        if  self .__cell__  is  not None :
101118            try :
102119                return  self .__cell__ .cell_contents 
@@ -159,17 +176,36 @@ def evaluate(self, *, globals=None, locals=None, type_params=None, owner=None):
159176        arg  =  self .__forward_arg__ 
160177        if  arg .isidentifier () and  not  keyword .iskeyword (arg ):
161178            if  arg  in  locals :
162-                 value   =  locals [arg ]
179+                 return  locals [arg ]
163180            elif  arg  in  globals :
164-                 value   =  globals [arg ]
181+                 return  globals [arg ]
165182            elif  hasattr (builtins , arg ):
166183                return  getattr (builtins , arg )
184+             elif  is_forwardref_format :
185+                 return  self 
167186            else :
168187                raise  NameError (arg )
169188        else :
170189            code  =  self .__forward_code__ 
171-             value  =  eval (code , globals = globals , locals = locals )
172-         return  value 
190+             try :
191+                 return  eval (code , globals = globals , locals = locals )
192+             except  Exception :
193+                 if  not  is_forwardref_format :
194+                     raise 
195+             new_locals  =  _StringifierDict (
196+                 {** builtins .__dict__ , ** locals },
197+                 globals = globals ,
198+                 owner = owner ,
199+                 is_class = self .__forward_is_class__ ,
200+                 format = format ,
201+             )
202+             try :
203+                 result  =  eval (code , globals = globals , locals = new_locals )
204+             except  Exception :
205+                 return  self 
206+             else :
207+                 new_locals .transmogrify ()
208+                 return  result 
173209
174210    def  _evaluate (self , globalns , localns , type_params = _sentinel , * , recursive_guard ):
175211        import  typing 
@@ -546,6 +582,14 @@ def __missing__(self, key):
546582        self .stringifiers .append (fwdref )
547583        return  fwdref 
548584
585+     def  transmogrify (self ):
586+         for  obj  in  self .stringifiers :
587+             obj .__class__  =  ForwardRef 
588+             obj .__stringifier_dict__  =  None   # not needed for ForwardRef 
589+             if  isinstance (obj .__ast_node__ , str ):
590+                 obj .__arg__  =  obj .__ast_node__ 
591+                 obj .__ast_node__  =  None 
592+ 
549593    def  create_unique_name (self ):
550594        name  =  f"__annotationlib_name_{ self .next_id }  
551595        self .next_id  +=  1 
@@ -595,19 +639,10 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
595639        # convert each of those into a string to get an approximation of the 
596640        # original source. 
597641        globals  =  _StringifierDict ({}, format = format )
598-         if  annotate .__closure__ :
599-             freevars  =  annotate .__code__ .co_freevars 
600-             new_closure  =  []
601-             for  i , cell  in  enumerate (annotate .__closure__ ):
602-                 if  i  <  len (freevars ):
603-                     name  =  freevars [i ]
604-                 else :
605-                     name  =  "__cell__" 
606-                 fwdref  =  _Stringifier (name , stringifier_dict = globals )
607-                 new_closure .append (types .CellType (fwdref ))
608-             closure  =  tuple (new_closure )
609-         else :
610-             closure  =  None 
642+         is_class  =  isinstance (owner , type )
643+         closure  =  _build_closure (
644+             annotate , owner , is_class , globals , allow_evaluation = False 
645+         )
611646        func  =  types .FunctionType (
612647            annotate .__code__ ,
613648            globals ,
@@ -649,32 +684,36 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
649684            is_class = is_class ,
650685            format = format ,
651686        )
652-         if  annotate .__closure__ :
653-             freevars  =  annotate .__code__ .co_freevars 
654-             new_closure  =  []
655-             for  i , cell  in  enumerate (annotate .__closure__ ):
656-                 try :
657-                     cell .cell_contents 
658-                 except  ValueError :
659-                     if  i  <  len (freevars ):
660-                         name  =  freevars [i ]
661-                     else :
662-                         name  =  "__cell__" 
663-                     fwdref  =  _Stringifier (
664-                         name ,
665-                         cell = cell ,
666-                         owner = owner ,
667-                         globals = annotate .__globals__ ,
668-                         is_class = is_class ,
669-                         stringifier_dict = globals ,
670-                     )
671-                     globals .stringifiers .append (fwdref )
672-                     new_closure .append (types .CellType (fwdref ))
673-                 else :
674-                     new_closure .append (cell )
675-             closure  =  tuple (new_closure )
687+         closure  =  _build_closure (
688+             annotate , owner , is_class , globals , allow_evaluation = True 
689+         )
690+         func  =  types .FunctionType (
691+             annotate .__code__ ,
692+             globals ,
693+             closure = closure ,
694+             argdefs = annotate .__defaults__ ,
695+             kwdefaults = annotate .__kwdefaults__ ,
696+         )
697+         try :
698+             result  =  func (Format .VALUE_WITH_FAKE_GLOBALS )
699+         except  Exception :
700+             pass 
676701        else :
677-             closure  =  None 
702+             globals .transmogrify ()
703+             return  result 
704+ 
705+         # Try again, but do not provide any globals. This allows us to return 
706+         # a value in certain cases where an exception gets raised during evaluation. 
707+         globals  =  _StringifierDict (
708+             {},
709+             globals = annotate .__globals__ ,
710+             owner = owner ,
711+             is_class = is_class ,
712+             format = format ,
713+         )
714+         closure  =  _build_closure (
715+             annotate , owner , is_class , globals , allow_evaluation = False 
716+         )
678717        func  =  types .FunctionType (
679718            annotate .__code__ ,
680719            globals ,
@@ -683,13 +722,21 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
683722            kwdefaults = annotate .__kwdefaults__ ,
684723        )
685724        result  =  func (Format .VALUE_WITH_FAKE_GLOBALS )
686-         for  obj  in  globals .stringifiers :
687-             obj .__class__  =  ForwardRef 
688-             obj .__stringifier_dict__  =  None   # not needed for ForwardRef 
689-             if  isinstance (obj .__ast_node__ , str ):
690-                 obj .__arg__  =  obj .__ast_node__ 
691-                 obj .__ast_node__  =  None 
692-         return  result 
725+         globals .transmogrify ()
726+         if  _is_evaluate :
727+             if  isinstance (result , ForwardRef ):
728+                 return  result .evaluate (format = Format .FORWARDREF )
729+             else :
730+                 return  result 
731+         else :
732+             return  {
733+                 key : (
734+                     val .evaluate (format = Format .FORWARDREF )
735+                     if  isinstance (val , ForwardRef )
736+                     else  val 
737+                 )
738+                 for  key , val  in  result .items ()
739+             }
693740    elif  format  ==  Format .VALUE :
694741        # Should be impossible because __annotate__ functions must not raise 
695742        # NotImplementedError for this format. 
@@ -698,6 +745,39 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
698745        raise  ValueError (f"Invalid format: { format !r}  )
699746
700747
748+ def  _build_closure (annotate , owner , is_class , stringifier_dict , * , allow_evaluation ):
749+     if  not  annotate .__closure__ :
750+         return  None 
751+     freevars  =  annotate .__code__ .co_freevars 
752+     new_closure  =  []
753+     for  i , cell  in  enumerate (annotate .__closure__ ):
754+         if  i  <  len (freevars ):
755+             name  =  freevars [i ]
756+         else :
757+             name  =  "__cell__" 
758+         new_cell  =  None 
759+         if  allow_evaluation :
760+             try :
761+                 cell .cell_contents 
762+             except  ValueError :
763+                 pass 
764+             else :
765+                 new_cell  =  cell 
766+         if  new_cell  is  None :
767+             fwdref  =  _Stringifier (
768+                 name ,
769+                 cell = cell ,
770+                 owner = owner ,
771+                 globals = annotate .__globals__ ,
772+                 is_class = is_class ,
773+                 stringifier_dict = stringifier_dict ,
774+             )
775+             stringifier_dict .stringifiers .append (fwdref )
776+             new_cell  =  types .CellType (fwdref )
777+         new_closure .append (new_cell )
778+     return  tuple (new_closure )
779+ 
780+ 
701781def  _stringify_single (anno ):
702782    if  anno  is  ...:
703783        return  "..." 
@@ -809,7 +889,7 @@ def get_annotations(
809889            # But if we didn't get it, we use __annotations__ instead. 
810890            ann  =  _get_dunder_annotations (obj )
811891            if  ann  is  not None :
812-                   return  annotations_to_string (ann )
892+                 return  annotations_to_string (ann )
813893        case  Format .VALUE_WITH_FAKE_GLOBALS :
814894            raise  ValueError ("The VALUE_WITH_FAKE_GLOBALS format is for internal use only" )
815895        case  _:
0 commit comments