Skip to content

Commit

Permalink
updating the headerToModule def to only manipulate '.h' files.
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonbrackman committed Mar 13, 2024
1 parent dd084b4 commit 27bd498
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 2 deletions.
13 changes: 12 additions & 1 deletion Qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,11 @@ def headerToModule(header):
Translate a header file to python module path
foo/bar.h => foo.bar
"""

if header.endswith(".h") is False:
# Only manipulate header files, identified by the `.h` ext.
return header

# Remove header extension
module = os.path.splitext(header)[0]

Expand All @@ -944,7 +949,13 @@ def headerToModule(header):
for custom_widget in custom_widgets:
class_name = custom_widget.find("class").text
header = custom_widget.find("header").text
module = importlib.import_module(headerToModule(header))
try:
header = headerToModule(header)
module = importlib.import_module(header)
except ModuleNotFoundError as _error:
# ReRaising the ModuleNOtFoundError with a more informative
# message to aid in the creation of Tests for this case.
raise ModuleNotFoundError("No module named '%s'" % header)
self.custom_widgets[class_name] = getattr(module,
class_name)

Expand Down
95 changes: 94 additions & 1 deletion tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,37 @@ class Widget(QtWidgets.QWidget):
</ui>
"""

qpycustomwidget_ui = u"""\
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>238</width>
<height>44</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="CustomWidget" name="customwidget">
</widget>
</widget>
<customwidgets>
<customwidget>
<class>CustomWidget</class>
<extends>QWidget</extends>
<header>tests</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
"""


def setup():
"""Module-wide initialisation
Expand All @@ -263,7 +294,7 @@ def saveUiFile(filename, ui_template):
self.ui_qdialog = saveUiFile("qdialog.ui", qdialog_ui)
self.ui_qdockwidget = saveUiFile("qdockwidget.ui", qdockwidget_ui)
self.ui_qcustomwidget = saveUiFile("qcustomwidget.ui", qcustomwidget_ui)

self.ui_qpycustomwidget = saveUiFile("qpycustomwidget.ui", qpycustomwidget_ui)

def teardown():
shutil.rmtree(self.tempdir)
Expand Down Expand Up @@ -418,6 +449,68 @@ def test_load_ui_customwidget():
app.exit()


def _rewrite_file(file, current, provided):
with open(file, "r") as f:
new = f.read().replace(
"<header>" + current + "</header>",
"<header>" + provided + "</header>"
)
with open(self.ui_qpycustomwidget, "w") as f:
f.write(new)


def test_load_ui_pycustomwidget():
"""Tests to see if loadUi loads a custom widget from different sources,
such as a Python path or a .h path can be parsed properly.
The structure of the current code does not provide direct access to the
headertomodule function. Instead, the test updates the temp.ui file to
contain a different header and tries to load the UI. All cases are
designed to trigger a ModuleImport Exception which reports the path
expected.
"""

from Qt import QtCompat

path_tests = {
# Input: Expected

# Valid paths; .h paths need to be updated to work with Qt.py
"path.to.module": "path.to.module", # valid python .path to module
"path\\to\\module.h": "path.to.module", # valid .h path with backslashes
"path\\to/module.h": "path.to.module", # mixed slashes
"path/to/module.h": "path.to.module", # valid .h path with forward slashes
"module.h": "module", # valid .h file in current path
"module": "module", # valid python module in current path

# malformed; Should we change QtDesigner input?
"path.to.module.py": "path.to.module.py",
"path\\to\\module.py": "path\\to\\module.py",
"path/to/module.py": "path/to/module.py",
"path\\to\\module": "path\\to\\module",
"path/to/module": "path/to/module",
"module.py": "module.py",
}

current = "tests"
for provided, expected in path_tests.items():
_rewrite_file(self.ui_qpycustomwidget, current, provided)
current = provided

try:
# actual test
QtCompat.loadUi(self.ui_qpycustomwidget)

except ModuleNotFoundError as error:
# Since the loadUi is a blackbox it is not possible to test the
# `headertomodule` function directly. Test if the moduleimport
# error contains the correct import path.
result = error.msg.split("'")[1]
assert result == expected, (
"Provided: %s expected: %s got: %s" % (provided, expected, result)
)


def test_load_ui_invalidpath():
"""Tests to see if loadUi successfully fails on invalid paths"""
import sys
Expand Down

0 comments on commit 27bd498

Please sign in to comment.