Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
200 changes: 192 additions & 8 deletions htpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from markupsafe import Markup as _Markup
from markupsafe import escape as _escape
from typing_extensions import TypedDict, Unpack

try:
from warnings import deprecated # type: ignore[attr-defined,unused-ignore]
Expand Down Expand Up @@ -265,19 +266,23 @@ def __str__(self) -> _Markup:

@t.overload
def __call__(
self: BaseElementSelf, id_class: str, attrs: Mapping[str, Attribute], **kwargs: Attribute
self: BaseElementSelf,
id_class: str,
attrs: Mapping[str, Attribute],
/,
**kwargs: Unpack[AttrKwargs],
) -> BaseElementSelf: ...
@t.overload
def __call__(
self: BaseElementSelf, id_class: str = "", **kwargs: Attribute
self: BaseElementSelf, id_class: str = "", /, **kwargs: Unpack[AttrKwargs]
) -> BaseElementSelf: ...
@t.overload
def __call__(
self: BaseElementSelf, attrs: Mapping[str, Attribute], **kwargs: Attribute
self: BaseElementSelf, attrs: Mapping[str, Attribute], /, **kwargs: Unpack[AttrKwargs]
) -> BaseElementSelf: ...
@t.overload
def __call__(self: BaseElementSelf, **kwargs: Attribute) -> BaseElementSelf: ...
def __call__(self: BaseElementSelf, *args: t.Any, **kwargs: t.Any) -> BaseElementSelf:
def __call__(
self: BaseElementSelf, *args: t.Any, **kwargs: Unpack[AttrKwargs]
) -> BaseElementSelf:
id_class = ""
attrs: Mapping[str, Attribute] = {}

Expand Down Expand Up @@ -456,7 +461,186 @@ def encode(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: ...
Renderable | None | bool | str | int | _HasHtml | Iterable["Node"] | Callable[[], "Node"]
)

Attribute: t.TypeAlias = None | bool | str | int | _HasHtml | _ClassNames
_NonClassAttribute: t.TypeAlias = None | bool | str | int | _HasHtml
Attribute: t.TypeAlias = _NonClassAttribute | _ClassNames


