Skip to content

Commit 0591649

Browse files
authored
fix(content): allow defining inner content without any wrapping html tags, with the ordering kept as written in hiccup (#8)
* test: assert that items of different types are ordered as expected * fix(content): allow defining inner content without any wrapping html tags, with the ordering kept as written in hiccup * bump version to 0.3.0
1 parent 4fa5552 commit 0591649

File tree

7 files changed

+34
-26
lines changed

7 files changed

+34
-26
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# Python Hiccup
22

3-
This project started out as a fun challenge, and now evolving into something that could be useful.
4-
5-
Current status: _experimental_
3+
Python Hiccup is a library for representing HTML using plain Python data structures.
64

75
[![CircleCI](https://dl.circleci.com/status-badge/img/gh/DavidVujic/python-hiccup/tree/main.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/DavidVujic/python-hiccup/tree/main)
86

@@ -14,6 +12,8 @@ Current status: _experimental_
1412
This is a Python implementation of the Hiccup syntax. Python Hiccup is a library for representing HTML in Python.
1513
Using `list` or `tuple` to represent HTML elements, and `dict` to represent the element attributes.
1614

15+
_This project started out as a fun coding challenge, and now evolving into something useful for Python Dev teams._
16+
1717
## Usage
1818
Create server side HTML using plain Python data structures.
1919
This library should also be possible to combine with PyScript, but I haven't tested that out yet.

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "python-hiccup"
3-
version = "0.2.0"
4-
description = "Add your description here"
3+
version = "0.3.0"
4+
description = "Python Hiccup is a library for representing HTML using plain Python data structures"
55
readme = "README.md"
66
requires-python = ">=3.10"
77
dependencies = []

src/python_hiccup/html/core.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from collections.abc import Mapping, Sequence
66
from functools import reduce
77

8-
from python_hiccup.transform import transform
8+
from python_hiccup.transform import CONTENT_TAG, transform
99

1010

1111
def _element_allows_raw_content(element: str) -> bool:
@@ -56,23 +56,28 @@ def _suffix(element_data: str) -> str:
5656
return "" if any(s in normalized for s in specials) else " /"
5757

5858

59-
def _to_html(tag: Mapping) -> list:
59+
def _is_content(element: str) -> bool:
60+
return element == CONTENT_TAG
61+
62+
63+
def _to_html(tag: Mapping, parent: str = "") -> list:
6064
element = next(iter(tag.keys()))
6165
child = next(iter(tag.values()))
6266

67+
if _is_content(element):
68+
return [_escape(str(child), parent)]
69+
6370
attributes = reduce(_to_attributes, tag.get("attributes", []), "")
6471
bool_attributes = reduce(_to_bool_attributes, tag.get("boolean_attributes", []), "")
6572
element_attributes = attributes + bool_attributes
6673

67-
content = [_escape(str(c), element) for c in tag.get("content", [])]
68-
69-
matrix = [_to_html(c) for c in child]
74+
matrix = [_to_html(c, element) for c in child]
7075
flattened: list = reduce(operator.iadd, matrix, [])
7176

7277
begin = f"{element}{element_attributes}" if element_attributes else element
7378

74-
if flattened or content:
75-
return [f"<{begin}>", *flattened, *content, f"</{element}>"]
79+
if flattened:
80+
return [f"<{begin}>", *flattened, f"</{element}>"]
7681

7782
if _closing_tag(element):
7883
return [f"<{begin}>", f"</{element}>"]
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""Transform Hiccup syntax."""
22

3-
from python_hiccup.transform.core import transform
3+
from python_hiccup.transform.core import CONTENT_TAG, transform
44

5-
__all__ = ["transform"]
5+
__all__ = ["CONTENT_TAG", "transform"]

src/python_hiccup/transform/core.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
ATTRIBUTES = "attributes"
1111
BOOLEAN_ATTRIBUTES = "boolean_attributes"
1212
CHILDREN = "children"
13-
CONTENT = "content"
13+
14+
CONTENT_TAG = "<::HICCUP_CONTENT::>"
1415

1516

1617
def _is_attribute(item: Item) -> bool:
@@ -25,12 +26,6 @@ def _is_child(item: Item) -> bool:
2526
return isinstance(item, list | tuple)
2627

2728

28-
def _is_content(item: Item) -> bool:
29-
pipeline = [_is_attribute, _is_boolean_attribute, _is_child]
30-
31-
return not any(fn(item) for fn in pipeline)
32-
33-
3429
def _is_sibling(item: Item) -> bool:
3530
return _is_child(item)
3631

@@ -40,8 +35,6 @@ def _key_for_group(item: Item) -> str:
4035
return ATTRIBUTES
4136
if _is_boolean_attribute(item):
4237
return BOOLEAN_ATTRIBUTES
43-
if _is_content(item):
44-
return CONTENT
4538

4639
return CHILDREN
4740

@@ -67,6 +60,9 @@ def _extract_from_tag(tag: str) -> tuple[str, dict]:
6760

6861

6962
def _transform_tags(tags: Sequence) -> dict:
63+
if not isinstance(tags, list | tuple):
64+
return {CONTENT_TAG: tags}
65+
7066
first, *rest = tags
7167

7268
element, extracted = _extract_from_tag(first)

test/test_render_html.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ def test_generates_an_element_with_children() -> None:
132132

133133
def test_allows_numeric_values_in_content() -> None:
134134
"""Assert that numeric values are allowed as the content of an element."""
135-
data = ["ul", ["li", 1]]
135+
data = ["ul", ["li", 1], ["li", 2.2]]
136136

137-
assert render(data) == "<ul><li>1</li></ul>"
137+
assert render(data) == "<ul><li>1</li><li>2.2</li></ul>"
138+
139+
140+
def test_order_of_items() -> None:
141+
"""Assert that items of different types are ordered as expected."""
142+
data = ["h1", "some ", ["span.pys", "<py>"]]
143+
144+
assert render(data) == '<h1>some <span class="pys">&lt;py&gt;</span></h1>'

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)