Skip to content

Commit f9ba4e8

Browse files
committed
fix typing/docstring issues
1 parent e3ede1c commit f9ba4e8

File tree

8 files changed

+81
-26
lines changed

8 files changed

+81
-26
lines changed

src/idom/backend/_common.py

+27-13
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import os
55
from dataclasses import dataclass
66
from pathlib import Path, PurePosixPath
7-
from typing import Any, Awaitable
7+
from typing import Any, Awaitable, Sequence
88

99
from asgiref.typing import ASGIApplication
1010
from uvicorn.config import Config as UvicornConfig
@@ -91,26 +91,40 @@ def read_client_index_html(options: CommonOptions) -> str:
9191
return (
9292
(CLIENT_BUILD_DIR / "index.html")
9393
.read_text()
94-
.format(__head__=vdom_to_html(options.head))
94+
.format(__head__=vdom_head_elements_to_html(options.head))
9595
)
9696

9797

98+
def vdom_head_elements_to_html(head: Sequence[VdomDict] | VdomDict | str) -> str:
99+
if isinstance(head, str):
100+
return head
101+
elif isinstance(head, dict):
102+
if head.get("tagName") == "head":
103+
head = {**head, "tagName": ""}
104+
return vdom_to_html(head)
105+
else:
106+
return vdom_to_html(html._(head))
107+
108+
98109
@dataclass
99110
class CommonOptions:
100111
"""Options for IDOM's built-in backed server implementations"""
101112

