diff --git a/cuegui/cuegui/Redirect.py b/cuegui/cuegui/Redirect.py index b7e60fcb5..2da6dcfb0 100644 --- a/cuegui/cuegui/Redirect.py +++ b/cuegui/cuegui/Redirect.py @@ -189,6 +189,8 @@ def showChanged(self, show): def __populate_menu(self): self.__menu.clear() + if not self.__show: + return for group in self.__show.getGroups(): if opencue.id(group) in self.__actions: self.__menu.addAction(self.__actions[opencue.id(group)]) @@ -212,9 +214,10 @@ class RedirectControls(QtWidgets.QWidget): """ def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) - self.__current_show = opencue.api.findShow(os.getenv("SHOW", "pipe")) + self.__current_show = self.__getDefaultShow() - self.__show_combo = ShowCombo(self.__current_show.data.name, self) + show_name = self.__current_show.data.name if self.__current_show else "" + self.__show_combo = ShowCombo(show_name, self) self.__job_box = JobBox(self) self.__alloc_filter = AllocFilter(self) @@ -299,6 +302,31 @@ def __init__(self, parent=None): self.__show_combo.currentIndexChanged.connect(self.showChanged) # pylint: enable=no-member + @staticmethod + def __getDefaultShow(): + """Returns the show to select by default. + + Tries the show named by the SHOW environment variable (falling back to + "pipe"), and if that show does not exist, falls back to the first active + show alphabetically. Returns None when there are no active shows, so the + widget can still build instead of leaving a blank page. + + @return: The default show, or None if no active shows exist + @rtype: L{opencue.wrappers.show.Show} or None + """ + show_name = os.getenv("SHOW", "pipe") + try: + return opencue.api.findShow(show_name) + except opencue.exception.CueException: + logger.warning( + "Default show '%s' not found, falling back to first active show", show_name) + shows = opencue.api.getActiveShows() + if shows: + shows.sort(key=lambda x: x.data.name) + return shows[0] + logger.warning("No active shows found") + return None + def _cfg(self): ''' Loads (if necessary) and returns the config values. @@ -314,8 +342,14 @@ def _cfg(self): def showChanged(self, show_index): """Load a new show.""" del show_index - show = self.__show_combo.currentText() - self.__current_show = opencue.api.findShow(str(show)) + show = str(self.__show_combo.currentText()) + if not show: + return + try: + self.__current_show = opencue.api.findShow(show) + except opencue.exception.CueException: + logger.warning("Unable to load show '%s'", show) + return self.__include_group_btn.showChanged(self.__current_show) def detect(self, name=None): @@ -751,6 +785,11 @@ def clearTarget(self): def update(self): """ Update the model """ + show = self.__controls.getShow() + if not show: + self.__warn("No active show is available to search.") + return + self.__model.clear() self.__model.setHorizontalHeaderLabels(RedirectWidget.HEADERS) @@ -761,7 +800,6 @@ def update(self): groupFilter = self.__controls.getIncludedGroups() jobRegexFilter = self.__controls.getJobNameExcludeRegex() - show = self.__controls.getShow() alloc = self.__controls.getAllocFilter() procs = opencue.api.getProcs(show=[str(show.data.name)], alloc=alloc.getSelected()) diff --git a/cuegui/tests/test_redirect.py b/cuegui/tests/test_redirect.py index 9d5e18e02..c90414acf 100644 --- a/cuegui/tests/test_redirect.py +++ b/cuegui/tests/test_redirect.py @@ -22,6 +22,8 @@ import qtpy.QtCore import qtpy.QtGui +import opencue.exception +import opencue.wrappers.show import opencue_proto.show_pb2 import cuegui.Redirect @@ -50,3 +52,30 @@ def setUp(self, getStubMock): def test_setup(self): pass + + @mock.patch('opencue.api.getJobNames', new=mock.Mock(return_value=[])) + @mock.patch('opencue.api.getAllocations', new=mock.Mock(return_value=[])) + @mock.patch('opencue.api.getActiveShows') + @mock.patch('opencue.api.findShow') + def test_builds_when_default_show_missing(self, findShowMock, getActiveShowsMock): + # The hardcoded default show ("pipe") does not exist on this cuebot. + findShowMock.side_effect = opencue.exception.EntityNotFoundException('show not found') + fallback_show = opencue.wrappers.show.Show( + opencue_proto.show_pb2.Show(name='fallback')) + getActiveShowsMock.return_value = [fallback_show] + + # Should build the widget instead of raising (which leaves a blank page). + widget = cuegui.Redirect.RedirectWidget() + self.assertIsNotNone(widget) + + @mock.patch('opencue.api.getJobNames', new=mock.Mock(return_value=[])) + @mock.patch('opencue.api.getAllocations', new=mock.Mock(return_value=[])) + @mock.patch('opencue.api.getActiveShows') + @mock.patch('opencue.api.findShow') + def test_builds_when_no_active_shows(self, findShowMock, getActiveShowsMock): + # No show matches the default and there are no active shows at all. + findShowMock.side_effect = opencue.exception.EntityNotFoundException('show not found') + getActiveShowsMock.return_value = [] + + widget = cuegui.Redirect.RedirectWidget() + self.assertIsNotNone(widget)