1111 wait ,
1212)
1313from collections import Counter
14- from collections .abc import Iterator
14+ from collections .abc import Sequence
1515from contextlib import AsyncExitStack
1616from logging import getLogger
1717from typing import (
2727from weakref import ref as weakref
2828
2929from anyio import Semaphore
30+ from typing_extensions import TypeAlias
3031
3132from reactpy .config import (
3233 REACTPY_ASYNC_RENDERING ,
3738from reactpy .core .types import (
3839 ComponentType ,
3940 EventHandlerDict ,
41+ Key ,
4042 LayoutEventMessage ,
4143 LayoutUpdateMessage ,
4244 VdomChild ,
@@ -328,11 +330,11 @@ async def _render_model_children(
328330 await self ._unmount_model_states (list (old_state .children_by_key .values ()))
329331 return None
330332
331- child_type_key_tuples = list ( _process_child_type_and_key ( raw_children ) )
333+ children_info = _get_children_info ( raw_children )
332334
333- new_keys = {item [ 2 ] for item in child_type_key_tuples }
334- if len (new_keys ) != len (child_type_key_tuples ):
335- key_counter = Counter (item [2 ] for item in child_type_key_tuples )
335+ new_keys = {k for _ , _ , k in children_info }
336+ if len (new_keys ) != len (children_info ):
337+ key_counter = Counter (item [2 ] for item in children_info )
336338 duplicate_keys = [key for key , count in key_counter .items () if count > 1 ]
337339 msg = f"Duplicate keys { duplicate_keys } at { new_state .patch_path or '/' !r} "
338340 raise ValueError (msg )
@@ -344,7 +346,7 @@ async def _render_model_children(
344346 )
345347
346348 new_state .model .current ["children" ] = []
347- for index , (child , child_type , key ) in enumerate (child_type_key_tuples ):
349+ for index , (child , child_type , key ) in enumerate (children_info ):
348350 old_child_state = old_state .children_by_key .get (key )
349351 if child_type is _DICT_TYPE :
350352 old_child_state = old_state .children_by_key .get (key )
@@ -419,17 +421,17 @@ async def _render_model_children_without_old_state(
419421 new_state : _ModelState ,
420422 raw_children : list [Any ],
421423 ) -> None :
422- child_type_key_tuples = list ( _process_child_type_and_key ( raw_children ) )
424+ children_info = _get_children_info ( raw_children )
423425
424- new_keys = {item [ 2 ] for item in child_type_key_tuples }
425- if len (new_keys ) != len (child_type_key_tuples ):
426- key_counter = Counter (item [ 2 ] for item in child_type_key_tuples )
426+ new_keys = {k for _ , _ , k in children_info }
427+ if len (new_keys ) != len (children_info ):
428+ key_counter = Counter (k for _ , _ , k in children_info )
427429 duplicate_keys = [key for key , count in key_counter .items () if count > 1 ]
428430 msg = f"Duplicate keys { duplicate_keys } at { new_state .patch_path or '/' !r} "
429431 raise ValueError (msg )
430432
431433 new_state .model .current ["children" ] = []
432- for index , (child , child_type , key ) in enumerate (child_type_key_tuples ):
434+ for index , (child , child_type , key ) in enumerate (children_info ):
433435 if child_type is _DICT_TYPE :
434436 child_state = _make_element_model_state (new_state , index , key )
435437 await self ._render_model (exit_stack , None , child_state , child )
@@ -608,7 +610,7 @@ def __init__(
608610 key : Any ,
609611 model : Ref [VdomJson ],
610612 patch_path : str ,
611- children_by_key : dict [str , _ModelState ],
613+ children_by_key : dict [Key , _ModelState ],
612614 targets_by_event : dict [str , str ],
613615 life_cycle_state : _LifeCycleState | None = None ,
614616 ):
@@ -719,9 +721,8 @@ async def get(self) -> _Type:
719721 return value
720722
721723
722- def _process_child_type_and_key (
723- children : list [VdomChild ],
724- ) -> Iterator [tuple [Any , _ElementType , Any ]]:
724+ def _get_children_info (children : list [VdomChild ]) -> Sequence [_ChildInfo ]:
725+ infos : list [_ChildInfo ] = []
725726 for index , child in enumerate (children ):
726727 if child is None :
727728 continue
@@ -730,7 +731,7 @@ def _process_child_type_and_key(
730731 key = child .get ("key" )
731732 elif isinstance (child , ComponentType ):
732733 child_type = _COMPONENT_TYPE
733- key = getattr ( child , " key" , None )
734+ key = child . key
734735 else :
735736 child = f"{ child } "
736737 child_type = _STRING_TYPE
@@ -739,8 +740,12 @@ def _process_child_type_and_key(
739740 if key is None :
740741 key = index
741742
742- yield ( child , child_type , key )
743+ infos . append (( child , child_type , key ) )
743744
745+ return infos
746+
747+
748+ _ChildInfo : TypeAlias = tuple [Any , "_ElementType" , Key ]
744749
745750# used in _process_child_type_and_key
746751_ElementType = NewType ("_ElementType" , int )
0 commit comments