From 1a249e750ab7e30169f79beb35b7503c01d994f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrik=20St=C3=B6ckli?= Date: Wed, 16 Sep 2026 11:17:44 +0200 Subject: [PATCH 1/2] Fix UTF-8 file I/O on IronPython by using codecs.open instead of io.open --- src/util.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/util.py b/src/util.py index f937be4..5b8c164 100644 --- a/src/util.py +++ b/src/util.py @@ -4,6 +4,7 @@ import shutil import sys import traceback +import codecs import scriptengine # type: ignore @@ -90,8 +91,16 @@ def ui_error_with_traceback(message): def open_utf8(path, mode): # ScriptEngine runs on Python 2.7; the builtin open() writes a byte stream and would # implicitly encode unicode text as ascii, crashing on Cyrillic / accented chars / smart - # punctuation. io.open with an explicit encoding keeps everything UTF-8 round-trippable. - return io.open(path, mode, encoding="utf-8") + # punctuation. codecs.open with an excplicit encoding keeps everything UTF-8 round-trippable. + # + # io.open(path, mode, encoding="utf-8") looks equivalent but is unreliable on the + # IronPython 2.7 runtime CODESYS ScriptEngine uses: encoding resolution can silently + # fall back to the OS ANSI code page instead of true UTF-8, which corrupts any + # non ASCII character(umlauts, accented letters, smart punctuation, etc.) on export and + # then fail to decode on the next import ("'unknown' codec can't decode byte ..."). + # codec.open is the long-standing, well-supported way to do UTF-8 text I/O on + # Python 2 / IronPython and does not have this problems. + return codecs.open(path, mode, encoding="utf-8") def print_python_version(): From a534b82a571c154729092cdb63d0a091247b46a7 Mon Sep 17 00:00:00 2001 From: pstoeckli <129617828+pstoeckli@users.noreply.github.com> Date: Wed, 16 Sep 2026 11:23:25 +0200 Subject: [PATCH 2/2] Fix typo in open_utf8 function comment Corrected a typo in the comment regarding codecs.open. --- src/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.py b/src/util.py index 5b8c164..bb2e677 100644 --- a/src/util.py +++ b/src/util.py @@ -91,7 +91,7 @@ def ui_error_with_traceback(message): def open_utf8(path, mode): # ScriptEngine runs on Python 2.7; the builtin open() writes a byte stream and would # implicitly encode unicode text as ascii, crashing on Cyrillic / accented chars / smart - # punctuation. codecs.open with an excplicit encoding keeps everything UTF-8 round-trippable. + # punctuation. codecs.open with an explicit encoding keeps everything UTF-8 round-trippable. # # io.open(path, mode, encoding="utf-8") looks equivalent but is unreliable on the # IronPython 2.7 runtime CODESYS ScriptEngine uses: encoding resolution can silently