11
11
wait ,
12
12
)
13
13
from collections import Counter
14
- from collections .abc import Iterator
14
+ from collections .abc import Sequence
15
15
from contextlib import AsyncExitStack
16
16
from logging import getLogger
17
17
from typing import (
27
27
from weakref import ref as weakref
28
28
29
29
from anyio import Semaphore
30
+ from typing_extensions import TypeAlias
30
31
31
32
from reactpy .config import (
32
33
REACTPY_ASYNC_RENDERING ,
37
38
from reactpy .core .types import (
38
39
ComponentType ,
39
40
EventHandlerDict ,
41
+ Key ,
40
42
LayoutEventMessage ,
41
43
LayoutUpdateMessage ,
42
44
VdomChild ,
@@ -328,11 +330,11 @@ async def _render_model_children(
328
330
await self ._unmount_model_states (list (old_state .children_by_key .values ()))
329
331
return None
330
332
331
- child_type_key_tuples = list ( _process_child_type_and_key ( raw_children ) )
333
+ children_info = _get_children_info ( raw_children )
332
334
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 )
336
338
duplicate_keys = [key for key , count in key_counter .items () if count > 1 ]
337
339
msg = f"Duplicate keys { duplicate_keys } at { new_state .patch_path or '/' !r} "
338
340
raise ValueError (msg )
@@ -344,7 +346,7 @@ async def _render_model_children(
344
346
)
345
347
346
348
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 ):
348
350
old_child_state = old_state .children_by_key .get (key )
349
351
if child_type is _DICT_TYPE :
350
352
old_child_state = old_state .children_by_key .get (key )
@@ -419,17 +421,17 @@ async def _render_model_children_without_old_state(
419
421
new_state : _ModelState ,
420
422
raw_children : list [Any ],
421
423
) -> None :
422
- child_type_key_tuples = list ( _process_child_type_and_key ( raw_children ) )
424
+ children_info = _get_children_info ( raw_children )
423
425
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 )
427
429
duplicate_keys = [key for key , count in key_counter .items () if count > 1 ]
428
430
msg = f"Duplicate keys { duplicate_keys } at { new_state .patch_path or '/' !r} "
429
431
raise ValueError (msg )
430
432
431
433
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 ):
433
435
if child_type is _DICT_TYPE :
434
436
child_state = _make_element_model_state (new_state , index , key )
435
437
await self ._render_model (exit_stack , None , child_state , child )
@@ -608,7 +610,7 @@ def __init__(
608
610
key : Any ,
609
611
model : Ref [VdomJson ],
610
612
patch_path : str ,
611
- children_by_key : dict [str , _ModelState ],
613
+ children_by_key : dict [Key , _ModelState ],
612
614
targets_by_event : dict [str , str ],
613
615
life_cycle_state : _LifeCycleState | None = None ,
614
616
):
@@ -719,9 +721,8 @@ async def get(self) -> _Type:
719
721
return value
720
722
721
723
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 ] = []
725
726
for index , child in enumerate (children ):
726
727
if child is None :
727
728
continue
@@ -730,7 +731,7 @@ def _process_child_type_and_key(
730
731
key = child .get ("key" )
731
732
elif isinstance (child , ComponentType ):
732
733
child_type = _COMPONENT_TYPE
733
- key = getattr ( child , " key" , None )
734
+ key = child . key
734
735
else :
735
736
child = f"{ child } "
736
737
child_type = _STRING_TYPE
@@ -739,8 +740,12 @@ def _process_child_type_and_key(
739
740
if key is None :
740
741
key = index
741
742
742
- yield ( child , child_type , key )
743
+ infos . append (( child , child_type , key ) )
743
744
745
+ return infos
746
+
747
+
748
+ _ChildInfo : TypeAlias = tuple [Any , "_ElementType" , Key ]
744
749
745
750
# used in _process_child_type_and_key
746
751
_ElementType = NewType ("_ElementType" , int )
0 commit comments