From adf09474bb7302fed4e92c583ba21831ea80b7e9 Mon Sep 17 00:00:00 2001 From: ttpss930141011 Date: Thu, 11 Jun 2026 22:20:28 -0700 Subject: [PATCH 1/3] [cuebot/proto] Fix SetManagedCores RPC name so the servant implements it The DepartmentInterface RPC was declared as SetMangedCores while the cuebot servant implements setManagedCores. The servant method never overrode the generated base method, so the RPC always returned UNIMPLEMENTED. Rename the RPC to the correct spelling and mark the servant method as an override. The rename is safe: no client could ever call this RPC successfully, and nothing else references the old name. Part of #2399. --- VERSION.in | 2 +- .../java/com/imageworks/spcue/servant/ManageDepartment.java | 1 + proto/src/department.proto | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/VERSION.in b/VERSION.in index 581595d5a..c8d389333 100644 --- a/VERSION.in +++ b/VERSION.in @@ -1 +1 @@ -1.25 \ No newline at end of file +1.26 \ No newline at end of file diff --git a/cuebot/src/main/java/com/imageworks/spcue/servant/ManageDepartment.java b/cuebot/src/main/java/com/imageworks/spcue/servant/ManageDepartment.java index 42936b9fd..7478fa06f 100644 --- a/cuebot/src/main/java/com/imageworks/spcue/servant/ManageDepartment.java +++ b/cuebot/src/main/java/com/imageworks/spcue/servant/ManageDepartment.java @@ -182,6 +182,7 @@ public void replaceTasks(DeptReplaceTaskRequest request, responseObserver.onCompleted(); } + @Override public void setManagedCores(DeptSetManagedCoresRequest request, StreamObserver responseObserver) { PointDetail deptConfig = diff --git a/proto/src/department.proto b/proto/src/department.proto index dd2af3183..498ee1d6e 100644 --- a/proto/src/department.proto +++ b/proto/src/department.proto @@ -69,7 +69,7 @@ service DepartmentInterface { rpc ReplaceTasks(DeptReplaceTaskRequest) returns (DeptReplaceTaskResponse); // Sets the minimum number of cores for the department to manage between its tasks. - rpc SetMangedCores(DeptSetManagedCoresRequest) returns (DeptSetManagedCoresResponse); + rpc SetManagedCores(DeptSetManagedCoresRequest) returns (DeptSetManagedCoresResponse); } From 083789ae906f9cecbd2fda3d2ead36bf60f8b14a Mon Sep 17 00:00:00 2001 From: ttpss930141011 Date: Thu, 11 Jun 2026 22:20:38 -0700 Subject: [PATCH 2/3] [pycue] Add Department wrapper and missing department RPC methods CueGUI's TasksDialog calls Show.getDepartments() and several methods on the returned department objects, but pycue never had a Department wrapper, so the dialog raised AttributeError on open (#1042). - Add opencue.wrappers.department.Department covering the DepartmentInterface RPCs that cuebot implements. - Add Show.getDepartment() and Show.getDepartments(). - Add api.addDepartmentName() and api.removeDepartmentName() alongside the existing getDepartmentNames() so the list of allowed department names can be managed from Python. - Add Task.clearAdjustments(), used by the Tasks dialog context menu. DepartmentInterface.Delete is intentionally not wrapped because cuebot does not implement it. Fixes #2399 --- api_docs/modules/opencue.wrappers.rst | 6 + pycue/opencue/api.py | 27 +++- pycue/opencue/wrappers/department.py | 143 ++++++++++++++++++ pycue/opencue/wrappers/show.py | 26 ++++ pycue/opencue/wrappers/task.py | 5 + pycue/tests/test_api.py | 42 ++++++ pycue/tests/wrappers/test_department.py | 189 ++++++++++++++++++++++++ pycue/tests/wrappers/test_show.py | 32 ++++ pycue/tests/wrappers/test_task.py | 12 ++ 9 files changed, 480 insertions(+), 2 deletions(-) create mode 100644 pycue/opencue/wrappers/department.py create mode 100644 pycue/tests/wrappers/test_department.py diff --git a/api_docs/modules/opencue.wrappers.rst b/api_docs/modules/opencue.wrappers.rst index cc29047ed..4def99c95 100644 --- a/api_docs/modules/opencue.wrappers.rst +++ b/api_docs/modules/opencue.wrappers.rst @@ -28,6 +28,12 @@ opencue.wrappers.deed module .. automodule:: opencue.wrappers.deed :members: +opencue.wrappers.department module +---------------------------------- + +.. automodule:: opencue.wrappers.department + :members: + opencue.wrappers.depend module ------------------------------ diff --git a/pycue/opencue/api.py b/pycue/opencue/api.py index 8f02dc983..b0f769310 100644 --- a/pycue/opencue/api.py +++ b/pycue/opencue/api.py @@ -38,6 +38,7 @@ # pylint: disable=cyclic-import from .wrappers.allocation import Allocation from .wrappers.comment import Comment +from .wrappers.department import Department from .wrappers.depend import Depend from .wrappers.filter import Action from .wrappers.filter import Filter @@ -62,8 +63,8 @@ filter_pb2, host_pb2, job_pb2, renderPartition_pb2, report_pb2, service_pb2, show_pb2, subscription_pb2, task_pb2] -__wrappers = [Action, Allocation, Comment, Depend, Filter, Frame, Group, Host, Job, Layer, Matcher, - NestedHost, Proc, Show, Subscription, Task] +__wrappers = [Action, Allocation, Comment, Department, Depend, Filter, Frame, Group, Host, Job, + Layer, Matcher, NestedHost, Proc, Show, Subscription, Task] # @@ -187,6 +188,28 @@ def getDepartmentNames(): department_pb2.DeptGetDepartmentNamesRequest(), timeout=Cuebot.Timeout).names) +@util.grpcExceptionParser +def addDepartmentName(name): + """Adds a department name to the list of allowed department names. + + :type name: str + :param name: a department name to allow + """ + Cuebot.getStub('department').AddDepartmentName( + department_pb2.DeptAddDeptNameRequest(name=name), timeout=Cuebot.Timeout) + + +@util.grpcExceptionParser +def removeDepartmentName(name): + """Removes a department name from the list of allowed department names. + + :type name: str + :param name: the department name to remove + """ + Cuebot.getStub('department').RemoveDepartmentName( + department_pb2.DeptRemoveDepartmentNameRequest(name=name), timeout=Cuebot.Timeout) + + # # Shows # diff --git a/pycue/opencue/wrappers/department.py b/pycue/opencue/wrappers/department.py new file mode 100644 index 000000000..ad90bcef5 --- /dev/null +++ b/pycue/opencue/wrappers/department.py @@ -0,0 +1,143 @@ +# Copyright Contributors to the OpenCue Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Module for classes related to departments.""" + +from opencue_proto import department_pb2 +from opencue.cuebot import Cuebot +import opencue.wrappers.task + + +class Department(object): + """This class contains the grpc implementation related to a Department.""" + + def __init__(self, department=None): + self.data = department + self.stub = Cuebot.getStub('department') + + def addTask(self, shot, minCores): + """Adds a task to the department and returns it. + + :type shot: str + :param shot: name of the shot the task is for + :type minCores: float + :param minCores: the minimum number of cores the task needs + :rtype: opencue.wrappers.task.Task + :return: the newly created task + """ + response = self.stub.AddTask( + department_pb2.DeptAddTaskRequest( + department=self.data, shot=shot, min_cores=minCores), + timeout=Cuebot.Timeout) + return opencue.wrappers.task.Task(response.task) + + def addTasks(self, taskMap): + """Adds a map of tasks to the department and returns them as a list. + + :type taskMap: dict + :param taskMap: map of shot names to minimum core units + :rtype: list + :return: the newly created tasks + """ + response = self.stub.AddTasks( + department_pb2.DeptAddTasksRequest(department=self.data, tmap=taskMap), + timeout=Cuebot.Timeout) + return [opencue.wrappers.task.Task(task) for task in response.tasks.tasks] + + def clearTaskAdjustments(self): + """Clears all manual task adjustments to managed tasks. + + This won't do anything unless the department is Track-It managed. + """ + self.stub.ClearTaskAdjustments( + department_pb2.DeptClearTaskAdjustmentsRequest(department=self.data), + timeout=Cuebot.Timeout) + + def clearTasks(self): + """Clears all tasks from the department.""" + self.stub.ClearTasks( + department_pb2.DeptClearTasksRequest(department=self.data), + timeout=Cuebot.Timeout) + + def disableTiManaged(self): + """Disables Track-It management; this also clears all tasks.""" + self.stub.DisableTiManaged( + department_pb2.DeptDisableTiManagedRequest(department=self.data), + timeout=Cuebot.Timeout) + + def enableTiManaged(self, tiTask, managedCores): + """Enables Track-It management. + + This will pull a task list from Track-It and keep it synced. + + :type tiTask: str + :param tiTask: name of the Track-It task to manage the department with + :type managedCores: float + :param managedCores: the number of cores to split up among the active tasks + """ + self.stub.EnableTiManaged( + department_pb2.DeptEnableTiManagedRequest( + department=self.data, ti_task=tiTask, managed_cores=managedCores), + timeout=Cuebot.Timeout) + + def getTasks(self): + """Returns the list of tasks for the department. + + :rtype: list + :return: tasks of the department + """ + response = self.stub.GetTasks( + department_pb2.DeptGetTasksRequest(department=self.data), + timeout=Cuebot.Timeout) + return [opencue.wrappers.task.Task(task) for task in response.tasks.tasks] + + def replaceTasks(self, taskMap): + """Replaces a map of tasks; existing tasks are updated, new tasks are inserted. + + :type taskMap: dict + :param taskMap: map of shot names to minimum core units + :rtype: list + :return: the resulting tasks + """ + response = self.stub.ReplaceTasks( + department_pb2.DeptReplaceTaskRequest(department=self.data, tmap=taskMap), + timeout=Cuebot.Timeout) + return [opencue.wrappers.task.Task(task) for task in response.tasks.tasks] + + def setManagedCores(self, managedCores): + """Sets the minimum number of cores for the department to manage between its tasks. + + :type managedCores: float + :param managedCores: the number of cores to manage between the tasks + """ + self.stub.SetManagedCores( + department_pb2.DeptSetManagedCoresRequest( + department=self.data, managed_cores=managedCores), + timeout=Cuebot.Timeout) + + def id(self): + """Returns the unique id of the department. + + :rtype: str + :return: department id + """ + return self.data.id + + def name(self): + """Returns the name of the department. + + :rtype: str + :return: department name + """ + return self.data.name diff --git a/pycue/opencue/wrappers/show.py b/pycue/opencue/wrappers/show.py index 806994e78..c40cf6a81 100644 --- a/pycue/opencue/wrappers/show.py +++ b/pycue/opencue/wrappers/show.py @@ -16,6 +16,7 @@ from opencue_proto import show_pb2 from opencue.cuebot import Cuebot +import opencue.wrappers.department import opencue.wrappers.filter import opencue.wrappers.group import opencue.wrappers.subscription @@ -257,6 +258,31 @@ def createFilter(self, name): show=self.data, name=name), timeout=Cuebot.Timeout) return opencue.wrappers.filter.Filter(response.filter) + def getDepartment(self, department): + """Gets the department of the show with the matching name. + + :type department: str + :param department: name of the department to find + :rtype: opencue.wrappers.department.Department + :return: matching department of the show + """ + response = self.stub.GetDepartment(show_pb2.ShowGetDepartmentRequest( + show=self.data, department=department), + timeout=Cuebot.Timeout) + return opencue.wrappers.department.Department(response.department) + + def getDepartments(self): + """Gets the departments that belong to the show. + + :rtype: list + :return: list of departments for this show + """ + response = self.stub.GetDepartments(show_pb2.ShowGetDepartmentsRequest( + show=self.data), + timeout=Cuebot.Timeout) + return [opencue.wrappers.department.Department(dept) + for dept in response.departments.departments] + def getGroups(self): """Gets the groups for the show. diff --git a/pycue/opencue/wrappers/task.py b/pycue/opencue/wrappers/task.py index 5f3c37f65..92152c18a 100644 --- a/pycue/opencue/wrappers/task.py +++ b/pycue/opencue/wrappers/task.py @@ -43,6 +43,11 @@ def setMinCores(self, minCores): task_pb2.TaskSetMinCoresRequest(task=self.data, new_min_cores=minCores), timeout=Cuebot.Timeout) + def clearAdjustments(self): + """Clears any manual adjustments made to the task.""" + self.stub.ClearAdjustments( + task_pb2.TaskClearAdjustmentsRequest(task=self.data), timeout=Cuebot.Timeout) + def delete(self): """Deletes the task.""" self.stub.Delete(task_pb2.TaskDeleteRequest(task=self.data), timeout=Cuebot.Timeout) diff --git a/pycue/tests/test_api.py b/pycue/tests/test_api.py index 94b0e8152..2343c5779 100644 --- a/pycue/tests/test_api.py +++ b/pycue/tests/test_api.py @@ -24,6 +24,7 @@ import mock from opencue_proto import cue_pb2 +from opencue_proto import department_pb2 from opencue_proto import depend_pb2 from opencue_proto import facility_pb2 from opencue_proto import filter_pb2 @@ -45,6 +46,7 @@ TEST_HOST_NAME = 'wolf1001' TEST_SUB_NAME = 'pipe.General' TEST_FACILITY_NAME = 'arbitrary-facility-name' +TEST_DEPARTMENT_NAME = 'arbitrary-department-name' TEST_TAG = 'General' TEST_ALLOC_NAME = 'pipe.General' TEST_PROC_NAME = 'arbitrary-proc-name' @@ -619,6 +621,46 @@ def testDeleteFacility(self, getStubMock): facility_pb2.FacilityDeleteRequest(name=TEST_FACILITY_NAME), timeout=mock.ANY) +class DepartmentTests(unittest.TestCase): + + @mock.patch('opencue.cuebot.Cuebot.getStub') + def testGetDepartmentNames(self, getStubMock): + stubMock = mock.Mock() + stubMock.GetDepartmentNames.return_value = department_pb2.DeptGetDepartmentNamesResponse( + names=[TEST_DEPARTMENT_NAME]) + getStubMock.return_value = stubMock + + names = opencue.api.getDepartmentNames() + + stubMock.GetDepartmentNames.assert_called_with( + department_pb2.DeptGetDepartmentNamesRequest(), timeout=mock.ANY) + self.assertEqual([TEST_DEPARTMENT_NAME], names) + + @mock.patch('opencue.cuebot.Cuebot.getStub') + def testAddDepartmentName(self, getStubMock): + stubMock = mock.Mock() + stubMock.AddDepartmentName.return_value = department_pb2.DeptAddDeptNameResponse() + getStubMock.return_value = stubMock + + opencue.api.addDepartmentName(TEST_DEPARTMENT_NAME) + + stubMock.AddDepartmentName.assert_called_with( + department_pb2.DeptAddDeptNameRequest(name=TEST_DEPARTMENT_NAME), timeout=mock.ANY) + + @mock.patch('opencue.cuebot.Cuebot.getStub') + def testRemoveDepartmentName(self, getStubMock): + stubMock = mock.Mock() + stubMock.RemoveDepartmentName.return_value = \ + department_pb2.DeptRemoveDepartmentNameResponse() + getStubMock.return_value = stubMock + + opencue.api.removeDepartmentName(TEST_DEPARTMENT_NAME) + + stubMock.RemoveDepartmentName.assert_called_with( + department_pb2.DeptRemoveDepartmentNameRequest(name=TEST_DEPARTMENT_NAME), + timeout=mock.ANY) + + class DependTests(unittest.TestCase): @mock.patch('opencue.cuebot.Cuebot.getStub') diff --git a/pycue/tests/wrappers/test_department.py b/pycue/tests/wrappers/test_department.py new file mode 100644 index 000000000..dd3c96ab5 --- /dev/null +++ b/pycue/tests/wrappers/test_department.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python + +# Copyright Contributors to the OpenCue Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests for `opencue.wrappers.department`.""" + +from __future__ import print_function +from __future__ import division +from __future__ import absolute_import +import unittest + +import mock + +from opencue_proto import department_pb2 +from opencue_proto import task_pb2 +import opencue.wrappers.department + + +TEST_DEPARTMENT_ID = 'ddd-dddd-ddd' +TEST_DEPARTMENT_NAME = 'testDepartment' +TEST_SHOT = 'testShot' +TEST_TI_TASK = 'testTiTask' +TEST_MIN_CORES = 42 + + +@mock.patch('opencue.cuebot.Cuebot.getStub') +class DepartmentTests(unittest.TestCase): + + def testId(self, getStubMock): + department = opencue.wrappers.department.Department( + department_pb2.Department(id=TEST_DEPARTMENT_ID)) + + self.assertEqual(department.id(), TEST_DEPARTMENT_ID) + + def testName(self, getStubMock): + department = opencue.wrappers.department.Department( + department_pb2.Department(name=TEST_DEPARTMENT_NAME)) + + self.assertEqual(department.name(), TEST_DEPARTMENT_NAME) + + def testAddTask(self, getStubMock): + stubMock = mock.Mock() + stubMock.AddTask.return_value = department_pb2.DeptAddTaskResponse( + task=task_pb2.Task(shot=TEST_SHOT, min_cores=TEST_MIN_CORES)) + getStubMock.return_value = stubMock + + department = opencue.wrappers.department.Department( + department_pb2.Department(name=TEST_DEPARTMENT_NAME)) + task = department.addTask(TEST_SHOT, TEST_MIN_CORES) + + stubMock.AddTask.assert_called_with( + department_pb2.DeptAddTaskRequest( + department=department.data, shot=TEST_SHOT, min_cores=TEST_MIN_CORES), + timeout=mock.ANY) + self.assertEqual(task.data.shot, TEST_SHOT) + + def testAddTasks(self, getStubMock): + stubMock = mock.Mock() + stubMock.AddTasks.return_value = department_pb2.DeptAddTasksResponse( + tasks=task_pb2.TaskSeq(tasks=[task_pb2.Task(shot=TEST_SHOT)])) + getStubMock.return_value = stubMock + + taskMap = {TEST_SHOT: TEST_MIN_CORES} + department = opencue.wrappers.department.Department( + department_pb2.Department(name=TEST_DEPARTMENT_NAME)) + tasks = department.addTasks(taskMap) + + stubMock.AddTasks.assert_called_with( + department_pb2.DeptAddTasksRequest(department=department.data, tmap=taskMap), + timeout=mock.ANY) + self.assertEqual(len(tasks), 1) + self.assertEqual(tasks[0].data.shot, TEST_SHOT) + + def testClearTaskAdjustments(self, getStubMock): + stubMock = mock.Mock() + stubMock.ClearTaskAdjustments.return_value = \ + department_pb2.DeptClearTaskAdjustmentsResponse() + getStubMock.return_value = stubMock + + department = opencue.wrappers.department.Department( + department_pb2.Department(name=TEST_DEPARTMENT_NAME)) + department.clearTaskAdjustments() + + stubMock.ClearTaskAdjustments.assert_called_with( + department_pb2.DeptClearTaskAdjustmentsRequest(department=department.data), + timeout=mock.ANY) + + def testClearTasks(self, getStubMock): + stubMock = mock.Mock() + stubMock.ClearTasks.return_value = department_pb2.DeptClearTasksResponse() + getStubMock.return_value = stubMock + + department = opencue.wrappers.department.Department( + department_pb2.Department(name=TEST_DEPARTMENT_NAME)) + department.clearTasks() + + stubMock.ClearTasks.assert_called_with( + department_pb2.DeptClearTasksRequest(department=department.data), + timeout=mock.ANY) + + def testDisableTiManaged(self, getStubMock): + stubMock = mock.Mock() + stubMock.DisableTiManaged.return_value = department_pb2.DeptDisableTiManagedResponse() + getStubMock.return_value = stubMock + + department = opencue.wrappers.department.Department( + department_pb2.Department(name=TEST_DEPARTMENT_NAME)) + department.disableTiManaged() + + stubMock.DisableTiManaged.assert_called_with( + department_pb2.DeptDisableTiManagedRequest(department=department.data), + timeout=mock.ANY) + + def testEnableTiManaged(self, getStubMock): + stubMock = mock.Mock() + stubMock.EnableTiManaged.return_value = department_pb2.DeptEnableTiManagedResponse() + getStubMock.return_value = stubMock + + department = opencue.wrappers.department.Department( + department_pb2.Department(name=TEST_DEPARTMENT_NAME)) + department.enableTiManaged(TEST_TI_TASK, TEST_MIN_CORES) + + stubMock.EnableTiManaged.assert_called_with( + department_pb2.DeptEnableTiManagedRequest( + department=department.data, ti_task=TEST_TI_TASK, managed_cores=TEST_MIN_CORES), + timeout=mock.ANY) + + def testGetTasks(self, getStubMock): + stubMock = mock.Mock() + stubMock.GetTasks.return_value = department_pb2.DeptGetTasksResponse( + tasks=task_pb2.TaskSeq(tasks=[task_pb2.Task(shot=TEST_SHOT)])) + getStubMock.return_value = stubMock + + department = opencue.wrappers.department.Department( + department_pb2.Department(name=TEST_DEPARTMENT_NAME)) + tasks = department.getTasks() + + stubMock.GetTasks.assert_called_with( + department_pb2.DeptGetTasksRequest(department=department.data), + timeout=mock.ANY) + self.assertEqual(len(tasks), 1) + self.assertEqual(tasks[0].data.shot, TEST_SHOT) + + def testReplaceTasks(self, getStubMock): + stubMock = mock.Mock() + stubMock.ReplaceTasks.return_value = department_pb2.DeptReplaceTaskResponse( + tasks=task_pb2.TaskSeq(tasks=[task_pb2.Task(shot=TEST_SHOT)])) + getStubMock.return_value = stubMock + + taskMap = {TEST_SHOT: TEST_MIN_CORES} + department = opencue.wrappers.department.Department( + department_pb2.Department(name=TEST_DEPARTMENT_NAME)) + tasks = department.replaceTasks(taskMap) + + stubMock.ReplaceTasks.assert_called_with( + department_pb2.DeptReplaceTaskRequest(department=department.data, tmap=taskMap), + timeout=mock.ANY) + self.assertEqual(len(tasks), 1) + self.assertEqual(tasks[0].data.shot, TEST_SHOT) + + def testSetManagedCores(self, getStubMock): + stubMock = mock.Mock() + stubMock.SetManagedCores.return_value = department_pb2.DeptSetManagedCoresResponse() + getStubMock.return_value = stubMock + + department = opencue.wrappers.department.Department( + department_pb2.Department(name=TEST_DEPARTMENT_NAME)) + department.setManagedCores(TEST_MIN_CORES) + + stubMock.SetManagedCores.assert_called_with( + department_pb2.DeptSetManagedCoresRequest( + department=department.data, managed_cores=TEST_MIN_CORES), + timeout=mock.ANY) + + +if __name__ == '__main__': + unittest.main() diff --git a/pycue/tests/wrappers/test_show.py b/pycue/tests/wrappers/test_show.py index 99d41bdf0..31873936e 100644 --- a/pycue/tests/wrappers/test_show.py +++ b/pycue/tests/wrappers/test_show.py @@ -23,6 +23,7 @@ import mock +from opencue_proto import department_pb2 from opencue_proto import facility_pb2 from opencue_proto import filter_pb2 from opencue_proto import host_pb2 @@ -49,6 +50,7 @@ TEST_ENABLE_VALUE = False TEST_GROUP_NAME = 'group' TEST_GROUP_DEPT = 'lighting' +TEST_DEPARTMENT_NAME = 'unittest_department' TEST_TARGET_SHOW_NAME = 'target_show' @@ -285,6 +287,36 @@ def testCreateFilter(self, getStubMock): timeout=mock.ANY) self.assertEqual(filter_created.name(), TEST_FILTER_NAME) + def testGetDepartment(self, getStubMock): + stubMock = mock.Mock() + stubMock.GetDepartment.return_value = show_pb2.ShowGetDepartmentResponse( + department=department_pb2.Department(name=TEST_DEPARTMENT_NAME)) + getStubMock.return_value = stubMock + + show = opencue.wrappers.show.Show(show_pb2.Show(name=TEST_SHOW_NAME)) + department = show.getDepartment(TEST_DEPARTMENT_NAME) + + stubMock.GetDepartment.assert_called_with( + show_pb2.ShowGetDepartmentRequest(show=show.data, department=TEST_DEPARTMENT_NAME), + timeout=mock.ANY) + self.assertEqual(department.name(), TEST_DEPARTMENT_NAME) + + def testGetDepartments(self, getStubMock): + stubMock = mock.Mock() + stubMock.GetDepartments.return_value = show_pb2.ShowGetDepartmentsResponse( + departments=department_pb2.DepartmentSeq( + departments=[department_pb2.Department(name=TEST_DEPARTMENT_NAME)]) + ) + getStubMock.return_value = stubMock + + show = opencue.wrappers.show.Show(show_pb2.Show(name=TEST_SHOW_NAME)) + departments = show.getDepartments() + + stubMock.GetDepartments.assert_called_with( + show_pb2.ShowGetDepartmentsRequest(show=show.data), timeout=mock.ANY) + self.assertEqual(len(departments), 1) + self.assertEqual(departments[0].name(), TEST_DEPARTMENT_NAME) + def testGetGroups(self, getStubMock): stubMock = mock.Mock() stubMock.GetGroups.return_value = show_pb2.ShowGetGroupsResponse( diff --git a/pycue/tests/wrappers/test_task.py b/pycue/tests/wrappers/test_task.py index cd066577e..3b4441823 100644 --- a/pycue/tests/wrappers/test_task.py +++ b/pycue/tests/wrappers/test_task.py @@ -57,6 +57,18 @@ def testSetMinCores(self, getStubMock): task_pb2.TaskSetMinCoresRequest(task=task.data, new_min_cores=minCores), timeout=mock.ANY) + def testClearAdjustments(self, getStubMock): + stubMock = mock.Mock() + stubMock.ClearAdjustments.return_value = task_pb2.TaskClearAdjustmentsResponse() + getStubMock.return_value = stubMock + + task = opencue.wrappers.task.Task( + task_pb2.Task(name='testTask')) + task.clearAdjustments() + + stubMock.ClearAdjustments.assert_called_with( + task_pb2.TaskClearAdjustmentsRequest(task=task.data), timeout=mock.ANY) + if __name__ == '__main__': unittest.main() From ffc2b2f134dac74a9e8161f3ed8a5e20a3f242ab Mon Sep 17 00:00:00 2001 From: ttpss930141011 Date: Thu, 11 Jun 2026 22:20:46 -0700 Subject: [PATCH 3/3] [cuegui] Call Task.clearAdjustments() from the task context menu TaskActions.clearAdjustment called task.clearAdjustment(), which never existed on the pycue Task wrapper; the unit test mocked the attribute so the gap was never caught. Point both at the real Task.clearAdjustments() method. Part of #2399. --- cuegui/cuegui/MenuActions.py | 2 +- cuegui/tests/test_menu_actions.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cuegui/cuegui/MenuActions.py b/cuegui/cuegui/MenuActions.py index 939bfb176..b709a6631 100644 --- a/cuegui/cuegui/MenuActions.py +++ b/cuegui/cuegui/MenuActions.py @@ -2264,7 +2264,7 @@ def setMinCores(self, rpcObjects=None): def clearAdjustment(self, rpcObjects=None): tasks = self._getSelected(rpcObjects) for task in tasks: - task.clearAdjustment() + task.clearAdjustments() self._update() delete_info = ["Delete Task", None, "configure"] diff --git a/cuegui/tests/test_menu_actions.py b/cuegui/tests/test_menu_actions.py index 3d7140d0b..324da23c8 100644 --- a/cuegui/tests/test_menu_actions.py +++ b/cuegui/tests/test_menu_actions.py @@ -1738,11 +1738,11 @@ def test_setMinCores(self, getDoubleMock): def test_clearAdjustment(self): task = opencue.wrappers.task.Task(opencue_proto.task_pb2.Task()) - task.clearAdjustment = mock.MagicMock() + task.clearAdjustments = mock.MagicMock() self.task_actions.clearAdjustment(rpcObjects=[task]) - task.clearAdjustment.assert_called() + task.clearAdjustments.assert_called() @mock.patch('cuegui.Utils.questionBoxYesNo', new=mock.Mock(return_value=True)) def test_delete(self):