From b3be4dffe820ff26fc60aa402d78bc2fd124dcb6 Mon Sep 17 00:00:00 2001 From: Evgeny Ivanov Date: Sun, 4 Jun 2023 19:52:11 +0600 Subject: [PATCH 1/5] Replace lists with tuples --- src/rico/_html.py | 6 +++--- tests/test__container.py | 46 ++++++++++++++++++++-------------------- tests/test__content.py | 42 ++++++++++++++++++------------------ tests/test__html.py | 20 ++++++++--------- 4 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/rico/_html.py b/src/rico/_html.py index 05ac735..94ed140 100644 --- a/src/rico/_html.py +++ b/src/rico/_html.py @@ -51,13 +51,13 @@ def handle_endtag(self, tag: str) -> None: def handle_data(self, data: str) -> None: self._builder.data(data) - def close(self) -> list[ET.Element]: + def close(self) -> tuple[ET.Element]: super().close() self._builder.end(self._root) - return list(self._builder.close()) + return tuple(self._builder.close()) -def parse_html(data: str) -> list[ET.Element]: +def parse_html(data: str) -> tuple[ET.Element]: """Parse an HTML document from a string. Assign None values to boolean attributes. diff --git a/tests/test__container.py b/tests/test__container.py index 61fb9e5..69a48f2 100644 --- a/tests/test__container.py +++ b/tests/test__container.py @@ -26,7 +26,7 @@ def test_div_init(): assert div0.tail is None assert len(div0) == 2 - div1 = list(div0)[0] + div1 = tuple(div0)[0] assert isinstance(div1, ET.Element) assert div1.tag == "div" assert div1.attrib == {} @@ -34,7 +34,7 @@ def test_div_init(): assert div1.tail is None assert len(div1) == 1 - p = list(div1)[0] + p = tuple(div1)[0] assert isinstance(p, ET.Element) assert p.tag == "p" assert p.attrib == {} @@ -42,7 +42,7 @@ def test_div_init(): assert p.tail is None assert len(p) == 0 - div2 = list(div0)[1] + div2 = tuple(div0)[1] assert isinstance(div2, ET.Element) assert div2.tag == "div" assert div2.attrib == {"class": "col"} @@ -50,7 +50,7 @@ def test_div_init(): assert div2.tail is None assert len(div2) == 1 - h1 = list(div2)[0] + h1 = tuple(div2)[0] assert isinstance(h1, ET.Element) assert h1.tag == "h1" assert h1.attrib == {} @@ -142,7 +142,7 @@ def test_doc_init_default(): # noqa: PLR0915 assert len(html) == 2 head = doc.head - assert head == list(html)[0] + assert head == tuple(html)[0] assert isinstance(head, ET.Element) assert head.tag == "head" assert head.attrib == {} @@ -150,7 +150,7 @@ def test_doc_init_default(): # noqa: PLR0915 assert head.tail is None assert len(head) == 4 - charset = list(head)[0] + charset = tuple(head)[0] assert isinstance(charset, ET.Element) assert charset.tag == "meta" assert charset.attrib == {"charset": "utf-8"} @@ -158,7 +158,7 @@ def test_doc_init_default(): # noqa: PLR0915 assert charset.tail is None assert len(charset) == 0 - viewport = list(head)[1] + viewport = tuple(head)[1] assert isinstance(viewport, ET.Element) assert viewport.tag == "meta" assert viewport.attrib == { @@ -169,7 +169,7 @@ def test_doc_init_default(): # noqa: PLR0915 assert viewport.tail is None assert len(viewport) == 0 - bootstrap_css = list(head)[2] + bootstrap_css = tuple(head)[2] assert isinstance(bootstrap_css, ET.Element) assert bootstrap_css.tag == "link" assert bootstrap_css.attrib == { @@ -180,7 +180,7 @@ def test_doc_init_default(): # noqa: PLR0915 assert bootstrap_css.tail is None assert len(bootstrap_css) == 0 - df_style = list(head)[3] + df_style = tuple(head)[3] assert isinstance(df_style, ET.Element) assert df_style.tag == "style" assert df_style.attrib == {} @@ -189,7 +189,7 @@ def test_doc_init_default(): # noqa: PLR0915 assert len(df_style) == 0 body = doc.body - assert body == list(html)[1] + assert body == tuple(html)[1] assert isinstance(body, ET.Element) assert body.tag == "body" assert body.attrib == {} @@ -198,7 +198,7 @@ def test_doc_init_default(): # noqa: PLR0915 assert len(body) == 1 div0 = doc.container - assert div0 == list(body)[0] + assert div0 == tuple(body)[0] assert isinstance(div0, ET.Element) assert div0.tag == "div" assert div0.attrib == {"class": "container"} @@ -206,7 +206,7 @@ def test_doc_init_default(): # noqa: PLR0915 assert div0.tail is None assert len(div0) == 1 - div1 = list(div0)[0] + div1 = tuple(div0)[0] assert isinstance(div1, ET.Element) assert div1.tag == "div" assert div1.attrib == {} @@ -214,7 +214,7 @@ def test_doc_init_default(): # noqa: PLR0915 assert div1.tail is None assert len(div1) == 1 - p = list(div1)[0] + p = tuple(div1)[0] assert isinstance(p, ET.Element) assert p.tag == "p" assert p.attrib == {} @@ -251,7 +251,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 assert len(html) == 2 head = doc.head - assert head == list(html)[0] + assert head == tuple(html)[0] assert isinstance(head, ET.Element) assert head.tag == "head" assert head.attrib == {} @@ -259,7 +259,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 assert head.tail is None assert len(head) == 4 - title = list(head)[0] + title = tuple(head)[0] assert isinstance(title, ET.Element) assert title.tag == "title" assert title.attrib == {} @@ -267,7 +267,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 assert title.tail is None assert len(title) == 0 - bootstrap_css = list(head)[1] + bootstrap_css = tuple(head)[1] assert isinstance(bootstrap_css, ET.Element) assert bootstrap_css.tag == "link" assert bootstrap_css.attrib == { @@ -278,7 +278,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 assert bootstrap_css.tail is None assert len(bootstrap_css) == 0 - style = list(head)[2] + style = tuple(head)[2] style = extra_style.style assert isinstance(style, ET.Element) assert style.tag == "link" @@ -287,7 +287,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 assert style.tail is None assert len(style) == 0 - bootstrap_js = list(head)[3] + bootstrap_js = tuple(head)[3] assert isinstance(bootstrap_js, ET.Element) assert bootstrap_js.tag == "script" assert bootstrap_js.attrib == {"src": rico._config.BOOTSTRAP_JS} @@ -296,7 +296,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 assert len(bootstrap_js) == 0 body = doc.body - assert body == list(html)[1] + assert body == tuple(html)[1] assert isinstance(body, ET.Element) assert body.tag == "body" assert body.attrib == {} @@ -305,7 +305,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 assert len(body) == 2 div0 = doc.container - assert div0 == list(body)[0] + assert div0 == tuple(body)[0] assert isinstance(div0, ET.Element) assert div0.tag == "div" assert div0.attrib == {} @@ -313,7 +313,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 assert div0.tail is None assert len(div0) == 1 - div1 = list(div0)[0] + div1 = tuple(div0)[0] assert isinstance(div1, ET.Element) assert div1.tag == "div" assert div1.attrib == {} @@ -321,7 +321,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 assert div1.tail is None assert len(div1) == 1 - p = list(div1)[0] + p = tuple(div1)[0] assert isinstance(p, ET.Element) assert p.tag == "p" assert p.attrib == {} @@ -329,7 +329,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 assert p.tail is None assert len(p) == 0 - script = list(body)[1] + script = tuple(body)[1] assert script == extra_script.script assert isinstance(script, ET.Element) assert script.tag == "script" diff --git a/tests/test__content.py b/tests/test__content.py index 1924723..8ef4bb0 100644 --- a/tests/test__content.py +++ b/tests/test__content.py @@ -116,7 +116,7 @@ def test_tag(): assert div.tail is None assert len(div) == 1 - p = list(div)[0] + p = tuple(div)[0] assert isinstance(p, ET.Element) assert p.tag == "p" assert p.attrib == {"class": "col", "id": "42"} @@ -136,7 +136,7 @@ def test_text_simple(): assert div.tail is None assert len(div) == 1 - p = list(div)[0] + p = tuple(div)[0] assert isinstance(p, ET.Element) assert p.tag == "p" assert p.attrib == {} @@ -149,7 +149,7 @@ def test_text_pre_mono(): content = rico._content.Text("Hello\nworld", mono=True) div = content.container - pre = list(div)[0] + pre = tuple(div)[0] assert isinstance(pre, ET.Element) assert pre.tag == "pre" assert pre.attrib == {"class": "font-monospace"} @@ -162,7 +162,7 @@ def test_text_int_mono_wrap(): content = rico._content.Text(42, mono=True, wrap=True) div = content.container - p = list(div)[0] + p = tuple(div)[0] assert isinstance(p, ET.Element) assert p.tag == "p" assert p.attrib == {"class": "font-monospace text-wrap"} @@ -182,7 +182,7 @@ def test_code(): assert div.tail is None assert len(div) == 1 - pre = list(div)[0] + pre = tuple(div)[0] assert isinstance(pre, ET.Element) assert pre.tag == "pre" assert pre.attrib == {} @@ -190,7 +190,7 @@ def test_code(): assert pre.tail is None assert len(pre) == 1 - code = list(pre)[0] + code = tuple(pre)[0] assert isinstance(code, ET.Element) assert code.tag == "code" assert code.attrib == {} @@ -210,7 +210,7 @@ def test_html_simple(): assert div.tail is None assert len(div) == 1 - p = list(div)[0] + p = tuple(div)[0] assert isinstance(p, ET.Element) assert p.tag == "p" assert p.attrib == {"border": "1"} @@ -244,10 +244,10 @@ def test_html_table_border( content = rico._content.HTML(df, strip_dataframe_borders) if wrap_in_div: - div = list(content.container)[0] - table = list(div)[0] + div = tuple(content.container)[0] + table = tuple(div)[0] else: - table = list(content.container)[0] + table = tuple(content.container)[0] if border and (not dataframe or not strip_dataframe_borders): assert table.get("border") == "1" @@ -272,7 +272,7 @@ def test_markdown(): assert div.tail is None assert len(div) == 3 - h1 = list(div)[0] + h1 = tuple(div)[0] assert isinstance(h1, ET.Element) assert h1.tag == "h1" assert h1.attrib == {} @@ -280,7 +280,7 @@ def test_markdown(): assert h1.tail == "\n" assert len(h1) == 0 - h2 = list(div)[1] + h2 = tuple(div)[1] assert isinstance(h2, ET.Element) assert h2.tag == "h2" assert h2.attrib == {} @@ -288,7 +288,7 @@ def test_markdown(): assert h2.tail == "\n" assert len(h2) == 0 - p = list(div)[2] + p = tuple(div)[2] assert isinstance(p, ET.Element) assert p.tag == "p" assert p.attrib == {} @@ -325,7 +325,7 @@ def test_image_svg(data: str | bytes): assert div.tail is None assert len(div) == 1 - svg = list(div)[0] + svg = tuple(div)[0] assert isinstance(svg, ET.Element) assert svg.tag == "svg" assert svg.attrib == { @@ -340,7 +340,7 @@ def test_image_svg(data: str | bytes): assert svg.tail is None assert len(svg) == 1 - path = list(svg)[0] + path = tuple(svg)[0] assert isinstance(path, ET.Element) assert path.tag == "path" assert path.attrib == { @@ -367,7 +367,7 @@ def test_image_png(data: str | bytes): assert div.tail is None assert len(div) == 1 - img = list(div)[0] + img = tuple(div)[0] assert isinstance(img, ET.Element) assert img.tag == "img" assert img.attrib == {"src": f"data:image/png;base64,{encoded_image}"} @@ -409,11 +409,11 @@ def test_chart_complete(chart: Any, format: Literal["svg", "png"] | None): # no assert len(div) == 1 if format is None: - svg = list(div)[0] + svg = tuple(div)[0] assert isinstance(svg, ET.Element) assert svg.tag == "svg" else: - img = list(div)[0] + img = tuple(div)[0] assert isinstance(img, ET.Element) assert img.tag == "img" @@ -452,7 +452,7 @@ def _repr_html_(self) -> str: assert div.tail is None assert len(div) == 3 - h1 = list(div)[0] + h1 = tuple(div)[0] assert isinstance(h1, ET.Element) assert h1.tag == "h1" assert h1.attrib == {} @@ -460,7 +460,7 @@ def _repr_html_(self) -> str: assert h1.tail is None assert len(h1) == 0 - p = list(div)[1] + p = tuple(div)[1] assert isinstance(p, ET.Element) assert p.tag == "p" assert p.attrib == {} @@ -468,7 +468,7 @@ def _repr_html_(self) -> str: assert p.tail is None assert len(p) == 0 - svg = list(div)[2] + svg = tuple(div)[2] assert isinstance(svg, ET.Element) assert svg.tag == "svg" diff --git a/tests/test__html.py b/tests/test__html.py index b2f33a7..3e37d78 100644 --- a/tests/test__html.py +++ b/tests/test__html.py @@ -8,8 +8,8 @@ import rico._html -def elem_to_string(elem: ET.Element | list[ET.Element], sep: str = "") -> str: - if isinstance(elem, list): +def elem_to_string(elem: ET.Element | tuple[ET.Element], sep: str = "") -> str: + if isinstance(elem, tuple): return sep.join(elem_to_string(e) for e in elem) return ET.tostring(elem, encoding="unicode", method="html") @@ -21,7 +21,7 @@ def test_html_parser_two_elements(): elements = parser.close() assert elem_to_string(elements) == text - assert isinstance(elements, list) + assert isinstance(elements, tuple) assert len(elements) == 2 p0 = elements[0] @@ -48,7 +48,7 @@ def test_html_parser_nested_tags(): elements = parser.close() assert elem_to_string(elements) == text - assert isinstance(elements, list) + assert isinstance(elements, tuple) assert len(elements) == 1 div = elements[0] @@ -59,7 +59,7 @@ def test_html_parser_nested_tags(): assert div.tail is None assert len(div) == 1 - p = list(div)[0] + p = tuple(div)[0] assert isinstance(p, ET.Element) assert p.tag == "p" assert p.attrib == {} @@ -67,7 +67,7 @@ def test_html_parser_nested_tags(): assert p.tail is None assert len(p) == 1 - strong = list(p)[0] + strong = tuple(p)[0] assert isinstance(strong, ET.Element) assert strong.tag == "strong" assert strong.attrib == {} @@ -83,7 +83,7 @@ def test_html_parser_attributes(): parser.feed(text) elements = parser.close() - assert isinstance(elements, list) + assert isinstance(elements, tuple) assert len(elements) == 1 script = elements[0] @@ -111,7 +111,7 @@ def test_html_parser_svg(): parser.feed(text) elements = parser.close() - assert isinstance(elements, list) + assert isinstance(elements, tuple) assert len(elements) == 1 svg = elements[0] @@ -129,7 +129,7 @@ def test_html_parser_svg(): assert svg.tail is None assert len(svg) == 1 - path = list(svg)[0] + path = tuple(svg)[0] assert isinstance(path, ET.Element) assert path.tag == "path" assert path.attrib == { @@ -145,7 +145,7 @@ def test_parse_html(): elements = rico._html.parse_html(text) assert elem_to_string(elements) == text - assert isinstance(elements, list) + assert isinstance(elements, tuple) assert len(elements) == 1 p = elements[0] From e5a3965baf0cc0ca065739965869561165be32be Mon Sep 17 00:00:00 2001 From: Evgeny Ivanov Date: Sun, 4 Jun 2023 19:57:21 +0600 Subject: [PATCH 2/5] Change bootstrap parametrization --- src/rico/__init__.py | 10 +--------- src/rico/_config.py | 2 +- src/rico/_container.py | 15 +++++++-------- tests/test__container.py | 8 +++----- 4 files changed, 12 insertions(+), 23 deletions(-) diff --git a/src/rico/__init__.py b/src/rico/__init__.py index 4ce00ce..7f8b378 100644 --- a/src/rico/__init__.py +++ b/src/rico/__init__.py @@ -2,15 +2,7 @@ # pyright: reportUnusedImport=false """Rich content to HTML as easy as `Doc(df, plot)`.""" -from rico._config import ( - BOOTSTRAP_CSS, - BOOTSTRAP_JS, - BOOTSTRAP_VER, - DATAFRAME_STYLE, - config_context, - get_config, - set_config, -) +from rico._config import config_context, get_config, set_config from rico._container import Div, Doc from rico._content import ( Chart, diff --git a/src/rico/_config.py b/src/rico/_config.py index 6068c06..5335f4a 100644 --- a/src/rico/_config.py +++ b/src/rico/_config.py @@ -58,7 +58,7 @@ "inline_scripts": False, "inline_styles": False, "bootstrap_css": BOOTSTRAP_CSS, - "bootstrap_js": "", + "bootstrap_js": BOOTSTRAP_JS, "dataframe_style": DATAFRAME_STYLE, } diff --git a/src/rico/_container.py b/src/rico/_container.py index 1b736ae..4bc794f 100644 --- a/src/rico/_container.py +++ b/src/rico/_container.py @@ -13,7 +13,7 @@ if TYPE_CHECKING: from collections.abc import Callable, Iterable - from typing import Any, Concatenate, ParamSpec + from typing import Any, Concatenate, Literal, ParamSpec P = ParamSpec("P") @@ -79,13 +79,13 @@ class Doc(Div): body: ET.Element container: ET.Element - def __init__( # noqa: C901 + def __init__( self, *objects: Any, title: str | None = None, charset: str | None = "utf-8", viewport: str | None = "width=device-width, initial-scale=1", - bootstrap: bool = True, + bootstrap: Literal["css", "full", "none"] = "css", extra_styles: Iterable[rico._content.Style] = (), extra_scripts: Iterable[rico._content.Script] = (), class_: str | None = "container", @@ -129,11 +129,10 @@ def __init__( # noqa: C901 scripts : list[rico._content.Script] = [] global_config = rico._config.get_config() - if bootstrap: - if global_config["bootstrap_css"]: - styles.append(rico._content.Style(src=global_config["bootstrap_css"])) - if global_config["bootstrap_js"]: - scripts.append(rico._content.Script(src=global_config["bootstrap_js"])) + if bootstrap.lower() in {"css", "full"}: + styles.append(rico._content.Style(src=global_config["bootstrap_css"])) + if bootstrap.lower() == "full": + scripts.append(rico._content.Script(src=global_config["bootstrap_js"])) if global_config["dataframe_style"]: styles.append(rico._content.Style(text=global_config["dataframe_style"])) diff --git a/tests/test__container.py b/tests/test__container.py index 69a48f2..eb99822 100644 --- a/tests/test__container.py +++ b/tests/test__container.py @@ -228,15 +228,13 @@ def test_doc_init_nondefault(): # noqa: PLR0915 extra_script = rico._content.Script(text="alert('Hello World!');") extra_script.footer = True - with rico._config.config_context( - bootstrap_js=rico._config.BOOTSTRAP_JS, - dataframe_style="", - ): + with rico._config.config_context(dataframe_style=""): doc = rico._container.Doc( "Hello world", title="Title", charset=None, viewport=None, + bootstrap="full", extra_styles=(extra_style,), extra_scripts=(extra_script,), class_=None, @@ -341,7 +339,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 def test_doc_serialize(): with rico._config.config_context(dataframe_style=""): - doc = rico._container.Doc("Hello world", bootstrap=False) + doc = rico._container.Doc("Hello world", bootstrap="none") assert doc.serialize() == ( '\n' From d1c6562f974a219d568b0af4688ca3f82e9a0df3 Mon Sep 17 00:00:00 2001 From: Evgeny Ivanov Date: Sun, 4 Jun 2023 20:05:58 +0600 Subject: [PATCH 3/5] Move charset and viewport to global config --- src/rico/_config.py | 68 ++++++++++++++++++++++++---------------- src/rico/_container.py | 16 +++------- tests/test__container.py | 10 +++--- 3 files changed, 52 insertions(+), 42 deletions(-) diff --git a/src/rico/_config.py b/src/rico/_config.py index 5335f4a..d81a686 100644 --- a/src/rico/_config.py +++ b/src/rico/_config.py @@ -51,15 +51,17 @@ _global_config = { + "bootstrap_css": BOOTSTRAP_CSS, + "bootstrap_js": BOOTSTRAP_JS, + "dataframe_style": DATAFRAME_STYLE, + "image_format": "svg", "indent_html": False, "indent_space": " ", - "strip_html": False, - "image_format": "svg", "inline_scripts": False, "inline_styles": False, - "bootstrap_css": BOOTSTRAP_CSS, - "bootstrap_js": BOOTSTRAP_JS, - "dataframe_style": DATAFRAME_STYLE, + "meta_charset": "utf-8", + "meta_viewport": "width=device-width, initial-scale=1", + "strip_html": False, } @@ -79,31 +81,37 @@ def get_config(param: str | None = None) -> Any: def set_config( + bootstrap_css: str | None = None, + bootstrap_js: str | None = None, + dataframe_style: str | None = None, + image_format: Literal["svg", "png"] | None = None, indent_html: bool | None = None, indent_space: str | None = None, - strip_html: bool | None = None, - image_format: Literal["svg", "png"] | None = None, inline_scripts: bool | None = None, inline_styles: bool | None = None, - bootstrap_css: str | None = None, - bootstrap_js: str | None = None, - dataframe_style: str | None = None, + meta_charset: str | None = None, + meta_viewport: str | None = None, + strip_html: bool | None = None, ) -> None: """Set global configuration. Args: - indent_html: Indent HTML elements in serialization methods. - indent_space: Default indent space. - strip_html: Strip HTML elements in serialization methods. - image_format: Default chart image format. - inline_scripts: If True then scripts are loaded inline. - inline_styles: If True then styles are loaded inline. bootstrap_css: A link to a bootstrap css file. If empty then bootstrap css is not loaded. bootstrap_js: A link to a bootstrap javascript file. If empty then bootstrap javascript is not loaded. dataframe_style: A dataframe table stylesheet. If empty then it's not used. + image_format: Default chart image format. + indent_html: Indent HTML elements in serialization methods. + indent_space: Default indent space. + inline_scripts: If True then scripts are loaded inline. + inline_styles: If True then styles are loaded inline. + meta_charset: An HTML document charset. + If empty then it's not used. + meta_viewport: An HTML document viewport property. + If empty then it's not used. + strip_html: Strip HTML elements in serialization methods. """ for param, value in locals().items(): if value is not None: @@ -112,31 +120,37 @@ def set_config( @contextlib.contextmanager def config_context( + bootstrap_css: str | None = None, + bootstrap_js: str | None = None, + dataframe_style: str | None = None, + image_format: Literal["svg", "png"] | None = None, indent_html: bool | None = None, indent_space: str | None = None, - strip_html: bool | None = None, - image_format: Literal["svg", "png"] | None = None, inline_scripts: bool | None = None, inline_styles: bool | None = None, - bootstrap_css: str | None = None, - bootstrap_js: str | None = None, - dataframe_style: str | None = None, + meta_charset: str | None = None, + meta_viewport: str | None = None, + strip_html: bool | None = None, ) -> Generator[None, Any, None]: """Context manager for configuration. Args: - indent_html: Indent HTML elements in serialization methods. - indent_space: Default indent space. - strip_html: Strip HTML elements in serialization methods. - image_format: Default chart image format. - inline_scripts: If True then scripts are loaded inline. - inline_styles: If True then styles are loaded inline. bootstrap_css: A link to a bootstrap css file. If empty then bootstrap css is not loaded. bootstrap_js: A link to a bootstrap javascript file. If empty then bootstrap javascript is not loaded. dataframe_style: A dataframe table stylesheet. If empty then it's not used. + image_format: Default chart image format. + indent_html: Indent HTML elements in serialization methods. + indent_space: Default indent space. + inline_scripts: If True then scripts are loaded inline. + inline_styles: If True then styles are loaded inline. + meta_charset: An HTML document charset. + If empty then it's not used. + meta_viewport: An HTML document viewport property. + If empty then it's not used. + strip_html: Strip HTML elements in serialization methods. """ new_config = locals() old_config = get_config() diff --git a/src/rico/_container.py b/src/rico/_container.py index 4bc794f..ad50434 100644 --- a/src/rico/_container.py +++ b/src/rico/_container.py @@ -83,8 +83,6 @@ def __init__( self, *objects: Any, title: str | None = None, - charset: str | None = "utf-8", - viewport: str | None = "width=device-width, initial-scale=1", bootstrap: Literal["css", "full", "none"] = "css", extra_styles: Iterable[rico._content.Style] = (), extra_scripts: Iterable[rico._content.Script] = (), @@ -95,8 +93,6 @@ def __init__( Args: *objects: The objects which are used to create a content. title: The document title. - charset: The document charset. - viewport: The document viewport property. bootstrap: If True then Bootstrap included to the document. extra_styles: Extra styles to be included to the document. extra_scripts: Extra scripts to be included to the document. @@ -115,25 +111,23 @@ def __init__( title_element.text = title self.head.append(title_element) - if charset is not None: - self.head.append(ET.Element("meta", charset=charset)) - - if viewport is not None: + global_config = rico._config.get_config() + if global_config["meta_charset"]: + self.head.append(ET.Element("meta", charset=global_config["meta_charset"])) + if global_config["meta_viewport"]: self.head.append(ET.Element( "meta", name="viewport", - content=viewport, + content=global_config["meta_viewport"], )) styles : list[rico._content.Style] = [] scripts : list[rico._content.Script] = [] - global_config = rico._config.get_config() if bootstrap.lower() in {"css", "full"}: styles.append(rico._content.Style(src=global_config["bootstrap_css"])) if bootstrap.lower() == "full": scripts.append(rico._content.Script(src=global_config["bootstrap_js"])) - if global_config["dataframe_style"]: styles.append(rico._content.Style(text=global_config["dataframe_style"])) diff --git a/tests/test__container.py b/tests/test__container.py index eb99822..4e80ffc 100644 --- a/tests/test__container.py +++ b/tests/test__container.py @@ -228,13 +228,15 @@ def test_doc_init_nondefault(): # noqa: PLR0915 extra_script = rico._content.Script(text="alert('Hello World!');") extra_script.footer = True - with rico._config.config_context(dataframe_style=""): + with rico._config.config_context( + meta_charset="", + meta_viewport="", + dataframe_style="", + ): doc = rico._container.Doc( "Hello world", title="Title", - charset=None, - viewport=None, - bootstrap="full", + bootstrap="full", extra_styles=(extra_style,), extra_scripts=(extra_script,), class_=None, From 9503e5e1c19516309579092e5e1de65dd0f1e649 Mon Sep 17 00:00:00 2001 From: Evgeny Ivanov Date: Sun, 4 Jun 2023 20:08:59 +0600 Subject: [PATCH 4/5] Remove script and style attrs from Script and Style classes --- src/rico/_container.py | 6 +++--- src/rico/_content.py | 14 ++++++-------- tests/test__container.py | 4 ++-- tests/test__content.py | 12 ++++++------ 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/rico/_container.py b/src/rico/_container.py index ad50434..c4d3e6e 100644 --- a/src/rico/_container.py +++ b/src/rico/_container.py @@ -135,13 +135,13 @@ def __init__( scripts = [*scripts, *extra_scripts] for style in styles: - self.head.append(style.style) + self.head.append(style.container) for script in scripts: if script.footer: - self.body.append(script.script) + self.body.append(script.container) else: - self.head.append(script.script) + self.head.append(script.container) def serialize( self, diff --git a/src/rico/_content.py b/src/rico/_content.py index 7b42264..d33ff55 100644 --- a/src/rico/_content.py +++ b/src/rico/_content.py @@ -377,7 +377,7 @@ class Script(ContentBase): footer (bool): Defines whether the script should be placed at a document footer, aftert all other content. """ - script: ET.Element + container: ET.Element footer: bool = False def __init__( @@ -428,9 +428,8 @@ def __init__( else: self.footer = defer - self.script = ET.Element("script", {**attrib, **extra}) - self.script.text = text - self.container = self.script + self.container = ET.Element("script", {**attrib, **extra}) + self.container.text = text class Style(ContentBase): @@ -439,7 +438,7 @@ class Style(ContentBase): Attributes: style (Element): The style element. """ - style: ET.Element + container: ET.Element def __init__( self, @@ -487,6 +486,5 @@ def __init__( else: tag = "style" - self.style = ET.Element(tag, {**attrib, **extra}) - self.style.text = text - self.container = self.style + self.container = ET.Element(tag, {**attrib, **extra}) + self.container.text = text diff --git a/tests/test__container.py b/tests/test__container.py index 4e80ffc..6eeebd6 100644 --- a/tests/test__container.py +++ b/tests/test__container.py @@ -279,7 +279,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 assert len(bootstrap_css) == 0 style = tuple(head)[2] - style = extra_style.style + style = extra_style.container assert isinstance(style, ET.Element) assert style.tag == "link" assert style.attrib == {"src": "style.css", "rel": "stylesheet"} @@ -330,7 +330,7 @@ def test_doc_init_nondefault(): # noqa: PLR0915 assert len(p) == 0 script = tuple(body)[1] - assert script == extra_script.script + assert script == extra_script.container assert isinstance(script, ET.Element) assert script.tag == "script" assert script.attrib == {} diff --git a/tests/test__content.py b/tests/test__content.py index 8ef4bb0..dfbe940 100644 --- a/tests/test__content.py +++ b/tests/test__content.py @@ -479,7 +479,7 @@ def test_script_text(defer: bool): attrib = {"async": True} content = rico._content.Script(text=text, defer=defer, attrib=attrib) - script = content.script + script = content.container assert isinstance(script, ET.Element) assert script.tag == "script" assert script.attrib == attrib @@ -501,7 +501,7 @@ def test_script_src(defer: bool): if defer: attrib = {"defer": True, **attrib} - script = content.script + script = content.container assert isinstance(script, ET.Element) assert script.tag == "script" assert script.attrib == attrib @@ -524,7 +524,7 @@ def test_script_inline(defer: bool): content = rico._content.Script(src=src, inline=True, defer=defer, attrib=attrib) urlopen.assert_called_once_with(src) - script = content.script + script = content.container assert isinstance(script, ET.Element) assert script.tag == "script" assert script.attrib == attrib @@ -548,7 +548,7 @@ def test_style_text(): attrib = {"title": "Style title"} content = rico._content.Style(text=text, attrib=attrib) - style = content.style + style = content.container assert isinstance(style, ET.Element) assert style.tag == "style" assert style.attrib == attrib @@ -566,7 +566,7 @@ def test_style_src(): attrib = {"src": src, **attrib, "rel": "stylesheet"} - link = content.style + link = content.container assert isinstance(link, ET.Element) assert link.tag == "link" assert link.attrib == attrib @@ -587,7 +587,7 @@ def test_style_inline(): content = rico._content.Style(src=src, inline=True, attrib=attrib) urlopen.assert_called_once_with(src) - style = content.style + style = content.container assert isinstance(style, ET.Element) assert style.tag == "style" assert style.attrib == attrib From f43e31e2b3deec3b7107a93455aa9778470813bd Mon Sep 17 00:00:00 2001 From: Evgeny Ivanov Date: Sun, 4 Jun 2023 20:14:36 +0600 Subject: [PATCH 5/5] Add global config text_mono and text_wrap --- src/rico/_config.py | 10 ++++++++++ src/rico/_content.py | 10 ++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/rico/_config.py b/src/rico/_config.py index d81a686..1cb9f40 100644 --- a/src/rico/_config.py +++ b/src/rico/_config.py @@ -62,6 +62,8 @@ "meta_charset": "utf-8", "meta_viewport": "width=device-width, initial-scale=1", "strip_html": False, + "text_mono": False, + "text_wrap": False, } @@ -92,6 +94,8 @@ def set_config( meta_charset: str | None = None, meta_viewport: str | None = None, strip_html: bool | None = None, + text_mono: bool | None = None, + text_wrap: bool | None = None, ) -> None: """Set global configuration. @@ -112,6 +116,8 @@ def set_config( meta_viewport: An HTML document viewport property. If empty then it's not used. strip_html: Strip HTML elements in serialization methods. + text_mono: Default value for the `mono` arg of the Text class. + text_wrap: Default value for the `wrap` arg of the Text class. """ for param, value in locals().items(): if value is not None: @@ -131,6 +137,8 @@ def config_context( meta_charset: str | None = None, meta_viewport: str | None = None, strip_html: bool | None = None, + text_mono: bool | None = None, + text_wrap: bool | None = None, ) -> Generator[None, Any, None]: """Context manager for configuration. @@ -151,6 +159,8 @@ def config_context( meta_viewport: An HTML document viewport property. If empty then it's not used. strip_html: Strip HTML elements in serialization methods. + text_mono: Default value for the `mono` arg of the Text class. + text_wrap: Default value for the `wrap` arg of the Text class. """ new_config = locals() old_config = get_config() diff --git a/src/rico/_content.py b/src/rico/_content.py index d33ff55..4f4be0a 100644 --- a/src/rico/_content.py +++ b/src/rico/_content.py @@ -125,8 +125,8 @@ class Text(ContentBase): def __init__( self, obj: Any, - mono: bool = False, - wrap: bool = False, + mono: bool | None = None, + wrap: bool | None = None, class_: str | None = None, ): """Create content from a text. @@ -144,6 +144,12 @@ def __init__( """ super().__init__(class_) + global_config = rico._config.get_config() + if mono is None: + mono = global_config["text_mono"] + if wrap is None: + wrap = global_config["text_wrap"] + if not isinstance(obj, str): obj = str(obj)