-
Notifications
You must be signed in to change notification settings - Fork 0
staging: MHTML support (mirror of upstream #149) #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8b83460
b20d2d9
8dfa216
341be1b
50b9629
9920d30
df61b31
076e77d
fbe5339
c21198b
0c4c81c
adaf984
529aaa2
2bca8ee
ff5820f
6372cf0
bbff29a
fe53a0a
b6c0889
5bd85ba
6c78e2c
ab653fb
6c70669
75cc2d2
c6b7bb1
32c6474
ee58d6a
ce79482
ee4aefd
c1c854c
108180e
da61872
bfebd99
b50bc1b
b67f51e
274f465
de11157
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import test from 'node:test' | ||
| import assert from 'node:assert/strict' | ||
| import { formatFromBytes, formatFromExtension, toMarkdownBytes } from './index.js' | ||
|
|
||
| test('standalone HTML is exposed through the Node binding', async () => { | ||
| const input = Buffer.from('<!doctype html><h1>Hello</h1><p><b>world</b></p>') | ||
| assert.equal(formatFromExtension('html'), 'html') | ||
| assert.equal(formatFromBytes(input), 'html') | ||
| assert.equal(await toMarkdownBytes(input), '# Hello\n\n**world**\n') | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import test from 'node:test' | ||
| import assert from 'node:assert/strict' | ||
| import { formatFromBytes, formatFromExtension, toMarkdownBytes } from './index.js' | ||
|
|
||
| const input = Buffer.from( | ||
| 'Snapshot-Content-Location: https://example.test/page\r\n' + | ||
| 'MIME-Version: 1.0\r\n' + | ||
| 'Content-Type: multipart/related; type="text/html"; boundary="b"\r\n\r\n' + | ||
| '--b\r\nContent-Type: text/html\r\n\r\n' + | ||
| '<!doctype html><h1>Hello MHTML</h1>\r\n--b--\r\n' | ||
| ) | ||
|
|
||
| test('MHTML is exposed through the Node binding', async () => { | ||
| assert.equal(formatFromExtension('mhtml'), 'mhtml') | ||
| assert.equal(formatFromExtension('mht'), 'mhtml') | ||
| assert.equal(formatFromBytes(input), 'mhtml') | ||
| assert.equal(await toMarkdownBytes(input), '# Hello MHTML\n') | ||
| }) |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -4,7 +4,7 @@ import os | |||||
| from typing import Literal, final | ||||||
|
|
||||||
| Format = Literal[ | ||||||
| "doc", "docx", "odt", "pdf", "ppt", "pptx", "rtf", "epub", "xlsx", "ods", "odp", "csv" | ||||||
| "doc", "docx", "odt", "pdf", "ppt", "pptx", "rtf", "epub", "html", "mhtml", "xlsx", "ods", "odp", "csv" | ||||||
| ] | ||||||
|
|
||||||
| class ConvertError(Exception): | ||||||
|
|
@@ -50,10 +50,10 @@ class MissingPartError(ConvertError): | |||||
|
|
||||||
| def format_from_bytes(data: bytes | bytearray) -> Format | None: | ||||||
| """Detect the format from the content itself: the signature and identity | ||||||
| each container specification designates (PDF header, RTF open group, OLE | ||||||
| stream names, ZIP package mimetype/content types). Plain-text formats | ||||||
| (CSV) carry no signature and return `None`; so does anything | ||||||
| unrecognized.""" | ||||||
| each container specification designates (PDF header, RTF open group, MIME | ||||||
| HTML aggregate, OLE stream names, ZIP package mimetype/content types). | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P3: The new detection documentation omits standalone HTML detection even though Prompt for AI agents
Suggested change
|
||||||
| Plain-text formats (CSV) carry no signature and return `None`; so does | ||||||
| anything unrecognized.""" | ||||||
|
|
||||||
| def format_from_extension(extension: str) -> Format | None: | ||||||
| """The format an extension names, with or without a leading dot.""" | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import unittest | ||
|
|
||
| import anydoc | ||
|
|
||
|
|
||
| class HtmlBindingTests(unittest.TestCase): | ||
| def test_standalone_html_is_exposed(self): | ||
| data = b'<!doctype html><h1>Hello</h1><p><b>world</b></p>' | ||
| self.assertEqual(anydoc.format_from_extension('html'), 'html') | ||
| self.assertEqual(anydoc.format_from_bytes(data), 'html') | ||
| self.assertEqual(anydoc.to_markdown_bytes(data), '# Hello\n\n**world**\n') | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import unittest | ||
| import anydoc | ||
|
|
||
| INPUT = ( | ||
| b'Snapshot-Content-Location: https://example.test/page\r\n' | ||
| b'MIME-Version: 1.0\r\n' | ||
| b'Content-Type: multipart/related; type="text/html"; boundary="b"\r\n\r\n' | ||
| b'--b\r\nContent-Type: text/html\r\n\r\n' | ||
| b'<!doctype html><h1>Hello MHTML</h1>\r\n--b--\r\n' | ||
| ) | ||
|
|
||
|
|
||
| class MhtmlTests(unittest.TestCase): | ||
| def test_mhtml_binding(self): | ||
| self.assertEqual(anydoc.format_from_extension('mhtml'), 'mhtml') | ||
| self.assertEqual(anydoc.format_from_extension('mht'), 'mhtml') | ||
| self.assertEqual(anydoc.format_from_bytes(INPUT), 'mhtml') | ||
| self.assertEqual(anydoc.to_markdown_bytes(INPUT), '# Hello MHTML\n') | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: This binding test only exercises the happy path (detection + conversion) and none of the MHTML-specific behavior this PR adds: the base64-reserve / quoted-printable bounds / nesting-depth / media-type-guard resource limits, Content-ID/Content-Location/base-href resolution, or the MHTML-over-HTML detection preference. A regression in error propagation through the binding (e.g. Prompt for AI agents |
||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Type checkers still reject
"html"and"mhtml"when callers use the publicanydoc.to_markdown_bytesoranydoc.to_documentAPIs. Add both literals topython/anydoc/__init__.py's publicFormatalias as well.Prompt for AI agents