Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.12", "3.11", "3.10", "3.9", "3.9"]
os: [ubuntu-latest, windows-latest, macOS-latest]
fail-fast: false
defaults:
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* `HTML` no longer inherits from `str`. It now inherits from `collections.UserString`. This was done to avoid confusion between `str` and `HTML` objects. (#86)

* `TagList` no longer inherits from `list`. It now inherits from `collections.UserList`. This was done to avoid confusion between `list` and `TagList` objects. (#97)

* `Tag` and `TagList`'s method `.get_html_string()` now both return `str` instead of `HTML`. (#86)

* Strings added to `HTML` objects, now return `HTML` objects. E.g. `HTML_value + str_value` and `str_value_ + HTML_value` both return `HTML` objects. To maintain a `str` result, call `str()` on your `HTML` objects before adding them to strings. (#86)
Expand Down
17 changes: 8 additions & 9 deletions htmltools/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@
import tempfile
import urllib.parse
import webbrowser
from collections import UserString
from collections import UserList, UserString
from copy import copy, deepcopy
from pathlib import Path
from typing import (
Any,
Callable,
Dict,
Iterable,
List,
Mapping,
Optional,
Sequence,
Expand Down Expand Up @@ -255,7 +254,7 @@ def _repr_html_(self) -> str: ...
# =============================================================================
# TagList class
# =============================================================================
class TagList(List[TagNode]):
class TagList(UserList[TagNode]):
"""
Create an HTML tag list (i.e., a fragment of HTML)

Expand All @@ -275,26 +274,26 @@ class TagList(List[TagNode]):
def __init__(self, *args: TagChild) -> None:
super().__init__(_tagchilds_to_tagnodes(args))

def extend(self, x: Iterable[TagChild]) -> None:
def extend(self, other: Iterable[TagChild]) -> None:
"""
Extend the children by appending an iterable of children.
"""

super().extend(_tagchilds_to_tagnodes(x))
super().extend(_tagchilds_to_tagnodes(other))

def append(self, *args: TagChild) -> None:
def append(self, item: TagChild, *args: TagChild) -> None:
"""
Append tag children to the end of the list.
"""

self.extend(args)
self.extend([item, *args])

def insert(self, index: SupportsIndex, x: TagChild) -> None:
def insert(self, i: SupportsIndex, item: TagChild) -> None:
"""
Insert tag children before a given index.
"""

self[index:index] = _tagchilds_to_tagnodes([x])
self[i:i] = _tagchilds_to_tagnodes([item])

def tagify(self) -> "TagList":
"""
Expand Down
9 changes: 7 additions & 2 deletions htmltools/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,16 @@ def flatten(x: Iterable[Union[T, None]]) -> list[T]:
# Having this separate function and passing along `result` is faster than defining
# a closure inside of `flatten()` (and not passing `result`).
def _flatten_recurse(x: Iterable[T | None], result: list[T]) -> None:
from ._core import TagList

for item in x:
if isinstance(item, (list, tuple)):
if isinstance(item, (list, tuple, TagList)):
# Don't yet know how to specify recursive generic types, so we'll tell
# the type checker to ignore this line.
_flatten_recurse(item, result) # pyright: ignore[reportUnknownArgumentType]
_flatten_recurse(
item, # pyright: ignore[reportUnknownArgumentType]
result, # pyright: ignore[reportArgumentType]
)
elif item is not None:
result.append(item)

Expand Down
63 changes: 27 additions & 36 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,56 +1,47 @@
[build-system]
requires = [
"setuptools",
"wheel"
]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "htmltools"
dynamic = ["version"]
authors = [{name = "Carson Sievert", email = "[email protected]"}]
authors = [{ name = "Carson Sievert", email = "[email protected]" }]
description = "Tools for HTML generation and output."
readme = "README.md"
license = {file = "LICENSE"}
license = { file = "LICENSE" }
keywords = ["html"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Text Processing :: Markup :: HTML"
]
dependencies = [
"typing-extensions>=3.10.0.0",
"packaging>=20.9",
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Text Processing :: Markup :: HTML",
]
requires-python = ">=3.8"
dependencies = ["typing-extensions>=3.10.0.0", "packaging>=20.9"]
requires-python = ">=3.9"

[project.urls]
"Bug Tracker" = "https://github.com/rstudio/py-htmltools/issues"
Source = "https://github.com/rstudio/py-htmltools"

[project.optional-dependencies]
test = [
"pytest>=6.2.4",
"syrupy>=4.6.0"
]
test = ["pytest>=6.2.4", "syrupy>=4.6.0"]
dev = [
"black>=24.2.0",
"flake8>=6.0.0",
"Flake8-pyproject",
"isort>=5.11.2",
"pyright>=1.1.348",
"pre-commit>=2.15.0",
"wheel",
"build"
"black>=24.2.0",
"flake8>=6.0.0",
"Flake8-pyproject",
"isort>=5.11.2",
"pyright>=1.1.348",
"pre-commit>=2.15.0",
"wheel",
"build",
]

[tool.setuptools]
Expand All @@ -59,7 +50,7 @@ include-package-data = true
zip-safe = false

[tool.setuptools.dynamic]
version = {attr = "htmltools.__version__"}
version = { attr = "htmltools.__version__" }

[tool.setuptools.package-data]
htmltools = ["py.typed"]
Expand Down