exporters: encoding="utf-8" across text writes; samm/file_helper to context manager - #518
Merged
sschleemilch merged 2 commits intoMay 12, 2026
Conversation
Fourteen exporters (json, tree, yaml, csv, protobuf, plantuml, go, id, franca, ddsidl, stats_utils, apigear, s2dm/__init__, s2dm/reference_generator) opened output files with `open(path, "w")` in text mode without an explicit encoding. On platforms whose default text-file encoding is not UTF-8 (most notably Windows cp1252), writing a VSS spec containing non-ASCII characters — e.g. "°" in unit names, "Ω" in resistance units, accented characters in descriptions — crashes with `UnicodeEncodeError`. Add `encoding="utf-8"` to every text-write open() call so the exporters behave consistently across platforms. Matches the existing correct usage in jsonschema.py. Note: yaml.py also passes `encoding="utf-8"` to `yaml.dump()`, but that argument is silently ignored when the dump target is a text-mode file (it only applies to byte-mode streams). The fix here is to set the encoding on `open()` itself; the yaml.dump kwarg is left in place for clarity but commented to that effect. The CSV exporter retains its `newline=""` argument (correct for cross-platform CSV writing) and gains `encoding="utf-8"` alongside. Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
write_graph_to_file in samm/helpers/file_helper.py manually opened the
output .ttl file with output_file.open("w") and called
file_writer.close() at the bottom of the function. If any of the
.write() calls raised — e.g. a transient I/O error on the second
write("\n") — the file handle would leak. The file was also opened
without an explicit encoding, sharing the cross-platform crash hazard
fixed for the other exporters in the previous commit.
Wrap the writes in a `with` statement and pin encoding to UTF-8.
Same shape as the rest of the exporters now.
Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
sschleemilch
approved these changes
May 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Two related file-handling hardening fixes across the exporters:
1. Missing
encoding="utf-8"on text-writeopen()callsFourteen exporters (
json,tree,yaml,csv,protobuf,plantuml,go,id,franca,ddsidl,stats_utils,apigear,s2dm/__init__,s2dm/reference_generator) opened output fileswith
open(path, "w")in text mode without specifying an encoding.On platforms whose default text-file encoding is not UTF-8 (notably
Windows cp1252), writing a VSS spec containing non-ASCII characters —
e.g.
°in unit names,Ωin resistance units, accented charactersin descriptions — crashes with
UnicodeEncodeError. Same shape onnon-UTF-8 Linux locales.
jsonschema.pyalready does this correctly; everything else didn't.2.
samm/helpers/file_helper.write_graph_to_filenot using a context managerThe function opened the output
.ttlfile withoutput_file.open("w"),wrote to it, then manually called
.close()at the end. If any of theintermediate
.write()calls raised, the file descriptor would leak.It also lacked the encoding fix from #1.
Fix
Two commits, one per problem:
exporters: add encoding="utf-8" to all text-write open() calls— adds
encoding="utf-8"to everyopen(path, "w")(andopen(path, "w", newline="")for CSV) across the 14 exporters.exporters/samm: use context manager and utf-8 encoding in file_helper— wraps the two
.write()calls in awithblock and pins theencoding.
Notes
yaml.pyhad a confusingencoding="utf-8"kwarg passed toyaml.dump(), which is silently ignored when the dump target is atext-mode file (PyYAML only honours that kwarg on byte-mode
streams). Left in place with a comment explaining why; the real
fix is on
open().newline=""argument is preserved (correct forcross-platform CSV writing).
prevents is platform/locale-specific. Happy to add a test if
maintainers can suggest a clean way to simulate non-UTF-8 default
encoding in CI.
Related
Companion to the validation hardening in #515, #516, and #517.