Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e3de148
docs(decisions): supersede 2026-05-18 type-system decisions with sibl…
schloerke May 20, 2026
f84b423
refactor(_core): non-generic recursive Tagified; forward-ref Tagified…
schloerke May 20, 2026
db29da8
feat(_core): introduce _TagBase and immutable TagifiedTag skeleton
schloerke May 20, 2026
3d4209d
feat(_core): introduce immutable TagifiedTagList (Sequence-backed)
schloerke May 20, 2026
73eea19
refactor(_core): drop Tag's TagNodeT generic; rewire Tag.tagify to co…
schloerke May 20, 2026
1a5fea3
refactor(_core): drop TagList's TagNodeT generic; rewire TagList.tagi…
schloerke May 20, 2026
d28d0a1
refactor(_jsx): JSXTag.tagify returns TagifiedTag (sibling), not Tag[…
schloerke May 20, 2026
e7c999d
refactor(_core, _jsx): finish isinstance audit for sibling classes
schloerke May 20, 2026
3a20ff8
refactor(_core): address review — explicit Tagified arm, is_tag_like …
schloerke May 20, 2026
91991b6
refactor(_core): address review — TagifiedNode parity, deduped __init__
schloerke May 20, 2026
be52222
feat(_core): add is_tagified(x) -> TypeIs[TagifiedTag | TagifiedTagList]
schloerke May 20, 2026
618c25c
feat(htmltools): export is_tag_like / is_taglist_like / is_tagified; …
schloerke May 20, 2026
4f25c2d
fix(htmltools): unexport is_tag_like and is_taglist_like
schloerke May 20, 2026
3c64a3b
refactor(_core): delete render-time mutation-after-tagify guard
schloerke May 20, 2026
b84eea1
refactor(_core): HTMLDocument.{_gen_html_tag_tree,_hoist_head_content…
schloerke May 20, 2026
4535849
test: update existing tests for sibling classes; add disjoint/immutab…
schloerke May 20, 2026
46c2e8f
docs(changelog): document sibling-classes refactor for 0.7.0
schloerke May 20, 2026
e475e78
fix(_core): restore render-time RuntimeError guard as defense-in-depth
schloerke May 20, 2026
fe3ac85
docs(changelog): audit 0.7.0 entries against v0.6.1 baseline
schloerke May 20, 2026
fdae559
docs(changelog): smooth 0.7.0 prose
schloerke May 20, 2026
6d099ed
fix(_core): address Copilot review on PR #120
schloerke May 20, 2026
4c102d8
fix(_core): move has_class to _TagBase (read-only, available on both …
schloerke May 20, 2026
c9ff329
feat(htmltools): export TagifiedTag and TagifiedTagList
schloerke May 20, 2026
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
32 changes: 7 additions & 25 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Breaking changes

* `Tagifiable.tagify()` now returns `Tagified`, a tighter type that
excludes the un-resolved `Tagifiable` arm of `TagNode`. Custom
`.tagify()` implementations annotated with bare `TagList` or `Tag`
return types will fail static type checking; update them to
`-> Tagified` (or omit the return annotation). Runtime behavior of
correct `.tagify()` implementations is unchanged. (#105)
* `Tagifiable.tagify()`'s return annotation is now `Tagified`, a new type alias for the union of fully-tagified shapes (`TagifiedNode | float | None | Sequence[Tagified]`, mirroring `TagChild`). Custom `.tagify()` implementations annotated with bare `TagList` / `Tag` return types should switch to `-> Tagified`, or drop the annotation. Runtime behavior of correct implementations is unchanged. (#105, #116)

* `Tag.tagify()` no longer preserves the caller's `Tag` subclass in
its return type. Code relying on the previous subclass-preserving
signature should `cast` the result. (#105)
* The result of `.tagify()` is now **immutable**. Calling `.append`, `.extend`, `.insert`, `.add_class`, `__setitem__`, or the context-manager `with` form on a tagified value raises `AttributeError` and is a static type error. Mutate on the buildable `Tag` / `TagList` side, then call `.tagify()` once to produce the render-ready result. (#116)

### New features

* `Tag` and `TagList` are now generic in their child type, defaulting
to `TagNode`. Bare `Tag` / `TagList` retain today's meaning. Mutation
methods (`append` / `extend` / `insert`) still accept `Tagifiable` at
static-type-check time even on tagified containers — the invariant
is enforced at runtime instead (`TagList.tagify()` raises `TypeError`
and `get_html_string` raises `RuntimeError` for an un-tagified
subtree). See `tests/test_types.py` for the rationale. (#105)
* `TagList.tagify()` now raises `TypeError` at the boundary when a child's `.tagify()` returns un-tagified content (e.g. a bare `TagList` containing a still-`Tagifiable` object). The error names the offending class and slot index so buggy `.tagify()` implementations surface at the source. The render-time `RuntimeError` for the same family of violations has been clarified. (#7, #105, #112, #116)

* Added the public type alias `Tagified` — the union of all
fully-tagified shapes — for use as the return annotation of
`Tagifiable.tagify()` implementations. (#105)
### New features

### Bug fixes
* Exported the new tagified sibling classes `TagifiedTag` and `TagifiedTagList`. Use them in narrow annotations (`def f(t: TagifiedTag): ...`) and `isinstance` checks on `.tagify()` output. (#116)

* `TagList.tagify()` now raises `TypeError` at the boundary when a child's `.tagify()` returns a `TagList` containing an un-tagified `Tagifiable` object. The error names the offending class and slot index so buggy `.tagify()` implementations surface at the source rather than later at render time. The render-time `RuntimeError` raised by `get_html_string()` for an un-tagified child has also been clarified to include the offending class name and a hint that the tree was likely mutated after `.tagify()` was called. (#7, #105, #112)
* Added `is_tagified(x)` for runtime distinguishability between buildable `Tag` / `TagList` and their tagified counterparts. Returns a `TypeIs[...]` so pyright narrows at call sites. (#116)

### Dependencies

* Bumped `typing_extensions` floor to `>=4.12.0`, required for
PEP 696 `TypeVar(default=...)` support on Python 3.13+.
* Bumped `typing-extensions` floor to `>=4.12.0`.

### Other changes

Expand Down
82 changes: 0 additions & 82 deletions decisions/2026-05-18-tag-mutation-wide-tagchild.md

This file was deleted.

90 changes: 0 additions & 90 deletions decisions/2026-05-18-tagify-returns-tagified.md

This file was deleted.

Loading
Loading