Skip to content

Commit

Permalink
Merge pull request #888 from jbellister-slac/add_display_tests
Browse files Browse the repository at this point in the history
TST: Add some test cases for loading python files as displays
  • Loading branch information
YektaY authored Jun 20, 2022
2 parents 222719f + 1a5908d commit d03cbc2
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 8 deletions.
13 changes: 5 additions & 8 deletions pydm/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ def load_py_file(pyfile, args=None, macros=None):
cls = module.intelclass
if not issubclass(cls, Display):
raise ValueError(
"Invalid class definition at file {}. {} does not inherit from Display. Nothing to open at this time.".format(
"Invalid class definition at file {}. {} does not inherit from Display. "
"Nothing to open at this time.".format(
pyfile, cls.__name__))
else:
classes = [obj for name, obj in inspect.getmembers(module) if
Expand All @@ -203,16 +204,12 @@ def load_py_file(pyfile, args=None, macros=None):
pyfile))
if len(classes) > 1:
warnings.warn(
"More than one Display class in file {}. The first occurence (in alphabetical order) will be opened: {}".format(
"More than one Display class in file {}. "
"The first occurrence (in alphabetical order) will be opened: {}".format(
pyfile, classes[0].__name__), RuntimeWarning, stacklevel=2)
cls = classes[0]

try:
# This only works in python 3 and up.
module_params = inspect.signature(cls).parameters
except AttributeError:
# Works in python 2, deprecated in 3.0 and up.
module_params = inspect.getargspec(cls.__init__).args
module_params = inspect.signature(cls).parameters

# Because older versions of Display may not have the args parameter or the macros parameter, we check
# to see if it does before trying to use them.
Expand Down
8 changes: 8 additions & 0 deletions pydm/tests/test_data/no_display_test_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# A sample test file of a python class that does not inherit from PyDM's display, but we try to load as a display anyway
from qtpy.QtCore import QObject


class InvalidDisplayExample(QObject):
""" A simple class that inherits from QObject only """
def __init__(self, parent=None):
super().__init__(parent=parent)
28 changes: 28 additions & 0 deletions pydm/tests/test_data/valid_display_test_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
""" This file is intended for use in Display related test files. """
import os
from pydm import Display
from pydm.widgets import PyDMPushButton, PyDMLabel
# Ensure loading of modules in the same directory works as expected when this file is loaded as a PyDM Display
import no_display_test_file


class DisplayExample(Display):
""" An example of a simple display that can be loaded by `load_py_file` in `display.py` """
def __init__(self, parent=None, args=None, macros=None):
super().__init__(parent=parent, args=args, macros=macros)
self.button = PyDMPushButton()
self.button.clicked.connect(self.delete_widget)

self.label = PyDMLabel(init_channel='TST:Val1')

def print_file(self):
print(f'{no_display_test_file}')

def delete_widget(self):
self.label.deleteLater()

def ui_filename(self):
return 'test.ui'

def ui_filepath(self):
return os.path.join(os.path.dirname(os.path.realpath(__file__)), self.ui_filename())
46 changes: 46 additions & 0 deletions pydm/tests/test_display.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import os
import pytest
from pydm import Display
from pydm.display import load_py_file

# The path to the .ui file used in these tests
test_ui_path = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
"test_data", "test.ui")

# The path to the .py files used in these tests
no_display_test_py_path = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
"test_data", "no_display_test_file.py")

valid_display_test_py_path = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
"test_data", "valid_display_test_file.py")


def test_ui_filename_arg(qtbot):
"""If you supply a valid filename argument, you shouldn't get any exceptions."""
Expand Down Expand Up @@ -34,3 +44,39 @@ def ui_filename(self):

with pytest.raises(IOError):
my_display = TestDisplay(parent=None)


def test_nonexistent_py_file_raises():
""" Load a python file that does not exist and confirm the error raised is as expected """
with pytest.raises(FileNotFoundError):
load_py_file('this_doesnt_exist.py')


def test_doesnt_inherit_display_raises():
""" Load a python file that does not inherit from PyDM Display and confirm the error raised is as expected """
with pytest.raises(ValueError) as error_info:
load_py_file(no_display_test_py_path)
assert 'no class inheriting from Display' in str(error_info.value)


def test_load_valid_python_display_file(qtbot):
""" Verify that loading a valid python only file inheriting from Display works as expected """
display = load_py_file(valid_display_test_py_path)
qtbot.addWidget(display)

# Confirm that the file loaded everything as expected
assert display.loaded_file() == valid_display_test_py_path
assert display.ui_filename() == 'test.ui'
assert display.macros() == {}
assert display.previous_display is None
assert display.next_display is None


def test_load_python_file_with_macros(qtbot):
""" Attempt to add macros to the display while loading the file """
macros = {'MACRO_1': 7, 'MACRO_2': 'test_string'}
display = load_py_file(valid_display_test_py_path, macros=macros)
qtbot.addWidget(display)
assert display.loaded_file() == valid_display_test_py_path
assert display.ui_filename() == 'test.ui'
assert display.macros() == {'MACRO_1': 7, 'MACRO_2': 'test_string'}

0 comments on commit d03cbc2

Please sign in to comment.