else:
parser.set_defaults(css_file=None)
+ parser.add_argument(
+ "--related-to-html-only",
+ action="store_true",
+ help="Make related content be sibling to HTML parts only"
+ )
+
parser.add_argument(
"--only-build",
action="store_true",
draftpath,
*,
cssfile=None,
+ related_to_html_only=True,
filewriter_fn=filewriter_fn,
tempdir=None,
extensions=None,
)
htmlpart = Part("text", "html", htmlpath, "HTML version")
- altpart = Multipart(
- "alternative", [textpart, htmlpart], "Group of alternative content"
- )
-
imgparts = collect_inline_images(
images, tempdir=tempdir, filewriter_fn=filewriter_fn
)
- if imgparts:
+
+ if related_to_html_only:
+ # If there are inline image part, they will be contained within a
+ # multipart/related part along with the HTML part only
+ if imgparts:
+ # replace htmlpart with a multipart/related container of the HTML
+ # parts and the images
+ htmlpart = Multipart(
+ "relative", [htmlpart] + imgparts, "Group of related content"
+ )
+
return Multipart(
- "relative", [altpart] + imgparts, "Group of related content"
+ "alternative", [textpart, htmlpart], "Group of alternative content"
)
+
else:
- return altpart
+ # If there are inline image part, they will be siblings to the
+ # multipart/alternative tree within a multipart/related part
+ altpart = Multipart(
+ "alternative", [textpart, htmlpart], "Group of alternative content"
+ )
+ if imgparts:
+ return Multipart(
+ "relative", [altpart] + imgparts, "Group of related content"
+ )
+ else:
+ return altpart
class MIMETreeDFWalker:
extensions=None,
cssfile=None,
converter=convert_markdown_to_html,
+ related_to_html_only=True,
only_build=False,
tempdir=None,
debug_commands=False,
draft_f.read(),
draftpath,
cssfile=cssfile,
+ related_to_html_only=related_to_html_only,
tempdir=tempdir,
extensions=extensions,
)
cmd_f,
extensions=args.extensions,
cssfile=args.css_file,
+ related_to_html_only=args.related_to_html_only,
only_build=args.only_build,
tempdir=args.tempdir,
debug_commands=args.debug_commands,
assert lines[5] in lines_out[7]
@pytest.fixture
- def basic_mime_tree(self):
+ def mime_tree_related_to_alternative(self):
return Multipart(
"relative",
children=[
desc="Related",
)
- def test_MIMETreeDFWalker_depth_first_walk(self, basic_mime_tree):
+ @pytest.fixture
+ def mime_tree_related_to_html(self):
+ return Multipart(
+ "alternative",
+ children=[
+ Part(
+ "text",
+ "plain",
+ "part.txt",
+ desc="Plain",
+ orig=True,
+ ),
+ Multipart(
+ "relative",
+ children=[
+ Part("text", "html", "part.html", desc="HTML"),
+ Part(
+ "text",
+ "png",
+ "logo.png",
+ cid="logo.png",
+ desc="Logo",
+ ),
+ ],
+ desc="Related",
+ ),
+ ],
+ desc="Alternative",
+ )
+
+ def test_MIMETreeDFWalker_depth_first_walk(
+ self, mime_tree_related_to_alternative
+ ):
mimetree = MIMETreeDFWalker()
items = []
- def visitor_fn(item, stack, debugprint):
- items.append((item, len(stack)))
+ def visitor_fn(item, ancestry, debugprint):
+ items.append((item, len(ancestry)))
- mimetree.walk(basic_mime_tree, visitor_fn=visitor_fn)
+ mimetree.walk(
+ mime_tree_related_to_alternative, visitor_fn=visitor_fn
+ )
assert len(items) == 5
assert items[0][0].subtype == "plain"
assert items[0][1] == 2
assert items[-1].subtype == "mixed"
def test_MIMETreeDFWalker_visitor_in_constructor(
- self, basic_mime_tree
+ self, mime_tree_related_to_alternative
):
items = []
items.append(item)
mimetree = MIMETreeDFWalker(visitor_fn=visitor_fn)
- mimetree.walk(basic_mime_tree)
+ mimetree.walk(mime_tree_related_to_alternative)
assert len(items) == 5
@pytest.fixture
return StringIO(text or const1)
def test_do_massage_basic(self, const1, string_io, capsys):
- def converter(drafttext, draftpath, cssfile, extensions, tempdir):
+ def converter(
+ drafttext,
+ draftpath,
+ cssfile,
+ related_to_html_only,
+ extensions,
+ tempdir,
+ ):
return Part("text", "plain", draftpath, orig=True)
do_massage(
assert "unset my_edit_headers" == lines.pop(0)
assert "send-message" in lines.pop(0)
assert "update-encoding" in lines.pop(0)
+ assert "first-entry" in lines.pop(0)
assert "source 'rm -f " in lines.pop(0)
assert "unset my_mdwn_postprocess_cmd_file" == lines.pop(0)
def test_do_massage_fulltree(
- self, string_io, const1, basic_mime_tree, capsys
+ self, string_io, const1, mime_tree_related_to_alternative, capsys
):
- def converter(drafttext, draftpath, cssfile, extensions, tempdir):
- return basic_mime_tree
+ def converter(
+ drafttext,
+ draftpath,
+ cssfile,
+ related_to_html_only,
+ extensions,
+ tempdir,
+ ):
+ return mime_tree_related_to_alternative
do_massage(
draft_f=string_io,
)
captured = capsys.readouterr()
- lines = captured.out.splitlines()[4:]
- assert "send-message" in lines.pop(0)
- assert "Related" in lines.pop(0)
- assert "group-related" in lines.pop(0)
- assert "tag-entry" in lines.pop(0)
- assert "Logo" in lines.pop(0)
- assert "content-id" in lines.pop(0)
- assert "toggle-unlink" in lines.pop(0)
- assert "logo.png" in lines.pop(0)
- assert "tag-entry" in lines.pop(0)
- assert "Alternative" in lines.pop(0)
- assert "group-alternatives" in lines.pop(0)
- assert "tag-entry" in lines.pop(0)
- assert "HTML" in lines.pop(0)
- assert "toggle-unlink" in lines.pop(0)
- assert "part.html" in lines.pop(0)
- assert "tag-entry" in lines.pop(0)
- assert "Plain" in lines.pop(0)
- assert "update-encoding" in lines.pop(0)
- assert len(lines) == 2
+ lines = captured.out.splitlines()[4:-2]
+ assert "first-entry" in lines.pop()
+ assert "update-encoding" in lines.pop()
+ assert "Plain" in lines.pop()
+ assert "part.html" in lines.pop()
+ assert "toggle-unlink" in lines.pop()
+ assert "HTML" in lines.pop()
+ assert "jump>1" in lines.pop()
+ assert "jump>2" in lines.pop()
+ assert "group-alternatives" in lines.pop()
+ assert "Alternative" in lines.pop()
+ assert "logo.png" in lines.pop()
+ assert "toggle-unlink" in lines.pop()
+ assert "content-id" in lines.pop()
+ assert "Logo" in lines.pop()
+ assert "jump>1" in lines.pop()
+ assert "jump>4" in lines.pop()
+ assert "group-related" in lines.pop()
+ assert "Related" in lines.pop()
+ assert "send-message" in lines.pop()
+ assert len(lines) == 0
@pytest.fixture
def fake_filewriter(self):
def markdown_non_converter(self, const1, const2):
return lambda s, text: f"{const1}{text}{const2}"
- def test_converter_tree_basic(
- self, const1, const2, fake_filewriter, markdown_non_converter
- ):
+ def test_converter_tree_basic(self, const1, const2, fake_filewriter):
path = pathlib.Path(const2)
tree = convert_markdown_to_html(
const1, path, filewriter_fn=fake_filewriter
text = f"![inline base64 image]({test_png})"
path = pathlib.Path(const1)
tree = convert_markdown_to_html(
- text, path, filewriter_fn=fake_filewriter
+ text,
+ path,
+ filewriter_fn=fake_filewriter,
+ related_to_html_only=False,
)
-
assert tree.subtype == "relative"
+ assert tree.children[0].subtype == "alternative"
assert tree.children[1].subtype == "png"
written = fake_filewriter.pop()
assert tree.children[1].path == written[0]
assert written[1] == request.urlopen(test_png).read()
+ def test_converter_tree_inline_image_base64_related_to_html(
+ self, test_png, const1, fake_filewriter
+ ):
+ text = f"![inline base64 image]({test_png})"
+ path = pathlib.Path(const1)
+ tree = convert_markdown_to_html(
+ text,
+ path,
+ filewriter_fn=fake_filewriter,
+ related_to_html_only=True,
+ )
+ assert tree.subtype == "alternative"
+ assert tree.children[1].subtype == "relative"
+ assert tree.children[1].children[1].subtype == "png"
+ written = fake_filewriter.pop()
+ assert tree.children[1].children[1].path == written[0]
+ assert written[1] == request.urlopen(test_png).read()
+
def test_converter_tree_inline_image_cid(
self, const1, fake_filewriter
):
out = apply_styling(html, _PYGMENTS_CSS)
assert f'{_CODEHILITE_CLASS}" style="' in out
+ def test_mime_tree_relative_within_alternative(
+ self, string_io, const1, capsys, mime_tree_related_to_html
+ ):
+ def converter(
+ drafttext,
+ draftpath,
+ cssfile,
+ related_to_html_only,
+ extensions,
+ tempdir,
+ ):
+ return mime_tree_related_to_html
+
+ do_massage(
+ draft_f=string_io,
+ draftpath=const1,
+ cmd_f=sys.stdout,
+ converter=converter,
+ )
+
+ captured = capsys.readouterr()
+ lines = captured.out.splitlines()[4:-2]
+ assert "first-entry" in lines.pop()
+ assert "update-encoding" in lines.pop()
+ assert "Plain" in lines.pop()
+ assert "part.html" in lines.pop()
+ assert "toggle-unlink" in lines.pop()
+ assert "HTML" in lines.pop()
+ assert "logo.png" in lines.pop()
+ assert "toggle-unlink" in lines.pop()
+ assert "content-id" in lines.pop()
+ assert "Logo" in lines.pop()
+ assert "jump>2" in lines.pop()
+ assert "jump>3" in lines.pop()
+ assert "group-related" in lines.pop()
+ assert "Related" in lines.pop()
+ assert "jump>1" in lines.pop()
+ assert "jump>2" in lines.pop()
+ assert "group-alternative" in lines.pop()
+ assert "Alternative" in lines.pop()
+ assert "send-message" in lines.pop()
+ assert len(lines) == 0
except ImportError:
pass