Skip to content

Commit

Permalink
add debug logs
Browse files Browse the repository at this point in the history
- "children" key not allowed in attributes
- key required for dynamic children
  • Loading branch information
rmorshea committed May 24, 2021
1 parent 246a3f5 commit 4b4f9b7
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/idom/client/app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion src/idom/client/app/package.json
Expand Up @@ -4,7 +4,9 @@
"version": "0.1.0",
"author": "Ryan Morshead",
"main": "index.js",
"workspaces": [ "./packages/*" ],
"workspaces": [
"./packages/*"
],
"license": "MIT",
"repository": {
"type": "git",
Expand Down
54 changes: 52 additions & 2 deletions src/idom/core/vdom.py
Expand Up @@ -5,15 +5,21 @@

from __future__ import annotations

import logging
from typing import Any, Iterable, List, Mapping, Optional, Sequence, Tuple, Union

from fastjsonschema import compile as compile_json_schema
from mypy_extensions import TypedDict
from typing_extensions import Protocol

from idom.config import IDOM_DEBUG_MODE

from .events import EventHandler


logger = logging.getLogger()


VDOM_JSON_SCHEMA = {
"$schema": "http://json-schema.org/draft-07/schema",
"$ref": "#/definitions/element",
Expand Down Expand Up @@ -209,15 +215,59 @@ def coalesce_attributes_and_children(

children_or_iterables: Sequence[Any]
attributes, *children_or_iterables = values
if not isinstance(attributes, Mapping) or "tagName" in attributes:
if not _is_attributes(attributes):
attributes = {}
children_or_iterables = values

children: List[Any] = []
for child in children_or_iterables:
if isinstance(child, (str, Mapping)) or not hasattr(child, "__iter__"):
if _is_single_child(child):
children.append(child)
else:
children.extend(child)

return attributes, children


def _is_attributes(value: Any) -> bool:
return isinstance(value, Mapping) and "tagName" not in value


if IDOM_DEBUG_MODE.current:

_debug_is_attributes = _is_attributes

def _is_attributes(value: Any) -> bool:
result = _debug_is_attributes(value)
if result and "children" in value:
logger.error(f"Reserved key 'children' found in attributes {value}")
return result


def _is_single_child(value: Any) -> bool:
return isinstance(value, (str, Mapping)) or not hasattr(value, "__iter__")


if IDOM_DEBUG_MODE.current:

_debug_is_single_child = _is_single_child

def _is_single_child(value: Any) -> bool:
if _debug_is_single_child(value):
return True

from .component import AbstractComponent

if hasattr(value, "__iter__") and not hasattr(value, "__len__"):
logger.error(
f"Did not verify key-path integrity of children in generator {value} "
"- pass a sequence (i.e. list of finite length) in order to verify"
)
else:
for child in value:
if (isinstance(child, AbstractComponent) and child.key is None) or (
isinstance(child, Mapping) and "key" not in child
):
logger.error(f"Key not specified for dynamic child {child}")

return False
38 changes: 38 additions & 0 deletions tests/test_core/test_vdom.py
Expand Up @@ -2,6 +2,7 @@
from fastjsonschema import JsonSchemaException

import idom
from idom.config import IDOM_DEBUG_MODE
from idom.core.vdom import make_vdom_constructor, validate_vdom


Expand Down Expand Up @@ -256,3 +257,40 @@ def test_valid_vdom(value):
def test_invalid_vdom(value, error_message_pattern):
with pytest.raises(JsonSchemaException, match=error_message_pattern):
validate_vdom(value)


@pytest.mark.skipif(not IDOM_DEBUG_MODE.current, reason="Only logs in debug mode")
def test_debug_log_if_children_in_attributes(caplog):
idom.vdom("div", {"children": ["hello"]})
assert len(caplog.records) == 1
assert caplog.records[0].message.startswith(
"Reserved key 'children' found in attributes"
)
caplog.records.clear()


@pytest.mark.skipif(not IDOM_DEBUG_MODE.current, reason="Only logs in debug mode")
def test_debug_log_cannot_verify_keypath_for_genereators(caplog):
idom.vdom("div", (1 for i in range(10)))
assert len(caplog.records) == 1
assert caplog.records[0].message.startswith(
"Did not verify key-path integrity of children in generator"
)
caplog.records.clear()


@pytest.mark.skipif(not IDOM_DEBUG_MODE.current, reason="Only logs in debug mode")
def test_debug_log_dynamic_children_must_have_keys(caplog):
idom.vdom("div", [idom.vdom("div")])
assert len(caplog.records) == 1
assert caplog.records[0].message.startswith("Key not specified for dynamic child")

caplog.records.clear()

@idom.component
def MyComponent():
return idom.vdom("div")

idom.vdom("div", [MyComponent()])
assert len(caplog.records) == 1
assert caplog.records[0].message.startswith("Key not specified for dynamic child")

0 comments on commit 4b4f9b7

Please sign in to comment.