class AttrKwargs(TypedDict, total=False, extra_items=_NonClassAttribute):
# These are the modified attributes to make them valid identifiers
accept_charset: _NonClassAttribute
async_: _NonClassAttribute
class_: Attribute
for_: _NonClassAttribute
http_equiv: _NonClassAttribute
# The rest of the html attributes
accept: _NonClassAttribute
accesskey: _NonClassAttribute
action: _NonClassAttribute
align: _NonClassAttribute
alt: _NonClassAttribute
autocomplete: _NonClassAttribute
autofocus: _NonClassAttribute
autoplay: _NonClassAttribute
bgcolor: _NonClassAttribute
border: _NonClassAttribute
charset: _NonClassAttribute
checked: _NonClassAttribute
cite: _NonClassAttribute
color: _NonClassAttribute
cols: _NonClassAttribute
colspan: _NonClassAttribute
content: _NonClassAttribute
contenteditable: _NonClassAttribute
controls: _NonClassAttribute
coords: _NonClassAttribute
data: _NonClassAttribute
datetime: _NonClassAttribute
default: _NonClassAttribute
defer: _NonClassAttribute
dir: _NonClassAttribute
dirname: _NonClassAttribute
disabled: _NonClassAttribute
download: _NonClassAttribute
draggable: _NonClassAttribute
enctype: _NonClassAttribute
enterkeyhint: _NonClassAttribute
form: _NonClassAttribute
formaction: _NonClassAttribute
headers: _NonClassAttribute
height: _NonClassAttribute
hidden: _NonClassAttribute
high: _NonClassAttribute
href: _NonClassAttribute
hreflang: _NonClassAttribute
id: _NonClassAttribute
inert: _NonClassAttribute
inputmode: _NonClassAttribute
ismap: _NonClassAttribute
kind: _NonClassAttribute
label: _NonClassAttribute
lang: _NonClassAttribute
list: _NonClassAttribute
loop: _NonClassAttribute
low: _NonClassAttribute
max: _NonClassAttribute
maxlength: _NonClassAttribute
media: _NonClassAttribute
method: _NonClassAttribute
min: _NonClassAttribute
multiple: _NonClassAttribute
muted: _NonClassAttribute
name: _NonClassAttribute
novalidate: _NonClassAttribute
onabort: _NonClassAttribute
onafterprint: _NonClassAttribute
onbeforeprint: _NonClassAttribute
onbeforeunload: _NonClassAttribute
onblur: _NonClassAttribute
oncanplay: _NonClassAttribute
oncanplaythrough: _NonClassAttribute
onchange: _NonClassAttribute
onclick: _NonClassAttribute
oncontextmenu: _NonClassAttribute
oncopy: _NonClassAttribute
oncuechange: _NonClassAttribute
oncut: _NonClassAttribute
ondblclick: _NonClassAttribute
ondrag: _NonClassAttribute
ondragend: _NonClassAttribute
ondragenter: _NonClassAttribute
ondragleave: _NonClassAttribute
ondragover: _NonClassAttribute
ondragstart: _NonClassAttribute
ondrop: _NonClassAttribute
ondurationchange: _NonClassAttribute
onemptied: _NonClassAttribute
onended: _NonClassAttribute
onerror: _NonClassAttribute
onfocus: _NonClassAttribute
onhashchange: _NonClassAttribute
oninput: _NonClassAttribute
oninvalid: _NonClassAttribute
onkeydown: _NonClassAttribute
onkeypress: _NonClassAttribute
onkeyup: _NonClassAttribute
onload: _NonClassAttribute
onloadeddata: _NonClassAttribute
onloadedmetadata: _NonClassAttribute
onloadstart: _NonClassAttribute
onmousedown: _NonClassAttribute
onmousemove: _NonClassAttribute
onmouseout: _NonClassAttribute
onmouseover: _NonClassAttribute
onmouseup: _NonClassAttribute
onmousewheel: _NonClassAttribute
onoffline: _NonClassAttribute
ononline: _NonClassAttribute
onpagehide: _NonClassAttribute
onpageshow: _NonClassAttribute
onpaste: _NonClassAttribute
onpause: _NonClassAttribute
onplay: _NonClassAttribute
onplaying: _NonClassAttribute
onpopstate: _NonClassAttribute
onprogress: _NonClassAttribute
onratechange: _NonClassAttribute
onreset: _NonClassAttribute
onresize: _NonClassAttribute
onscroll: _NonClassAttribute
onsearch: _NonClassAttribute
onseeked: _NonClassAttribute
onseeking: _NonClassAttribute
onselect: _NonClassAttribute
onstalled: _NonClassAttribute
onstorage: _NonClassAttribute
onsubmit: _NonClassAttribute
onsuspend: _NonClassAttribute
ontimeupdate: _NonClassAttribute
ontoggle: _NonClassAttribute
onunload: _NonClassAttribute
onvolumechange: _NonClassAttribute
onwaiting: _NonClassAttribute
onwheel: _NonClassAttribute
open: _NonClassAttribute
optimum: _NonClassAttribute
pattern: _NonClassAttribute
placeholder: _NonClassAttribute
popover: _NonClassAttribute
popovertarget: _NonClassAttribute
popovertargetaction: _NonClassAttribute
poster: _NonClassAttribute
preload: _NonClassAttribute
readonly: _NonClassAttribute
rel: _NonClassAttribute
required: _NonClassAttribute
reversed: _NonClassAttribute
rows: _NonClassAttribute
rowspan: _NonClassAttribute
sandbox: _NonClassAttribute
scope: _NonClassAttribute
selected: _NonClassAttribute
shape: _NonClassAttribute
size: _NonClassAttribute
sizes: _NonClassAttribute
span: _NonClassAttribute
spellcheck: _NonClassAttribute
src: _NonClassAttribute
srcdoc: _NonClassAttribute
srclang: _NonClassAttribute
srcset: _NonClassAttribute
start: _NonClassAttribute
step: _NonClassAttribute
style: _NonClassAttribute
tabindex: _NonClassAttribute
target: _NonClassAttribute
title: _NonClassAttribute
translate: _NonClassAttribute
type: _NonClassAttribute
usemap: _NonClassAttribute
value: _NonClassAttribute
width: _NonClassAttribute
wrap: _NonClassAttribute


# https://developer.mozilla.org/en-US/docs/Glossary/Doctype
html = HTMLElement("html")
Expand Down Expand Up @@ -593,5 +777,5 @@ def encode(self, encoding: str = "utf-8", errors: str = "strict") -> bytes: ...
| Fragment
| _HasHtml
| Callable
| Iterable
| Iterable # pyright: ignore [reportMissingTypeArgument]
)
7 changes: 5 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ dynamic = ["version"]
dependencies = [
"markupsafe>=2.0.0",
# typing_extensions is used for @warnings.deprecated introduced in Python 3.13
"typing_extensions>=4.13.2 ; python_version<'3.13'",
# it is also used for the extra_items feature of TypedDict coming in python 3.14 (PEP 728)
"typing_extensions>=4.13.2 ; python_version<'3.14'",
]
readme = "docs/README.md"
authors = [
Expand All @@ -26,7 +27,7 @@ optional-dependencies.dev = [
"pre-commit",
"flit",
"mypy",
"pyright",
"pyright>=1.1.400",
"pytest",
"black",
"ruff",
Expand Down Expand Up @@ -84,6 +85,8 @@ exclude = ["examples", "scripts"]
[tool.pyright]
include = ["htpy", "tests"]
strict = ["htpy", "tests"]
# This is for PEP 728 support (TypedDict with extra keys)
enableExperimentalFeatures = true

[tool.pytest.ini_options]
addopts = "--doctest-glob='docs/*.md'"
Loading