justhtml 3.6.1__tar.gz → 3.7.0__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.6.1 → justhtml-3.7.0}/CHANGELOG.md +10 -1
- {justhtml-3.6.1 → justhtml-3.7.0}/PKG-INFO +2 -2
- {justhtml-3.6.1 → justhtml-3.7.0}/benchmarks/correctness.py +1 -1
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/comparison.md +9 -9
- {justhtml-3.6.1 → justhtml-3.7.0}/pyproject.toml +2 -2
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/parser/engine.py +0 -24
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_parser_engine.py +7 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/.github/copilot-instructions.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/.github/workflows/ci.yml +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/.github/workflows/publish.yml +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/.gitignore +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/.pre-commit-config.yaml +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/AGENTS.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/CODE_OF_CONDUCT.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/CONTRIBUTING.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/LICENSE +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/Makefile +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/PERFORMANCE.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/README.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/SECURITY.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/assets/justhtml-readme-explainer.png +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/benchmarks/chromium_parser_diff.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/benchmarks/fuzz.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/benchmarks/html5lib_engine_diff.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/benchmarks/parser_engine_gate.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/benchmarks/performance.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/benchmarks/profile.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/_config.yml +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/_layouts/default.html +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/api.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/assets/search.js +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/bleach-migration.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/building.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/cli.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/correctness.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/encoding.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/errors.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/fragments.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/html-cleaning.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/index.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/linkify.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/migration-examples.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/playground/app.js +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/playground/index.html +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/playground/py/__init__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/playground/py/install_latest_justhtml.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/playground/py/render.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/playground/py/use_local_repo.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/quickstart.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/sanitization.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/selectors.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/streaming.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/text.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/transforms.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/unsafe-handling.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/docs/url-cleaning.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/llms.txt +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/project_ideas.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/run_tests.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/scripts/release.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/__init__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/__main__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/core/__init__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/core/constants.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/core/doctype.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/core/entities.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/core/errors.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/core/rawtext.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/core/text.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/core/types.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/dom/__init__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/dom/builder.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/parser/__init__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/parser/context.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/parser/encoding.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/parser/options.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/parser/scanner.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/parser/stream.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/py.typed +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/sanitizer/__init__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/sanitizer/css.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/sanitizer/dom.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/sanitizer/policy.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/sanitizer/policy_defaults.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/sanitizer/rawtext.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/sanitizer/url/__init__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/sanitizer/url/policy.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/sanitizer/url/runtime.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/sanitizer/url/spec.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/selector/__init__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/selector/core.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/serializer/__init__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/serializer/html.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/serializer/markdown.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/transforms/__init__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/transforms/compile.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/transforms/linkify.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/transforms/linkify_core.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/transforms/runtime.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/src/justhtml/transforms/spec.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/test-summary.txt +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/README.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/__init__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/data/wikipedia.html +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/harness/__init__.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/harness/encoding.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/harness/regressions.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/harness/reporter.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/harness/serializer.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/harness/tree.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-sanitize-tests/cases.json +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/character_preprocessing.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/document_shell_recovery.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/entities.test +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/foreign_content.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/foreign_stack_recovery.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/frameset_recovery.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/head_noscript_recovery.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/iframe_srcdoc.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/in_body_recovery.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/raw_text_recovery.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/select_recovery.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/selectedcontent.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/table_recovery.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/template_recovery.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/tokenizer_recovery.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/tokenizer_state_transitions.test +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/tokenizer_states.test +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/xml_coercion.dat +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/justhtml-tests/xml_coercion_invalid_characters.test +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/linkify-it/LICENSE.txt +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/linkify-it/README.md +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/linkify-it/fixtures/links.txt +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/linkify-it/fixtures/not_links.txt +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_builder.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_cli.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_docs_examples.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_encoding.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_entities.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_errors.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_linkify_internals.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_linkify_it.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_linkify_transform.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_node.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_parser_regressions.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_parser_tree.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_playground_local_repo_file_list.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_sanitize.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_sanitize_integration.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_sanitize_transform.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_selector.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_serialize.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_stream.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_transform_runtime.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_transforms.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_transforms_compiler.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_transforms_sanitize_integration.py +0 -0
- {justhtml-3.6.1 → justhtml-3.7.0}/tests/test_wikipedia.py +0 -0
|
@@ -5,7 +5,16 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [3.7.0] - 2026-07-15
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Keep templates open in the head when they contain a processing instruction, matching the latest web-platform-tests tree-construction fixture.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Refresh the web-platform-tests tree-construction fixtures and comparison scores.
|
|
17
|
+
- Make the correctness benchmark skip an optional `html5-parser` installation when its libxml2 ABI conflicts with `lxml`.
|
|
9
18
|
|
|
10
19
|
## [3.6.1] - 2026-07-13
|
|
11
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: justhtml
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.7.0
|
|
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
|
|
@@ -40,7 +40,7 @@ Requires-Dist: html5-parser; extra == 'benchmark'
|
|
|
40
40
|
Requires-Dist: html5lib; extra == 'benchmark'
|
|
41
41
|
Requires-Dist: lxml; extra == 'benchmark'
|
|
42
42
|
Requires-Dist: markupever; extra == 'benchmark'
|
|
43
|
-
Requires-Dist: selectolax>=0.4.
|
|
43
|
+
Requires-Dist: selectolax>=0.4.11; extra == 'benchmark'
|
|
44
44
|
Requires-Dist: turbohtml>=1.3.1; extra == 'benchmark'
|
|
45
45
|
Requires-Dist: zstandard; extra == 'benchmark'
|
|
46
46
|
Provides-Extra: dev
|
|
@@ -11,22 +11,22 @@ Use a different tool when one narrow requirement matters more than the whole pip
|
|
|
11
11
|
| Tool | HTML5 parsing [1] | Speed | Query | Build | Sanitize | Notes |
|
|
12
12
|
|------|------------------------------------------|-------|----------|-------|------------------|-------|
|
|
13
13
|
| **JustHTML**<br>Pure Python | ✅ 100% | ⚡ Fast | ✅ CSS selectors | ✅ `element()` | ✅ Built-in | Correct, secure, easy to install, and fast enough. |
|
|
14
|
-
| **`selectolax`**<br>Python wrapper of C-based Lexbor |
|
|
15
|
-
| **Chromium**<br>browser engine | 🟡 95.
|
|
16
|
-
| **`turbohtml`**<br>Python wrapper of a C core | 🟡 94.
|
|
17
|
-
| **WebKit**<br>browser engine | 🟡
|
|
18
|
-
| **Firefox**<br>browser engine | 🟡 93.
|
|
14
|
+
| **`selectolax`**<br>Python wrapper of C-based Lexbor | ✅ 100% | 🚀 Very Fast | ✅ CSS selectors | ✅ `create_node()` | ❌ Needs sanitization | Very fast. |
|
|
15
|
+
| **Chromium**<br>browser engine | 🟡 95.0% [2] | 🚀 Very Fast | — | — | — | Current browser-harness result. |
|
|
16
|
+
| **`turbohtml`**<br>Python wrapper of a C core | 🟡 94.2% | 🚀 Very Fast | ✅ CSS selectors, XPath | ✅ `E.*` builder | ✅ Built-in | Broad, compiled alternative with parsing, querying, and sanitization. |
|
|
17
|
+
| **WebKit**<br>browser engine | 🟡 93.9% [2] | 🚀 Very Fast | — | — | — | Current browser-harness result. |
|
|
18
|
+
| **Firefox**<br>browser engine | 🟡 93.1% [2] | 🚀 Very Fast | — | — | — | Current browser-harness result. |
|
|
19
19
|
| **`html5lib`**<br>Pure Python | 🟡 82.3% | 🐢 Slow | 🟡 XPath (lxml) | 🟡 Tree API | 🔴 [Deprecated](https://github.com/html5lib/html5lib-python/issues/443) | Unmaintained reference implementation; incomplete coverage of the tree-construction fixtures. |
|
|
20
|
-
| **`markupever`**<br>Python wrapper of Rust-based html5ever | 🟡 79.4% | 🚀 Very Fast | ✅ CSS selectors | ✅ `TreeDom .create_*()` | ❌ Needs sanitization | Fast, but
|
|
20
|
+
| **`markupever`**<br>Python wrapper of Rust-based html5ever | 🟡 79.4% | 🚀 Very Fast | ✅ CSS selectors | ✅ `TreeDom .create_*()` | ❌ Needs sanitization | Fast, but many fixtures cases abort its current parser process. |
|
|
21
21
|
| **`html5_parser`**<br>Python wrapper of C-based Gumbo | 🔴 47.8% | 🚀 Very Fast | 🟡 XPath (lxml) | 🟡 `etree` (lxml) | ❌ Needs sanitization | Fast, but its public tree API loses information needed by many fixtures. |
|
|
22
22
|
| **`BeautifulSoup`**<br>Pure Python | 🔴 0.3% (default) | 🐢 Slow | 🟡 Custom API | ✅ `new_tag()` API | ❌ Needs sanitization | Wraps `html.parser` (default). Can use lxml or html5lib. |
|
|
23
23
|
| **`html.parser`**<br>Python stdlib | 🔴 0.3% | ⚡ Fast | ❌ None | ❌ None | ❌ Needs sanitization | Standard library. Chokes on malformed HTML. |
|
|
24
|
-
| **`lxml`**<br>Python wrapper of C-based libxml2 | 🔴 0.
|
|
24
|
+
| **`lxml`**<br>Python wrapper of C-based libxml2 | 🔴 0.9% | 🚀 Very Fast | 🟡 XPath | ✅ `etree` / E-factory | ❌ Needs sanitization | Fast but not HTML5 compliant. Context-fragment cases are skipped; supported cases still perform poorly. Don't use the old lxml.html.clean module! |
|
|
25
25
|
|
|
26
|
-
[1]:
|
|
26
|
+
[1]: Library correctness scores are counted against the [web-platform-tests tree-construction tests](https://github.com/web-platform-tests/wpt/tree/master/html/syntax/parsing/resources). They were run locally at [2026-07-15](https://github.com/web-platform-tests/wpt/commit/4830edb033cb486fd0cd6f85b5e937cfc718704d) and cover 1,880 cases after excluding scripting-directed fixtures. JustHTML and Selectolax 0.4.11 passed all 1,880 cases; MarkupEver's score counts its 103 process-aborting cases as errors.
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
[2]: Current local rerun with [`justhtml-html5lib-tests-bench`](https://github.com/EmilStenstrom/justhtml-html5lib-tests-bench) against WPT commit [`
|
|
29
|
+
[2]: Current local rerun with [`justhtml-html5lib-tests-bench`](https://github.com/EmilStenstrom/justhtml-html5lib-tests-bench) against WPT commit [`4830edb`](https://github.com/web-platform-tests/wpt/commit/4830edb033cb486fd0cd6f85b5e937cfc718704d). Chromium 143.0.7499.4, WebKit 26.0, and Firefox 144.0.2 were compared against 1,908 cases; the harness skips 12 `#script-on` cases but includes `#script-off` cases, so these scores are not directly comparable to the 1,880-case Python-parser scores above.
|
|
30
30
|
|
|
31
31
|
## Why JustHTML
|
|
32
32
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "justhtml"
|
|
3
3
|
authors = [{ name = "Emil Stenström", email = "emil@emilstenstrom.se" }]
|
|
4
|
-
version = "3.
|
|
4
|
+
version = "3.7.0"
|
|
5
5
|
description = "A pure Python HTML5 parser that just works."
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
license = { file = "LICENSE" }
|
|
@@ -18,7 +18,7 @@ benchmark = [
|
|
|
18
18
|
"html5lib",
|
|
19
19
|
"lxml",
|
|
20
20
|
"beautifulsoup4",
|
|
21
|
-
"selectolax>=0.4.
|
|
21
|
+
"selectolax>=0.4.11",
|
|
22
22
|
"html5-parser",
|
|
23
23
|
"markupever",
|
|
24
24
|
"turbohtml>=1.3.1",
|
|
@@ -1253,32 +1253,8 @@ class ParseEngine:
|
|
|
1253
1253
|
if self._has_null and "\0" in data:
|
|
1254
1254
|
data = data.replace("\0", "\ufffd")
|
|
1255
1255
|
node = ProcessingInstruction(data=data)
|
|
1256
|
-
self._move_head_template_to_body_for_processing_instruction()
|
|
1257
1256
|
self._append_misc_node(node, source_pos)
|
|
1258
1257
|
|
|
1259
|
-
def _move_head_template_to_body_for_processing_instruction(self) -> None:
|
|
1260
|
-
if self._fragment or self._head is None or self._html is None:
|
|
1261
|
-
return
|
|
1262
|
-
stack = self._stack
|
|
1263
|
-
template_idx = self._open_template_index()
|
|
1264
|
-
if template_idx is None:
|
|
1265
|
-
return
|
|
1266
|
-
outer_template_idx = template_idx
|
|
1267
|
-
for idx in range(template_idx, 0, -1):
|
|
1268
|
-
candidate = stack[idx]
|
|
1269
|
-
if type(candidate) is Template and candidate.parent is self._head:
|
|
1270
|
-
outer_template_idx = idx
|
|
1271
|
-
template = stack[outer_template_idx]
|
|
1272
|
-
if type(template) is not Template or template.parent is not self._head:
|
|
1273
|
-
return
|
|
1274
|
-
head_children = self._head.children
|
|
1275
|
-
if head_children is not None: # pragma: no branch - Document head always owns a children list
|
|
1276
|
-
head_children.remove(template)
|
|
1277
|
-
self._append(self._body, template)
|
|
1278
|
-
self._stack = _CountingStack([self._doc, self._html, self._body, *stack[outer_template_idx:]]) # type: ignore[list-item]
|
|
1279
|
-
self._body_mode_seen = True
|
|
1280
|
-
self._after_head = False
|
|
1281
|
-
|
|
1282
1258
|
def _processing_instruction_data(self, content_start: int, content_end: int) -> str | None:
|
|
1283
1259
|
html = self._html_input
|
|
1284
1260
|
if content_start >= content_end or not _is_processing_instruction_name_start(html[content_start]):
|
|
@@ -14,6 +14,7 @@ from justhtml.parser.engine import (
|
|
|
14
14
|
)
|
|
15
15
|
from justhtml.parser.options import ParserOptions
|
|
16
16
|
from justhtml.sanitizer import DEFAULT_DOCUMENT_POLICY, DEFAULT_POLICY, SanitizationPolicy, UrlPolicy, UrlRule
|
|
17
|
+
from justhtml.serializer import to_test_format
|
|
17
18
|
from tests.harness.tree import TestRunner
|
|
18
19
|
|
|
19
20
|
|
|
@@ -48,6 +49,12 @@ class TestParserSyntaxAndRecovery(_ParserEngineTestCase):
|
|
|
48
49
|
document = JustHTML("<?\ud83d\ude80\ud83dX\ud83d\ude80>", sanitize=False)
|
|
49
50
|
assert document.root.children[0].data == "?🚀\ud83dX🚀"
|
|
50
51
|
|
|
52
|
+
def test_processing_instruction_keeps_open_head_template_in_head(self) -> None:
|
|
53
|
+
document = JustHTML("<template><?pi>", sanitize=False)
|
|
54
|
+
assert to_test_format(document.root) == (
|
|
55
|
+
"| <html>\n| <head>\n| <template>\n| content\n| <?pi ?>\n| <body>"
|
|
56
|
+
)
|
|
57
|
+
|
|
51
58
|
def test_rawtext_processing_instruction_branch(self) -> None:
|
|
52
59
|
script = Element("script", {}, "html")
|
|
53
60
|
engine = ParseEngine("<?x>", fragment=True, plan=compile_raw_engine_plan(fragment=True))
|
|
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
|
|
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
|