@@ -85,6 +85,9 @@ def __init__(
8585        # These are always set to None here but may be non-None if a ForwardRef 
8686        # is created through __class__ assignment on a _Stringifier object. 
8787        self .__globals__  =  None 
88+         # This may be either a cell object (for a ForwardRef referring to a single name) 
89+         # or a dict mapping cell names to cell objects (for a ForwardRef containing references 
90+         # to multiple names). 
8891        self .__cell__  =  None 
8992        self .__extra_names__  =  None 
9093        # These are initially None but serve as a cache and may be set to a non-None 
@@ -117,7 +120,7 @@ def evaluate(
117120                is_forwardref_format  =  True 
118121            case  _:
119122                raise  NotImplementedError (format )
120-         if  self .__cell__   is   not   None :
123+         if  isinstance ( self .__cell__ ,  types . CellType ) :
121124            try :
122125                return  self .__cell__ .cell_contents 
123126            except  ValueError :
@@ -160,11 +163,18 @@ def evaluate(
160163
161164        # Type parameters exist in their own scope, which is logically 
162165        # between the locals and the globals. We simulate this by adding 
163-         # them to the globals. 
164-         if  type_params  is  not   None :
166+         # them to the globals. Similar reasoning applies to nonlocals stored in cells.  
167+         if  type_params  is  not   None   or   isinstance ( self . __cell__ ,  dict ) :
165168            globals  =  dict (globals )
169+         if  type_params  is  not   None :
166170            for  param  in  type_params :
167171                globals [param .__name__ ] =  param 
172+         if  isinstance (self .__cell__ , dict ):
173+             for  cell_name , cell_value  in  self .__cell__ .items ():
174+                 try :
175+                     globals [cell_name ] =  cell_value .cell_contents 
176+                 except  ValueError :
177+                     pass 
168178        if  self .__extra_names__ :
169179            locals  =  {** locals , ** self .__extra_names__ }
170180
@@ -199,7 +209,7 @@ def evaluate(
199209            except  Exception :
200210                return  self 
201211            else :
202-                 new_locals .transmogrify ()
212+                 new_locals .transmogrify (self . __cell__ )
203213                return  result 
204214
205215    def  _evaluate (self , globalns , localns , type_params = _sentinel , * , recursive_guard ):
@@ -278,7 +288,7 @@ def __hash__(self):
278288            self .__forward_module__ ,
279289            id (self .__globals__ ),  # dictionaries are not hashable, so hash by identity 
280290            self .__forward_is_class__ ,
281-             self .__cell__ ,
291+             tuple ( sorted ( self . __cell__ . items ()))  if   isinstance ( self . __cell__ ,  dict )  else   self .__cell__ ,
282292            self .__owner__ ,
283293            tuple (sorted (self .__extra_names__ .items ())) if  self .__extra_names__  else  None ,
284294        ))
@@ -608,13 +618,15 @@ def __missing__(self, key):
608618        self .stringifiers .append (fwdref )
609619        return  fwdref 
610620
611-     def  transmogrify (self ):
621+     def  transmogrify (self ,  cell_dict ):
612622        for  obj  in  self .stringifiers :
613623            obj .__class__  =  ForwardRef 
614624            obj .__stringifier_dict__  =  None   # not needed for ForwardRef 
615625            if  isinstance (obj .__ast_node__ , str ):
616626                obj .__arg__  =  obj .__ast_node__ 
617627                obj .__ast_node__  =  None 
628+             if  cell_dict  is  not   None  and  obj .__cell__  is  None :
629+                 obj .__cell__  =  cell_dict 
618630
619631    def  create_unique_name (self ):
620632        name  =  f"__annotationlib_name_{ self .next_id }  __" 
@@ -666,7 +678,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
666678        # original source. 
667679        globals  =  _StringifierDict ({}, format = format )
668680        is_class  =  isinstance (owner , type )
669-         closure  =  _build_closure (
681+         closure ,  _  =  _build_closure (
670682            annotate , owner , is_class , globals , allow_evaluation = False 
671683        )
672684        func  =  types .FunctionType (
@@ -710,7 +722,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
710722            is_class = is_class ,
711723            format = format ,
712724        )
713-         closure  =  _build_closure (
725+         closure ,  cell_dict  =  _build_closure (
714726            annotate , owner , is_class , globals , allow_evaluation = True 
715727        )
716728        func  =  types .FunctionType (
@@ -725,7 +737,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
725737        except  Exception :
726738            pass 
727739        else :
728-             globals .transmogrify ()
740+             globals .transmogrify (cell_dict )
729741            return  result 
730742
731743        # Try again, but do not provide any globals. This allows us to return 
@@ -737,7 +749,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
737749            is_class = is_class ,
738750            format = format ,
739751        )
740-         closure  =  _build_closure (
752+         closure ,  cell_dict  =  _build_closure (
741753            annotate , owner , is_class , globals , allow_evaluation = False 
742754        )
743755        func  =  types .FunctionType (
@@ -748,7 +760,7 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
748760            kwdefaults = annotate .__kwdefaults__ ,
749761        )
750762        result  =  func (Format .VALUE_WITH_FAKE_GLOBALS )
751-         globals .transmogrify ()
763+         globals .transmogrify (cell_dict )
752764        if  _is_evaluate :
753765            if  isinstance (result , ForwardRef ):
754766                return  result .evaluate (format = Format .FORWARDREF )
@@ -773,14 +785,16 @@ def call_annotate_function(annotate, format, *, owner=None, _is_evaluate=False):
773785
774786def  _build_closure (annotate , owner , is_class , stringifier_dict , * , allow_evaluation ):
775787    if  not  annotate .__closure__ :
776-         return  None 
788+         return  None ,  None 
777789    freevars  =  annotate .__code__ .co_freevars 
778790    new_closure  =  []
791+     cell_dict  =  {}
779792    for  i , cell  in  enumerate (annotate .__closure__ ):
780793        if  i  <  len (freevars ):
781794            name  =  freevars [i ]
782795        else :
783796            name  =  "__cell__" 
797+         cell_dict [name ] =  cell 
784798        new_cell  =  None 
785799        if  allow_evaluation :
786800            try :
@@ -801,7 +815,7 @@ def _build_closure(annotate, owner, is_class, stringifier_dict, *, allow_evaluat
801815            stringifier_dict .stringifiers .append (fwdref )
802816            new_cell  =  types .CellType (fwdref )
803817        new_closure .append (new_cell )
804-     return  tuple (new_closure )
818+     return  tuple (new_closure ),  cell_dict 
805819
806820
807821def  _stringify_single (anno ):
0 commit comments