Skip to content

Commit 35e5b99

Browse files
committed
fix errors
1 parent 781c6f6 commit 35e5b99

File tree

4 files changed

+67
-17
lines changed

4 files changed

+67
-17
lines changed

docs/source/_custom_js/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/idom/core/layout.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,10 +417,18 @@ def _render_model_children(
417417
def _render_model_children_without_old_state(
418418
self, new_state: _ModelState, raw_children: List[Any]
419419
) -> None:
420+
child_type_key_tuples = list(_process_child_type_and_key(raw_children))
421+
422+
new_keys = {item[2] for item in child_type_key_tuples}
423+
if len(new_keys) != len(raw_children):
424+
key_counter = Counter(item[2] for item in child_type_key_tuples)
425+
duplicate_keys = [key for key, count in key_counter.items() if count > 1]
426+
raise ValueError(
427+
f"Duplicate keys {duplicate_keys} at {new_state.patch_path or '/'!r}"
428+
)
429+
420430
new_children = new_state.model.current["children"] = []
421-
for index, (child, child_type, key) in enumerate(
422-
_process_child_type_and_key(raw_children)
423-
):
431+
for index, (child, child_type, key) in enumerate(child_type_key_tuples):
424432
if child_type is _DICT_TYPE:
425433
child_state = _make_element_model_state(new_state, index, key)
426434
self._render_model(None, child_state, child)

src/idom/html.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
"""
2+
**Fragment**
3+
4+
- :func:`_`
5+
26
**Dcument metadata**
37
48
- :func:`base`
@@ -148,6 +152,8 @@
148152
149153
- :func:`slot`
150154
- :func:`template`
155+
156+
.. autofunction:: _
151157
"""
152158

153159
from __future__ import annotations
@@ -158,6 +164,14 @@
158164
from .core.vdom import coalesce_attributes_and_children, make_vdom_constructor
159165

160166

167+
def _(*children: Any) -> VdomDict:
168+
"""An HTML fragment - this element will not appear in the DOM"""
169+
attributes, children = coalesce_attributes_and_children(children)
170+
if attributes:
171+
raise ValueError("Fragments cannot have attributes")
172+
return {"tagName": "", "children": children}
173+
174+
161175
# Dcument metadata
162176
base = make_vdom_constructor("base")
163177
head = make_vdom_constructor("head")

tests/test_core/test_layout.py

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ def Child():
148148
child_set_state.current(1)
149149
path, changes = await render_json_patch(layout)
150150

151-
assert path == "/children/1"
151+
assert path == "/children/0/children/1"
152152
assert changes == [
153153
{"op": "replace", "path": "/children/0/children/0", "value": "1"}
154154
]
@@ -225,21 +225,31 @@ def BadChild():
225225
assert_same_items(
226226
patch.changes,
227227
[
228-
{"op": "add", "path": "/tagName", "value": ""},
229228
{
230229
"op": "add",
231230
"path": "/children",
232231
"value": [
233232
{
234233
"children": [
235-
{"children": [...], "tagName": ""},
234+
{
235+
"children": [
236+
{"children": ["hello"], "tagName": "div"}
237+
],
238+
"tagName": "",
239+
},
236240
{"error": "", "tagName": ""},
237-
{"children": [...], "tagName": ""},
241+
{
242+
"children": [
243+
{"children": ["hello"], "tagName": "div"}
244+
],
245+
"tagName": "",
246+
},
238247
],
239248
"tagName": "div",
240249
}
241250
],
242251
},
252+
{"op": "add", "path": "/tagName", "value": ""},
243253
],
244254
)
245255

@@ -598,9 +608,14 @@ def Inner():
598608
{
599609
"op": "add",
600610
"path": "/children",
601-
"value": [{"children": ["hello"], "tagName": "div"}],
611+
"value": [
612+
{
613+
"children": [{"children": ["hello"], "tagName": "div"}],
614+
"tagName": "",
615+
}
616+
],
602617
},
603-
{"op": "add", "path": "/tagName", "value": "div"},
618+
{"op": "add", "path": "/tagName", "value": ""},
604619
],
605620
)
606621

@@ -685,18 +700,31 @@ def HasNestedEventHandler():
685700

686701

687702
async def test_duplicate_sibling_keys_causes_error(caplog):
703+
hook = HookCatcher()
704+
688705
@idom.component
706+
@hook.capture
689707
def ComponentReturnsDuplicateKeys():
690708
return idom.html.div(
691-
idom.html.div(key="duplicate"), idom.html.div(key="duplicate")
709+
idom.html.div(key="duplicate"),
710+
idom.html.div(key="duplicate"),
692711
)
693712

694-
with assert_idom_logged(
695-
error_type=ValueError,
696-
match_error=r"Duplicate keys \['duplicate'\] at '/'",
697-
clear_matched_records=True,
698-
):
699-
with idom.Layout(ComponentReturnsDuplicateKeys()) as layout:
713+
with idom.Layout(ComponentReturnsDuplicateKeys()) as layout:
714+
with assert_idom_logged(
715+
error_type=ValueError,
716+
match_error=r"Duplicate keys \['duplicate'\] at '/children/0'",
717+
clear_matched_records=True,
718+
):
719+
await layout.render()
720+
721+
hook.latest.schedule_render()
722+
723+
with assert_idom_logged(
724+
error_type=ValueError,
725+
match_error=r"Duplicate keys \['duplicate'\] at '/children/0'",
726+
clear_matched_records=True,
727+
):
700728
await layout.render()
701729

702730

0 commit comments

Comments
 (0)