102-
head: VdomDict | str = vdom_to_html(
103-
html.head(
104-
html.title("IDOM"),
105-
html.link(
106-
{
107-
"rel": "icon",
108-
"href": "_idom/assets/idom-logo-square-small.svg",
109-
"type": "image/svg+xml",
110-
}
111-
),
112-
)
113+
head: Sequence[VdomDict] | VdomDict | str = (
114+
html.title("IDOM"),
115+
html.link(
116+
{
117+
"rel": "icon",
118+
"href": "_idom/assets/idom-logo-square-small.svg",
119+
"type": "image/svg+xml",
120+
}
121+
),
113122
)
123+
"""Add elements to the ``<head>`` of the application.
124+
125+
For example, this can be used to customize the title of the page, link extra
126+
scripts, or load stylesheets.
127+
"""
114128

115129
url_prefix: str = ""
116130
"""The URL prefix where IDOM resources will be served from"""

src/idom/backend/flask.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import idom
2828
from idom.backend._common import (
2929
ASSETS_PATH,
30-
CLIENT_BUILD_DIR,
3130
MODULES_PATH,
3231
PATH_PREFIX,
3332
STREAM_PATH,
@@ -139,7 +138,7 @@ def use_connection() -> Connection[_FlaskCarrier]:
139138

140139
@dataclass
141140
class Options(CommonOptions):
142-
"""Render server config for :class:`FlaskRenderServer`"""
141+
"""Render server config for :func:`idom.backend.flask.configure`"""
143142

144143
cors: bool | dict[str, Any] = False
145144
"""Enable or configure Cross Origin Resource Sharing (CORS)

src/idom/backend/sanic.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import json
55
import logging
66
from dataclasses import dataclass
7-
from typing import Any, Dict, MutableMapping, Tuple, Union
7+
from typing import Any, MutableMapping, Tuple
88
from urllib import parse as urllib_parse
99
from uuid import uuid4
1010

@@ -23,11 +23,9 @@
2323
serve_json_patch,
2424
)
2525
from idom.core.types import RootComponentConstructor
26-
from idom.utils import vdom_to_html
2726

2827
from ._common import (
2928
ASSETS_PATH,
30-
CLIENT_BUILD_DIR,
3129
MODULES_PATH,
3230
PATH_PREFIX,
3331
STREAM_PATH,
@@ -97,7 +95,7 @@ def use_connection() -> Connection[_SanicCarrier]:
9795

9896
@dataclass
9997
class Options(CommonOptions):
100-
"""Options for :class:`SanicRenderServer`"""
98+
"""Render server config for :func:`idom.backend.sanic.configure`"""
10199

102100
cors: bool | dict[str, Any] = False
103101
"""Enable or configure Cross Origin Resource Sharing (CORS)

src/idom/backend/starlette.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def use_connection() -> Connection[WebSocket]:
9393

9494
@dataclass
9595
class Options(CommonOptions):
96-
"""Optionsuration options for :class:`StarletteRenderServer`"""
96+
"""Render server config for :func:`idom.backend.starlette.configure`"""
9797

9898
cors: bool | dict[str, Any] = False
9999
"""Enable or configure Cross Origin Resource Sharing (CORS)

src/idom/backend/tornado.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import json
55
from asyncio import Queue as AsyncQueue
66
from asyncio.futures import Future
7-
from dataclasses import dataclass
87
from typing import Any, List, Tuple, Type, Union
98
from urllib.parse import urljoin
109

@@ -35,6 +34,7 @@
3534

3635

3736
Options = CommonOptions
37+
"""Render server config for :func:`idom.backend.tornado.configure`"""
3838

3939

4040
def configure(

src/idom/utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def vdom_to_html(value: str | VdomDict, indent: int = 0, depth: int = 0) -> str:
8787

8888
if "attributes" in value:
8989
if not tag: # pragma: no cover
90-
warn(f"Ignored attributes from element frament", UserWarning)
90+
warn("Ignored attributes from element frament", UserWarning)
9191
else:
9292
vdom_attributes = dict(value["attributes"])
9393
if "style" in vdom_attributes:

tests/test_backend/test__common.py

+43-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import pytest
22

3-
from idom.backend._common import traversal_safe_path
3+
from idom import html
4+
from idom.backend._common import traversal_safe_path, vdom_head_elements_to_html
45

56

67
@pytest.mark.parametrize(
@@ -14,3 +15,44 @@
1415
def test_catch_unsafe_relative_path_traversal(tmp_path, bad_path):
1516
with pytest.raises(ValueError, match="Unsafe path"):
1617
traversal_safe_path(tmp_path, *bad_path.split("/"))
18+
19+
20+
@pytest.mark.parametrize(
21+
"vdom_in, html_out",
22+
[
23+
(
24+
"<title>example</title>",
25+
"<title>example</title>",
26+
),
27+
(
28+
# We do not modify strings given by user. If given as VDOM we would have
29+
# striped this head element, but since provided as string, we leav as-is.
30+
"<head></head>",
31+
"<head></head>",
32+
),
33+
(
34+
html.head(
35+
html.meta({"charset": "utf-8"}),
36+
html.title("example"),
37+
),
38+
# we strip the head element
39+
'<meta charset="utf-8" /><title>example</title>',
40+
),
41+
(
42+
html._(
43+
html.meta({"charset": "utf-8"}),
44+
html.title("example"),
45+
),
46+
'<meta charset="utf-8" /><title>example</title>',
47+
),
48+
(
49+
[
50+
html.meta({"charset": "utf-8"}),
51+
html.title("example"),
52+
],
53+
'<meta charset="utf-8" /><title>example</title>',
54+
),
55+
],
56+
)
57+
def test_vdom_head_elements_to_html(vdom_in, html_out):
58+
assert vdom_head_elements_to_html(vdom_in) == html_out

tests/test_backend/test_all.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,16 @@ def ShowRoute():
159159

160160
@pytest.mark.parametrize("imp", all_implementations())
161161
async def test_customized_head(imp: BackendImplementation, page):
162+
custom_title = f"Custom Title for {imp.__name__}"
163+
162164
@idom.component
163165
def sample():
164-
return html.h1("the page title is customized")
166+
return html.h1(f"^ Page title is customized to: '{custom_title}'")
165167

166168
async with BackendFixture(
167169
implementation=imp,
168-
options=imp.Options(head=html.title("Custom Title")),
170+
options=imp.Options(head=html.title(custom_title)),
169171
) as server:
170172
async with DisplayFixture(backend=server, driver=page) as display:
171173
await display.show(sample)
172-
assert (await display.page.title()) == "Custom Title"
174+
assert (await display.page.title()) == custom_title

0 commit comments

Comments
 (0)