Ui file encoding issue: PyQt5.uic.compileUiDir() uses local default text encoding for all UI files, instead of utf-8 (PyQt5 5.15.7)

Thomas Hess thomas.hess at udo.edu
Wed Oct 19 20:17:17 BST 2022


Hello list,

I think I found a file-encoding related bug in PyQt5.uic.compileUiDir():

It internally open()s the input UI file and output Python file without 
specifying the encoding, thus using the system-default encoding for text files.

For my Windows VMs, the default encoding is cp1252. Compiling my UI files 
causes a UnicodeDecodeError on utf-8 encoded UI files that contain characters 
invalid in said default encoding, which crashes the ui compilation step.

Additionally, the generated file header explicitly mentions that the output is 
using utf-8, which is currently simply not true, because compileUiDir() 
doesn’t always write using utf-8.

I propose this patch (released as Public Domain) to solve both points (which 
is also attached):


--- a/PyQt5/uic/__init__.py
+++ b/PyQt5/uic/__init__.py
@@ -111,13 +111,11 @@ def compileUiDir(dir, recurse=False, map=None, 
**compileUi_args):
             ui_path = os.path.join(ui_dir, ui_file)
             py_path = os.path.join(py_dir, py_file)
 
-            ui_file = open(ui_path, 'r')
-            py_file = open(py_path, 'w')
+            py_file = open(py_path, 'w',  encoding='utf-8')
 
             try:
-                compileUi(ui_file, py_file, **compileUi_args)
+                compileUi(ui_path, py_file, **compileUi_args)
             finally:
-                ui_file.close()
                 py_file.close()
 
For the output side, the patched code explicitly specifies utf-8 as the output 
encoding, according to the header defined starting with line 46.

The input encoding issue is solved by not opening the UI file here at all, 
instead passing the file path to compileUi(), which can handle file paths 
according to the docstring. The compileUi-internal file handling logic then 
handles the utf-8 input files properly.

The attached UI file contains a minimal crashing example. Place mce.ui into the 
the current directory.
Compiling via compileUi is successful: 
>>> with open("mce.py", "w", encoding="utf-8") as f: compileUi("mce.ui", f)

Compiling via compileUiDir fails:
>>> compileUiDir(".")
[snip]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d in position 161: 
character maps to <undefined>

Greetings,

Thomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: compileUiDir.patch
Type: text/x-patch
Size: 650 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20221019/3c99f484/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mce.ui
Type: application/x-designer
Size: 233 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20221019/3c99f484/attachment-0001.bin>


More information about the PyQt mailing list