Skip to content

Commit 4b4f9b7

Browse files
committed
add debug logs
- "children" key not allowed in attributes - key required for dynamic children
1 parent 246a3f5 commit 4b4f9b7

File tree

4 files changed

+94
-4
lines changed

4 files changed

+94
-4
lines changed

src/idom/client/app/package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/idom/client/app/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
"version": "0.1.0",
55
"author": "Ryan Morshead",
66
"main": "index.js",
7-
"workspaces": [ "./packages/*" ],
7+
"workspaces": [
8+
"./packages/*"
9+
],
810
"license": "MIT",
911
"repository": {
1012
"type": "git",

src/idom/core/vdom.py

+52-2
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,21 @@
55

66
from __future__ import annotations
77

8+
import logging
89
from typing import Any, Iterable, List, Mapping, Optional, Sequence, Tuple, Union
910

1011
from fastjsonschema import compile as compile_json_schema
1112
from mypy_extensions import TypedDict
1213
from typing_extensions import Protocol
1314

15+
from idom.config import IDOM_DEBUG_MODE
16+
1417
from .events import EventHandler
1518

1619

20+
logger = logging.getLogger()
21+
22+
1723
VDOM_JSON_SCHEMA = {
1824
"$schema": "http://json-schema.org/draft-07/schema",
1925
"$ref": "#/definitions/element",
@@ -209,15 +215,59 @@ def coalesce_attributes_and_children(
209215

210216
children_or_iterables: Sequence[Any]
211217
attributes, *children_or_iterables = values
212-
if not isinstance(attributes, Mapping) or "tagName" in attributes:
218+
if not _is_attributes(attributes):
213219
attributes = {}
214220
children_or_iterables = values
215221

216222
children: List[Any] = []
217223
for child in children_or_iterables:
218-
if isinstance(child, (str, Mapping)) or not hasattr(child, "__iter__"):
224+
if _is_single_child(child):
219225
children.append(child)
220226
else:
221227
children.extend(child)
222228

223229
return attributes, children
230+
231+
232+
def _is_attributes(value: Any) -> bool:
233+
return isinstance(value, Mapping) and "tagName" not in value
234+
235+
236+
if IDOM_DEBUG_MODE.current:
237+
238+
_debug_is_attributes = _is_attributes
239+
240+
def _is_attributes(value: Any) -> bool:
241+
result = _debug_is_attributes(value)
242+
if result and "children" in value:
243+
logger.error(f"Reserved key 'children' found in attributes {value}")
244+
return result
245+
246+
247+
def _is_single_child(value: Any) -> bool:
248+
return isinstance(value, (str, Mapping)) or not hasattr(value, "__iter__")
249+
250+
251+
if IDOM_DEBUG_MODE.current:
252+
253+
_debug_is_single_child = _is_single_child
254+
255+
def _is_single_child(value: Any) -> bool:
256+
if _debug_is_single_child(value):
257+
return True
258+
259+
from .component import AbstractComponent
260+
261+
if hasattr(value, "__iter__") and not hasattr(value, "__len__"):
262+
logger.error(
263+
f"Did not verify key-path integrity of children in generator {value} "
264+
"- pass a sequence (i.e. list of finite length) in order to verify"
265+
)
266+
else:
267+
for child in value:
268+
if (isinstance(child, AbstractComponent) and child.key is None) or (
269+
isinstance(child, Mapping) and "key" not in child
270+
):
271+
logger.error(f"Key not specified for dynamic child {child}")
272+
273+
return False

tests/test_core/test_vdom.py

+38
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from fastjsonschema import JsonSchemaException
33

44
import idom
5+
from idom.config import IDOM_DEBUG_MODE
56
from idom.core.vdom import make_vdom_constructor, validate_vdom
67

78

@@ -256,3 +257,40 @@ def test_valid_vdom(value):
256257
def test_invalid_vdom(value, error_message_pattern):
257258
with pytest.raises(JsonSchemaException, match=error_message_pattern):
258259
validate_vdom(value)
260+
261+
262+
@pytest.mark.skipif(not IDOM_DEBUG_MODE.current, reason="Only logs in debug mode")
263+
def test_debug_log_if_children_in_attributes(caplog):
264+
idom.vdom("div", {"children": ["hello"]})
265+
assert len(caplog.records) == 1
266+
assert caplog.records[0].message.startswith(
267+
"Reserved key 'children' found in attributes"
268+
)
269+
caplog.records.clear()
270+
271+
272+
@pytest.mark.skipif(not IDOM_DEBUG_MODE.current, reason="Only logs in debug mode")
273+
def test_debug_log_cannot_verify_keypath_for_genereators(caplog):
274+
idom.vdom("div", (1 for i in range(10)))
275+
assert len(caplog.records) == 1
276+
assert caplog.records[0].message.startswith(
277+
"Did not verify key-path integrity of children in generator"
278+
)
279+
caplog.records.clear()
280+
281+
282+
@pytest.mark.skipif(not IDOM_DEBUG_MODE.current, reason="Only logs in debug mode")
283+
def test_debug_log_dynamic_children_must_have_keys(caplog):
284+
idom.vdom("div", [idom.vdom("div")])
285+
assert len(caplog.records) == 1
286+
assert caplog.records[0].message.startswith("Key not specified for dynamic child")
287+
288+
caplog.records.clear()
289+
290+
@idom.component
291+
def MyComponent():
292+
return idom.vdom("div")
293+
294+
idom.vdom("div", [MyComponent()])
295+
assert len(caplog.records) == 1
296+
assert caplog.records[0].message.startswith("Key not specified for dynamic child")

0 commit comments

Comments
 (0)