justhtml 3.11.2__tar.gz → 3.11.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {justhtml-3.11.2 → justhtml-3.11.3}/CHANGELOG.md +7 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/PKG-INFO +1 -1
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/linkify.md +3 -2
- {justhtml-3.11.2 → justhtml-3.11.3}/pyproject.toml +1 -1
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/parser/engine.py +2 -5
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/transforms/runtime.py +0 -3
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_parser_engine.py +1 -1
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_sanitize_integration.py +11 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_transforms.py +23 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/.github/workflows/ci.yml +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/.github/workflows/publish.yml +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/.gitignore +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/.pre-commit-config.yaml +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/AGENTS.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/ARCHITECTURE.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/CODE_OF_CONDUCT.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/CONTRIBUTING.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/LICENSE +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/Makefile +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/PERFORMANCE.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/README.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/SECURITY.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/assets/justhtml-readme-explainer.png +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/benchmarks/chromium_parser_diff.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/benchmarks/correctness.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/benchmarks/fuzz.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/benchmarks/html5lib_engine_diff.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/benchmarks/parser_engine_gate.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/benchmarks/performance.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/benchmarks/profile.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/_config.yml +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/_layouts/default.html +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/api.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/assets/search.js +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/bleach-migration.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/building.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/cli.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/comparison.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/correctness.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/encoding.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/errors.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/fragments.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/html-cleaning.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/index.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/migration-examples.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/playground/app.js +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/playground/index.html +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/playground/py/__init__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/playground/py/install_latest_justhtml.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/playground/py/render.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/playground/py/use_local_repo.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/quickstart.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/sanitization.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/selectors.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/streaming.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/text.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/transforms.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/unsafe-handling.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/docs/url-cleaning.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/llms.txt +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/project_ideas.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/run_tests.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/scripts/release.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/__init__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/__main__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/core/__init__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/core/constants.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/core/doctype.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/core/entities.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/core/errors.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/core/rawtext.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/core/text.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/core/types.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/dom/__init__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/dom/builder.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/parser/__init__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/parser/context.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/parser/encoding.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/parser/options.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/parser/scanner.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/parser/stream.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/py.typed +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/sanitizer/__init__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/sanitizer/css.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/sanitizer/dom.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/sanitizer/policy.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/sanitizer/policy_defaults.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/sanitizer/rawtext.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/sanitizer/url/__init__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/sanitizer/url/policy.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/sanitizer/url/runtime.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/sanitizer/url/spec.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/selector/__init__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/selector/core.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/serializer/__init__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/serializer/html.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/serializer/markdown.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/transforms/__init__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/transforms/compile.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/transforms/linkify.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/transforms/linkify_core.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/src/justhtml/transforms/spec.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/test-summary.txt +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/README.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/__init__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/data/wikipedia.html +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/harness/__init__.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/harness/encoding.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/harness/regressions.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/harness/reporter.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/harness/scaling.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/harness/serializer.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/harness/tree.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-sanitize-tests/cases.json +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/character_preprocessing.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/document_shell_recovery.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/entities.test +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/foreign_content.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/foreign_stack_recovery.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/frameset_recovery.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/head_noscript_recovery.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/iframe_srcdoc.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/in_body_recovery.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/raw_text_recovery.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/select_recovery.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/selectedcontent.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/table_recovery.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/template_recovery.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/tokenizer_recovery.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/tokenizer_state_transitions.test +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/tokenizer_states.test +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/xml_coercion.dat +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/xml_coercion_invalid_characters.test +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/linkify-it/LICENSE.txt +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/linkify-it/README.md +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/linkify-it/fixtures/links.txt +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/linkify-it/fixtures/not_links.txt +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_builder.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_cli.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_docs_examples.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_encoding.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_entities.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_errors.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_linkify_internals.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_linkify_it.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_linkify_transform.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_node.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_parser_regressions.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_parser_tree.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_playground_local_repo_file_list.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_sanitize.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_sanitize_transform.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_selector.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_serialize.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_stream.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_transform_runtime.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_transforms_compiler.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_transforms_sanitize_integration.py +0 -0
- {justhtml-3.11.2 → justhtml-3.11.3}/tests/test_wikipedia.py +0 -0
|
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.11.3] - 2026-09-27
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Apply earlier transforms to allowed children hoisted when sanitization removes a parent (#85).
|
|
15
|
+
- Drop foreign subtrees inside disallowed HTML parents in the default parsing path.
|
|
16
|
+
|
|
10
17
|
## [3.11.2] - 2026-08-27
|
|
11
18
|
|
|
12
19
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: justhtml
|
|
3
|
-
Version: 3.11.
|
|
3
|
+
Version: 3.11.3
|
|
4
4
|
Summary: A pure Python HTML5 parser that just works.
|
|
5
5
|
Project-URL: Homepage, https://github.com/emilstenstrom/justhtml
|
|
6
6
|
Project-URL: Issues, https://github.com/emilstenstrom/justhtml/issues
|
|
@@ -136,6 +136,7 @@ policy = SanitizationPolicy(
|
|
|
136
136
|
allowed_attributes={"a": ["href"]},
|
|
137
137
|
url_policy=UrlPolicy(allow_rules={("a", "href"): UrlRule(allowed_schemes={"https"})}),
|
|
138
138
|
)
|
|
139
|
+
# An example that uses HTTP, so it should NOT be allowed
|
|
139
140
|
text = "See http://example.com"
|
|
140
141
|
|
|
141
142
|
# Wrong: Linkify's generated <a href> is created after the sanitize point,
|
|
@@ -144,10 +145,10 @@ doc = JustHTML(text, transforms=[Sanitize(policy), Linkify()])
|
|
|
144
145
|
print(doc.to_html(pretty=False))
|
|
145
146
|
# => See <a href="http://example.com">http://example.com</a>
|
|
146
147
|
|
|
147
|
-
#
|
|
148
|
+
# Correct: Linkify runs first, so its output is covered by the same sanitize pass.
|
|
148
149
|
doc = JustHTML(text, transforms=[Linkify(), Sanitize(policy)])
|
|
149
150
|
print(doc.to_html(pretty=False))
|
|
150
|
-
# => See http://example.com
|
|
151
|
+
# => See <a>http://example.com</a>
|
|
151
152
|
```
|
|
152
153
|
|
|
153
154
|
If you don't need other transforms between them, the simplest safe option is to omit `Sanitize()` entirely and let `sanitize=True` (the default) append it automatically after `Linkify()`.
|
|
@@ -4212,11 +4212,8 @@ class ParseEngine:
|
|
|
4212
4212
|
self._foreign_context_seen = True
|
|
4213
4213
|
self._nodes_to_unwrap.append(node)
|
|
4214
4214
|
parent_namespace = getattr(parent, "namespace", None)
|
|
4215
|
-
if parent is self._fragment_context_node or parent_namespace in {None, "html"}:
|
|
4216
|
-
|
|
4217
|
-
parent is self._fragment_context_node or parent.name in self._allowed_tags
|
|
4218
|
-
):
|
|
4219
|
-
self._nodes_to_drop.append(node)
|
|
4215
|
+
if parent is self._fragment_context_node or parent_namespace in {None, "html", _PARSER_ONLY_NAMESPACE}:
|
|
4216
|
+
self._nodes_to_drop.append(node)
|
|
4220
4217
|
elif name not in self._allowed_tags:
|
|
4221
4218
|
self._nodes_to_unwrap.append(node)
|
|
4222
4219
|
if not is_void:
|
|
@@ -231,7 +231,6 @@ def apply_compiled_transforms(
|
|
|
231
231
|
|
|
232
232
|
if moved:
|
|
233
233
|
for child in moved:
|
|
234
|
-
_mark_start(child, mark_new_start_index)
|
|
235
234
|
child.parent = parent
|
|
236
235
|
replacement.extend(moved)
|
|
237
236
|
|
|
@@ -294,7 +293,6 @@ def apply_compiled_transforms(
|
|
|
294
293
|
moved_nodes = _detach_children_for_hoist(node, name)
|
|
295
294
|
if moved_nodes:
|
|
296
295
|
for child in moved_nodes:
|
|
297
|
-
_mark_start(child, transform_index)
|
|
298
296
|
child.parent = parent
|
|
299
297
|
children[child_index : child_index + 1] = moved_nodes
|
|
300
298
|
else:
|
|
@@ -865,7 +863,6 @@ def apply_compiled_transforms(
|
|
|
865
863
|
|
|
866
864
|
if moved_nodes_unwrap:
|
|
867
865
|
for child in moved_nodes_unwrap:
|
|
868
|
-
_mark_start(child, idx + 1)
|
|
869
866
|
child.parent = parent
|
|
870
867
|
children[i : i + 1] = moved_nodes_unwrap
|
|
871
868
|
else:
|
|
@@ -1745,7 +1745,7 @@ class TestParserAttributeProjection(_ParserEngineTestCase):
|
|
|
1745
1745
|
)
|
|
1746
1746
|
self.assert_parses_to(
|
|
1747
1747
|
"<tr selected> <svg href=x><table href=x></table><math a=1> </svg>\n</tr></math>\n<blockquote a=1>",
|
|
1748
|
-
"<tbody><tr> </tr></tbody><table></table
|
|
1748
|
+
"<tbody><tr> </tr></tbody><table></table>\n<blockquote></blockquote>",
|
|
1749
1749
|
fragment_context=FragmentContext("table"),
|
|
1750
1750
|
)
|
|
1751
1751
|
self.assert_parses_to(
|
|
@@ -8,6 +8,7 @@ from typing import Any
|
|
|
8
8
|
from justhtml import DEFAULT_POLICY, JustHTML
|
|
9
9
|
from justhtml.parser.context import FragmentContext
|
|
10
10
|
from justhtml.sanitizer import SanitizationPolicy, UrlPolicy, UrlProxy, UrlRule
|
|
11
|
+
from justhtml.transforms import Sanitize
|
|
11
12
|
|
|
12
13
|
_CASES_DIR = Path(__file__).with_name("justhtml-sanitize-tests")
|
|
13
14
|
|
|
@@ -89,6 +90,16 @@ def _build_policy(spec: Any) -> SanitizationPolicy:
|
|
|
89
90
|
|
|
90
91
|
|
|
91
92
|
class TestSanitizeIntegration(unittest.TestCase):
|
|
93
|
+
def test_foreign_subtree_under_disallowed_parent_is_dropped(self) -> None:
|
|
94
|
+
for html in (
|
|
95
|
+
"<table><tr><td><select><math><mi>unsafe</mi><p>safe</table>",
|
|
96
|
+
"<template><svg><foo><template><foreignObject><div></template><div>",
|
|
97
|
+
):
|
|
98
|
+
fused = JustHTML(html).to_html(pretty=False)
|
|
99
|
+
explicit = JustHTML(html, transforms=[Sanitize()]).to_html(pretty=False)
|
|
100
|
+
assert fused == explicit
|
|
101
|
+
assert "unsafe" not in fused
|
|
102
|
+
|
|
92
103
|
def test_sanitize_cases(self) -> None:
|
|
93
104
|
cases_path = _CASES_DIR / "cases.json"
|
|
94
105
|
cases = json.loads(cases_path.read_text(encoding="utf-8"))
|
|
@@ -208,6 +208,29 @@ class TestTransforms(unittest.TestCase):
|
|
|
208
208
|
doc = JustHTML("<p>Hello <span>world</span></p>", transforms=[Unwrap("span")])
|
|
209
209
|
assert doc.to_html(pretty=False) == "<html><head></head><body><p>Hello world</p></body></html>"
|
|
210
210
|
|
|
211
|
+
def test_hoisted_children_receive_earlier_transforms(self) -> None:
|
|
212
|
+
for structural_transform in (Unwrap("p, span"), Escape("p, span")):
|
|
213
|
+
doc = JustHTML(
|
|
214
|
+
"<p><span><a href='https://eff.org'>EFF</a></span></p>",
|
|
215
|
+
fragment=True,
|
|
216
|
+
transforms=[SetAttrs("a", rel="noopener"), structural_transform],
|
|
217
|
+
)
|
|
218
|
+
assert '<a href="https://eff.org" rel="noopener">EFF</a>' in doc.to_html(pretty=False)
|
|
219
|
+
|
|
220
|
+
def test_sanitize_hoisted_children_receive_earlier_transforms(self) -> None:
|
|
221
|
+
policy = SanitizationPolicy(
|
|
222
|
+
allowed_tags={"a"},
|
|
223
|
+
allowed_attributes={"a": {"href", "rel"}},
|
|
224
|
+
url_policy=UrlPolicy(allow_rules={("a", "href"): UrlRule(allowed_schemes={"https"})}),
|
|
225
|
+
)
|
|
226
|
+
doc = _JustHTML(
|
|
227
|
+
'<p><span><a href="https://eff.org">EFF</a></span></p>',
|
|
228
|
+
fragment=True,
|
|
229
|
+
transforms=[SetAttrs("a", rel="noopener")],
|
|
230
|
+
policy=policy,
|
|
231
|
+
)
|
|
232
|
+
assert doc.to_html(pretty=False) == '<a href="https://eff.org" rel="noopener">EFF</a>'
|
|
233
|
+
|
|
211
234
|
def test_unwrap_handles_empty_elements(self) -> None:
|
|
212
235
|
doc = JustHTML("<div><span></span>ok</div>", transforms=[Unwrap("span")])
|
|
213
236
|
assert doc.to_html(pretty=False) == "<html><head></head><body><div>ok</div></body></html>"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{justhtml-3.11.2 → justhtml-3.11.3}/tests/justhtml-tests/xml_coercion_invalid_characters.test
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|