|
7 | 7 |
|
8 | 8 | import inspect |
9 | 9 | import logging |
10 | | -from typing import ( |
11 | | - Any, |
12 | | - Dict, |
13 | | - Iterable, |
14 | | - List, |
15 | | - Mapping, |
16 | | - Optional, |
17 | | - Sequence, |
18 | | - Tuple, |
19 | | - Union, |
20 | | - cast, |
21 | | -) |
| 10 | +from typing import Any, Dict, List, Mapping, Optional, Sequence, Tuple, cast |
22 | 11 |
|
23 | 12 | from fastjsonschema import compile as compile_json_schema |
24 | | -from mypy_extensions import TypedDict |
25 | 13 | from typing_extensions import Protocol |
26 | 14 |
|
27 | 15 | from idom.config import IDOM_DEBUG_MODE |
|
30 | 18 | merge_event_handlers, |
31 | 19 | to_event_handler_function, |
32 | 20 | ) |
33 | | -from idom.core.proto import EventHandlerDict, EventHandlerMapping, EventHandlerType |
| 21 | +from idom.core.proto import ( |
| 22 | + EventHandlerDict, |
| 23 | + EventHandlerMapping, |
| 24 | + EventHandlerType, |
| 25 | + ImportSourceDict, |
| 26 | + VdomAttributesAndChildren, |
| 27 | + VdomDict, |
| 28 | + VdomJson, |
| 29 | +) |
34 | 30 |
|
35 | 31 |
|
36 | 32 | logger = logging.getLogger() |
|
106 | 102 | _COMPILED_VDOM_VALIDATOR = compile_json_schema(VDOM_JSON_SCHEMA) |
107 | 103 |
|
108 | 104 |
|
109 | | -def validate_vdom(value: Any) -> VdomJson: |
| 105 | +def validate_vdom_json(value: Any) -> VdomJson: |
110 | 106 | """Validate serialized VDOM - see :attr:`VDOM_JSON_SCHEMA` for more info""" |
111 | 107 | _COMPILED_VDOM_VALIDATOR(value) |
112 | 108 | return cast(VdomJson, value) |
113 | 109 |
|
114 | 110 |
|
115 | | -_AttributesAndChildrenArg = Union[Mapping[str, Any], str, Iterable[Any], Any] |
116 | | -_EventHandlersArg = Optional[EventHandlerMapping] |
117 | | -_ImportSourceArg = Optional["ImportSourceDict"] |
| 111 | +def is_vdom(value: Any) -> bool: |
| 112 | + """Return whether a value is a :class:`VdomDict` |
| 113 | +
|
| 114 | + This employs a very simple heuristic - something is VDOM if: |
| 115 | +
|
| 116 | + 1. It is a ``dict`` instance |
| 117 | + 2. It contains the key ``"tagName"`` |
| 118 | + 3. The value of the key ``"tagName"`` is a string |
| 119 | +
|
| 120 | + .. note:: |
| 121 | +
|
| 122 | + Performing an ``isinstance(value, VdomDict)`` check is too restrictive since the |
| 123 | + user would be forced to import ``VdomDict`` every time they needed to declare a |
| 124 | + VDOM element. Giving the user more flexibility, at the cost of this check's |
| 125 | + accuracy, is worth it. |
| 126 | + """ |
| 127 | + return ( |
| 128 | + isinstance(value, dict) |
| 129 | + and "tagName" in value |
| 130 | + and isinstance(value["tagName"], str) |
| 131 | + ) |
118 | 132 |
|
119 | 133 |
|
120 | 134 | def vdom( |
121 | 135 | tag: str, |
122 | | - *attributes_and_children: _AttributesAndChildrenArg, |
| 136 | + *attributes_and_children: VdomAttributesAndChildren, |
123 | 137 | key: str = "", |
124 | | - event_handlers: _EventHandlersArg = None, |
125 | | - import_source: _ImportSourceArg = None, |
| 138 | + event_handlers: Optional[EventHandlerMapping] = None, |
| 139 | + import_source: Optional[ImportSourceDict] = None, |
126 | 140 | ) -> VdomDict: |
127 | 141 | """A helper function for creating VDOM dictionaries. |
128 | 142 |
|
@@ -169,28 +183,31 @@ def vdom( |
169 | 183 | return model |
170 | 184 |
|
171 | 185 |
|
172 | | -class VdomDictConstructor(Protocol): |
| 186 | +class _VdomDictConstructor(Protocol): |
173 | 187 | def __call__( |
174 | 188 | self, |
175 | | - *args: _AttributesAndChildrenArg, |
176 | | - event_handlers: _EventHandlersArg = None, |
177 | | - import_source: _ImportSourceArg = None, |
| 189 | + *attributes_and_children: VdomAttributesAndChildren, |
| 190 | + key: str = ..., |
| 191 | + event_handlers: Optional[EventHandlerMapping] = ..., |
| 192 | + import_source: Optional[ImportSourceDict] = ..., |
178 | 193 | ) -> VdomDict: |
179 | 194 | ... |
180 | 195 |
|
181 | 196 |
|
182 | | -def make_vdom_constructor(tag: str, allow_children: bool = True) -> VdomDictConstructor: |
| 197 | +def make_vdom_constructor( |
| 198 | + tag: str, allow_children: bool = True |
| 199 | +) -> _VdomDictConstructor: |
183 | 200 | """Return a constructor for VDOM dictionaries with the given tag name. |
184 | 201 |
|
185 | 202 | The resulting callable will have the same interface as :func:`vdom` but without its |
186 | 203 | first ``tag`` argument. |
187 | 204 | """ |
188 | 205 |
|
189 | 206 | def constructor( |
190 | | - *attributes_and_children: _AttributesAndChildrenArg, |
| 207 | + *attributes_and_children: VdomAttributesAndChildren, |
191 | 208 | key: str = "", |
192 | | - event_handlers: _EventHandlersArg = None, |
193 | | - import_source: _ImportSourceArg = None, |
| 209 | + event_handlers: Optional[EventHandlerMapping] = None, |
| 210 | + import_source: Optional[ImportSourceDict] = None, |
194 | 211 | ) -> VdomDict: |
195 | 212 | model = vdom( |
196 | 213 | tag, |
@@ -319,54 +336,3 @@ def _is_single_child(value: Any) -> bool: |
319 | 336 | logger.error(f"Key not specified for dynamic child {child}") |
320 | 337 |
|
321 | 338 | return False |
322 | | - |
323 | | - |
324 | | -class _VdomDictOptional(TypedDict, total=False): |
325 | | - key: str |
326 | | - children: Sequence[Any] |
327 | | - attributes: Dict[str, Any] |
328 | | - eventHandlers: EventHandlerDict # noqa |
329 | | - importSource: ImportSourceDict # noqa |
330 | | - |
331 | | - |
332 | | -class _VdomDictRequired(TypedDict, total=True): |
333 | | - tagName: str # noqa |
334 | | - |
335 | | - |
336 | | -class VdomDict(_VdomDictRequired, _VdomDictOptional): |
337 | | - """A :ref:`VDOM` dictionary""" |
338 | | - |
339 | | - |
340 | | -class ImportSourceDict(TypedDict): |
341 | | - source: str |
342 | | - fallback: Any |
343 | | - sourceType: str # noqa |
344 | | - unmountBeforeUpdate: bool # noqa |
345 | | - |
346 | | - |
347 | | -class _OptionalVdomJson(TypedDict, total=False): |
348 | | - key: str |
349 | | - error: str |
350 | | - children: List[Any] |
351 | | - attributes: Dict[str, Any] |
352 | | - eventHandlers: Dict[str, _JsonEventTarget] # noqa |
353 | | - importSource: _JsonImportSource # noqa |
354 | | - |
355 | | - |
356 | | -class _RequiredVdomJson(TypedDict, total=True): |
357 | | - tagName: str # noqa |
358 | | - |
359 | | - |
360 | | -class VdomJson(_RequiredVdomJson, _OptionalVdomJson): |
361 | | - """A JSON serializable form of :class:`VdomDict` matching the :data:`VDOM_JSON_SCHEMA`""" |
362 | | - |
363 | | - |
364 | | -class _JsonEventTarget(TypedDict): |
365 | | - target: str |
366 | | - preventDefault: bool # noqa |
367 | | - stopPropagation: bool # noqa |
368 | | - |
369 | | - |
370 | | -class _JsonImportSource(TypedDict): |
371 | | - source: str |
372 | | - fallback: Any |
0 commit comments