Skip to content

Commit d7a71b3

Browse files
authored
allow string return type (#817)
1 parent 6fe9fa2 commit d7a71b3

File tree

12 files changed

+38
-45
lines changed

12 files changed

+38
-45
lines changed

.github/workflows/test.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ on:
1111
- cron: "0 0 * * *"
1212

1313
jobs:
14-
python-coverage:
14+
python-exhaustive:
1515
uses: ./.github/workflows/.nox-session.yml
1616
with:
1717
job-name: "python-{0}"
18-
session-name: test_python_suite
18+
session-name: test_python
1919
session-arguments: --maxfail=3
2020
python-environments:
2121
uses: ./.github/workflows/.nox-session.yml

noxfile.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ def test_python_types(session: Session) -> None:
200200
install_requirements_file(session, "check-types")
201201
install_requirements_file(session, "pkg-deps")
202202
install_requirements_file(session, "pkg-extras")
203-
session.run("mypy", "--strict", "src/idom")
203+
session.run("mypy", "--show-error-codes", "--strict", "src/idom")
204204

205205

206206
@nox.session

src/idom/_option.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def __init__(self, new_opt: Option[_O], name: str) -> None:
103103
self._new_opt = new_opt
104104

105105
@property # type: ignore
106-
def _current(self) -> _O: # type: ignore
106+
def _current(self) -> _O:
107107
warnings.warn(
108108
f"{self.name!r} has been renamed to {self._new_opt.name!r}",
109109
DeprecationWarning,

src/idom/core/component.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
import inspect
44
from functools import wraps
5-
from typing import Any, Callable, Dict, Optional, Tuple, Union
5+
from typing import Any, Callable, Dict, Optional, Tuple
66

77
from .types import ComponentType, VdomDict
88

99

1010
def component(
11-
function: Callable[..., Union[ComponentType, VdomDict | None]]
11+
function: Callable[..., ComponentType | VdomDict | str | None]
1212
) -> Callable[..., Component]:
1313
"""A decorator for defining a new component.
1414
@@ -39,7 +39,7 @@ class Component:
3939

4040
def __init__(
4141
self,
42-
function: Callable[..., ComponentType | VdomDict | None],
42+
function: Callable[..., ComponentType | VdomDict | str | None],
4343
key: Optional[Any],
4444
args: Tuple[Any, ...],
4545
kwargs: Dict[str, Any],
@@ -51,7 +51,7 @@ def __init__(
5151
self._kwargs = kwargs
5252
self._sig = sig
5353

54-
def render(self) -> VdomDict | ComponentType | None:
54+
def render(self) -> ComponentType | VdomDict | str | None:
5555
return self.type(*self._args, **self._kwargs)
5656

5757
def should_render(self, new: Component) -> bool:

src/idom/core/hooks.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
from typing_extensions import Protocol
2525

26-
from idom.config import IDOM_DEBUG_MODE
2726
from idom.utils import Ref
2827

2928
from ._thread_local import ThreadLocal
@@ -226,9 +225,6 @@ def use_debug_value(
226225
:func:`id` is different). By default these are inferred based on local
227226
variables that are referenced by the given function.
228227
"""
229-
if not IDOM_DEBUG_MODE.current:
230-
return # pragma: no cover
231-
232228
old: Ref[Any] = _use_const(lambda: Ref(object()))
233229
memo_func = message if callable(message) else lambda: message
234230
new = use_memo(memo_func, dependencies)
@@ -541,7 +537,7 @@ def _try_to_infer_closure_values(
541537
else:
542538
return None
543539
else:
544-
return cast("Sequence[Any] | None", values)
540+
return values
545541

546542

547543
def current_hook() -> LifeCycleHook:

src/idom/core/layout.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ def _render_component(
234234
old_parent_model = parent.model.current
235235
old_parent_children = old_parent_model["children"]
236236
parent.model.current = {
237-
**old_parent_model,
237+
**old_parent_model, # type: ignore[misc]
238238
"children": [
239239
*old_parent_children[:index],
240240
new_state.model.current,

src/idom/core/types.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class ComponentType(Protocol):
4444
This is used to see if two component instances share the same definition.
4545
"""
4646

47-
def render(self) -> VdomDict | ComponentType | None:
47+
def render(self) -> VdomDict | ComponentType | str | None:
4848
"""Render the component's view model."""
4949

5050
def should_render(self: _OwnType, new: _OwnType) -> bool:

src/idom/testing/display.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
async_playwright,
1313
)
1414

15-
from idom import html
1615
from idom.config import IDOM_TESTING_DEFAULT_TIMEOUT
1716
from idom.types import RootComponentConstructor
1817

@@ -49,7 +48,7 @@ async def goto(self, path: str, query: Any | None = None) -> None:
4948
await self.page.goto(self.backend.url(path, query))
5049

5150
async def root_element(self) -> ElementHandle:
52-
element = await self.page.wait_for_selector(f"#app", state="attached")
51+
element = await self.page.wait_for_selector("#app", state="attached")
5352
if element is None:
5453
raise RuntimeError("Root element not attached") # pragma: no cover
5554
return element

src/idom/utils.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ def __repr__(self) -> str:
5656
return f"{type(self).__name__}({current})"
5757

5858

59-
def html_to_vdom(html: str, *transforms: _ModelTransform, strict: bool = True) -> VdomDict:
59+
def html_to_vdom(
60+
html: str, *transforms: _ModelTransform, strict: bool = True
61+
) -> VdomDict:
6062
"""Transform HTML into a DOM model. Unique keys can be provided to HTML elements
6163
using a ``key=...`` attribute within your HTML tag.
6264
@@ -82,7 +84,9 @@ def html_to_vdom(html: str, *transforms: _ModelTransform, strict: bool = True) -
8284
recover=not strict,
8385
)
8486
try:
85-
nodes: List = fragments_fromstring(html, no_leading_text=True, parser=parser)
87+
nodes: list[etree._Element] = fragments_fromstring(
88+
html, no_leading_text=True, parser=parser
89+
)
8690
except etree.XMLSyntaxError as e:
8791
if not strict:
8892
raise e # pragma: no cover
@@ -139,10 +143,11 @@ def _etree_to_vdom(
139143
attributes = dict(node.items())
140144
key = attributes.pop("key", None)
141145

146+
vdom: VdomDict
142147
if hasattr(idom.html, node.tag):
143148
vdom = getattr(idom.html, node.tag)(attributes, *children, key=key)
144149
else:
145-
vdom: VdomDict = {"tagName": node.tag}
150+
vdom = {"tagName": node.tag}
146151
if children:
147152
vdom["children"] = children
148153
if attributes:
@@ -160,7 +165,7 @@ def _etree_to_vdom(
160165
return vdom
161166

162167

163-
def _mutate_vdom(vdom: VdomDict):
168+
def _mutate_vdom(vdom: VdomDict) -> None:
164169
"""Performs any necessary mutations on the VDOM attributes to meet VDOM spec.
165170
166171
Currently, this function only transforms the ``style`` attribute into a dictionary whose keys are
@@ -216,5 +221,5 @@ def _hypen_to_camel_case(string: str) -> str:
216221
return first.lower() + remainder.title().replace("-", "")
217222

218223

219-
class HTMLParseError(etree.LxmlSyntaxError):
224+
class HTMLParseError(etree.LxmlSyntaxError): # type: ignore[misc]
220225
"""Raised when an HTML document cannot be parsed using strict parsing."""

tests/test_core/test_layout.py

+2-11
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
capture_idom_logs,
2121
)
2222
from idom.utils import Ref
23-
from tests.tooling.asserts import assert_same_items
23+
from tests.tooling.hooks import use_toggle
2424

2525

2626
@pytest.fixture(autouse=True)
@@ -495,11 +495,6 @@ def SomeComponent():
495495
)
496496

497497

498-
def use_toggle(init=False):
499-
state, set_state = idom.hooks.use_state(init)
500-
return state, lambda: set_state(lambda old: not old)
501-
502-
503498
async def test_model_key_preserves_callback_identity_for_common_elements(caplog):
504499
called_good_trigger = idom.Ref(False)
505500
good_handler = StaticEventHandler()
@@ -818,13 +813,9 @@ async def test_elements_and_components_with_the_same_key_can_be_interchanged():
818813
set_toggle = idom.Ref()
819814
effects = []
820815

821-
def use_toggle():
822-
state, set_state = idom.hooks.use_state(True)
823-
return state, lambda: set_state(not state)
824-
825816
@idom.component
826817
def Root():
827-
toggle, set_toggle.current = use_toggle()
818+
toggle, set_toggle.current = use_toggle(True)
828819
if toggle:
829820
return SomeComponent("x")
830821
else:

tests/test_html.py

+3-12
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,17 @@
11
import pytest
22

3-
from idom import component, config, html, use_state
3+
from idom import component, config, html
44
from idom.testing import DisplayFixture, poll
55
from idom.utils import Ref
6-
7-
8-
def use_toggle(initial=True):
9-
state, set_state = use_state(initial)
10-
return state, lambda: set_state(not state)
11-
12-
13-
def use_counter(initial_value):
14-
state, set_state = use_state(initial_value)
15-
return state, lambda: set_state(state + 1)
6+
from tests.tooling.hooks import use_counter, use_toggle
167

178

189
async def test_script_mount_unmount(display: DisplayFixture):
1910
toggle_is_mounted = Ref()
2011

2112
@component
2213
def Root():
23-
is_mounted, toggle_is_mounted.current = use_toggle()
14+
is_mounted, toggle_is_mounted.current = use_toggle(True)
2415
return html.div(
2516
html.div({"id": "mount-state", "data-value": False}),
2617
HasScript() if is_mounted else html.div(),

tests/tooling/hooks.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from idom import use_state
2+
3+
4+
def use_toggle(init=False):
5+
state, set_state = use_state(init)
6+
return state, lambda: set_state(lambda old: not old)
7+
8+
9+
def use_counter(initial_value):
10+
state, set_state = use_state(initial_value)
11+
return state, lambda: set_state(state + 1)

0 commit comments

Comments
 (0)