Skip to content

Commit e4f485e

Browse files
Address PR #10 review feedback: data URIs, errors, source_path auto-fill
Five gemini-code-assist comments on #10: * Data URI leading-space stripped in three places (svgembed.py data_URI_base64 and embed_svg_images, plus Harness._render's PNG b64 inline). The prior ``data:image/png;base64, <b64>`` form had a stray space after the comma which violates RFC 2397; most browsers tolerate it but stricter parsers (some PDF/EPUB tooling, lint tools) reject it. All three call sites now emit the canonical ``data:image/png;base64,<b64>``. * wv_cli.py: ``raise Exception("Unknown output format: ...")`` → ``raise click.UsageError(...)``. Matches the multi-format-stdout check elsewhere in the file and gives users the clean ``Try 'wireviz -h' for help.\nError: ...`` UX instead of a Python traceback. * wv_cli.py: stdin mode now defaults ``image_paths`` to ``{Path.cwd()}`` instead of an empty set, so relative ``image: src:`` references in piped YAML resolve against the invocation directory the same way file-based input resolves against the YAML's parent. * Harness._extend_tweak: tweak override conflict error now reports both the existing and new values (``"X1.tweak.override.X1.color: new value 'blue' conflicts with existing 'red'"``) instead of the prior vague ``"conflicts with another"``. * wireviz.parse(): ``source_path`` now auto-fills from ``yaml_file`` when the input was a Path. The docstring already promised this behavior; the code didn't actually do it. Confirmed via ``parse(Path('examples/demo01.yml'), output_formats=('svg',), ...)`` succeeding without explicit source_path. Verified against build_examples.py: deterministic outputs (.gv, .bom.tsv) byte-identical to baseline. Tweak conflict YAML correctly raises the new error. Bad CLI format flag now renders Click's UsageError formatting. Data URIs in re-rendered ex08.svg / .html now emit ``data:image/png;base64,iVB...`` (no space). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c66441e commit e4f485e

4 files changed

Lines changed: 15 additions & 6 deletions

File tree

src/wireviz/Harness.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ def _extend_tweak(self, node: Union[Connector, Cable]) -> None:
172172
k, v = rph(k), rph(v)
173173
if k in s_dict and v != s_dict[k]:
174174
raise ValueError(
175-
f"{node.name}.tweak.override.{ident}.{k} conflicts with another"
175+
f"{node.name}.tweak.override.{ident}.{k}: new value "
176+
f"{v!r} conflicts with existing {s_dict[k]!r}"
176177
)
177178
s_dict[k] = v
178179
# Keep the empty dict rather than collapsing to None — the
@@ -935,7 +936,7 @@ def _render(
935936
# rendered in this same call; otherwise let the template
936937
# fall back to reading {output_dir}/{output_name}.png.
937938
png_b64 = (
938-
f"data:image/png;base64, {base64.b64encode(png_bytes).decode('utf-8')}"
939+
f"data:image/png;base64,{base64.b64encode(png_bytes).decode('utf-8')}"
939940
if png_bytes is not None
940941
else None
941942
)

src/wireviz/svgembed.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def data_URI_base64(file: Union[str, Path], media: str = "image") -> str:
1313
"""Return Base64-encoded data URI of input file."""
1414
file = Path(file)
1515
b64 = base64.b64encode(file.read_bytes()).decode("utf-8")
16-
uri = f"data:{media}/{get_mime_subtype(file)};base64, {b64}"
16+
uri = f"data:{media}/{get_mime_subtype(file)};base64,{b64}"
1717
# print(f"data_URI_base64('{file}', '{media}') -> {len(uri)}-character URI")
1818
if len(uri) > 65535:
1919
print(
@@ -36,7 +36,7 @@ def replace(match: re.Match) -> str:
3636
images_b64[imgurl] = base64.b64encode(image).decode("utf-8")
3737
return image_tag(
3838
match["PRE"] or "",
39-
f"data:image/{get_mime_subtype(imgurl)};base64, {images_b64[imgurl]}",
39+
f"data:image/{get_mime_subtype(imgurl)};base64,{images_b64[imgurl]}",
4040
match["POST"] or "",
4141
)
4242

src/wireviz/wireviz.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ def parse(
112112
raise TypeError(
113113
f"Expected a dict as top-level YAML input, but got: {type(yaml_data)}"
114114
)
115+
# When inp was a Path, derive source_path automatically so callers
116+
# don't have to pass it twice. Matches the docstring contract.
117+
if source_path is None and yaml_file is not None:
118+
source_path = yaml_file
115119
write_to_stdout = (
116120
output_formats and (str(output_dir) == "-" or str(output_name) == "-")
117121
)

src/wireviz/wv_cli.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def wireviz(
116116
if fmt not in output_formats:
117117
output_formats.append(fmt)
118118
else:
119-
raise Exception(f"Unknown output format: {code}")
119+
raise click.UsageError(f"Unknown output format: {code}")
120120
output_formats = tuple(output_formats)
121121
output_formats_str = (
122122
f'[{"|".join(output_formats)}]'
@@ -150,7 +150,11 @@ def wireviz(
150150
for file in filepaths:
151151
if str(file) == "-":
152152
yaml_input = prepend_input + sys.stdin.read()
153-
image_paths = set()
153+
# No source-file directory available, so any relative
154+
# `image: src:` paths in the stdin YAML are resolved against
155+
# the current working directory (matching how a typical
156+
# piped invocation would be run from a project root).
157+
image_paths = {Path.cwd()}
154158
sys.stderr.write("Input: <stdin>\n")
155159
_output_dir = output_dir if output_dir else "-"
156160
_output_name = output_name if output_name else "stdin"

0 commit comments

Comments
 (0)