From 3b68d24cfbafaf7d9155a655c742540311d05701 Mon Sep 17 00:00:00 2001 From: Kuldeep Date: Tue, 9 Dec 2025 17:27:36 +0530 Subject: [PATCH 1/9] Do not show disabled pipeline steps in the File Open or Save dialogs --- info.yml | 4 ++ python/tk_multi_workfiles/new_task_form.py | 9 +-- python/tk_multi_workfiles/step_list_filter.py | 67 ++++++++++++++++--- 3 files changed, 66 insertions(+), 14 deletions(-) diff --git a/info.yml b/info.yml index c59aef36..0bc3d2b9 100644 --- a/info.yml +++ b/info.yml @@ -127,6 +127,10 @@ configuration: # General preferences # + pipeline_step_filter: + type: bool + description: If True, only Steps visible for the current Project and entity type are listed. + default_value: True entities: type: list description: "This setting defines the different tabs that will show up on the left hand side. diff --git a/python/tk_multi_workfiles/new_task_form.py b/python/tk_multi_workfiles/new_task_form.py index 263156e1..80195b69 100644 --- a/python/tk_multi_workfiles/new_task_form.py +++ b/python/tk_multi_workfiles/new_task_form.py @@ -16,6 +16,7 @@ from sgtk.platform.qt import QtCore, QtGui from .util import value_to_str +from .step_list_filter import get_steps_for_entity_type get_type_display_name = sgtk.platform.import_framework( "tk-framework-shotgunutils", "shotgun_globals" @@ -74,11 +75,11 @@ def __init__(self, entity, step, user, parent): self._ui.assigned_to.setText(username or "") # populate pipeline steps for this entity type: - sg_result = self._app.shotgun.find( - "Step", [["entity_type", "is", self._entity["type"]]], ["code", "id"] - ) + entity_type = self._entity["type"] + steps = get_steps_for_entity_type(entity_type) + self._pipeline_step_dict = {} - for item in sg_result: + for item in steps: step_name = item.get("code") if step_name is None: step_name = "Unnamed Step" diff --git a/python/tk_multi_workfiles/step_list_filter.py b/python/tk_multi_workfiles/step_list_filter.py index 24409803..8214a67c 100644 --- a/python/tk_multi_workfiles/step_list_filter.py +++ b/python/tk_multi_workfiles/step_list_filter.py @@ -58,6 +58,22 @@ def get_filter_from_filter_list(step_list): return step_filter +def get_steps_for_entity_type(entity_type): + """ + Return cached Shotgun Step dictionaries for a given Entity type. + + The list is sourced from StepListWidget's class-level cache, which + respects the app setting 'filter_by_pipeline_step_visible_only' + and the current project context. + + :param str entity_type: A Shotgun Entity type (e.g. 'Asset', 'Shot'). + :returns: List of Step dictionaries with at least 'id', 'code', + 'entity_type' and optionally 'color'. + """ + StepListWidget._cache_step_list() + return list(StepListWidget._step_list.get(entity_type, [])) + + class StepListWidget(QtCore.QObject): """ A list widget of Shotgun Pipeline steps per entity type. @@ -100,17 +116,48 @@ def _cache_step_list(cls): cached. Do nothing if they were already cached. """ if cls._step_list is None: - shotgun = sgtk.platform.current_bundle().shotgun - sg_steps = shotgun.find( - "Step", - [], - ["code", "entity_type", "color"], - order=[{"field_name": "code", "direction": "asc"}], - ) - # Build a dictionary for indexing by the entity_type + bundle = sgtk.platform.current_bundle() + shotgun = bundle.shotgun + limit_visible = bundle.get_setting("pipeline_step_filter", False) + project = getattr(bundle.context, "project", None) cls._step_list = defaultdict(list) - for sg_step in sg_steps: - cls._step_list[sg_step["entity_type"]].append(sg_step) + + if limit_visible and project: + # Build a map: entity_type -> set of step ids used by Tasks in this project + step_ids_by_entity_type = defaultdict(set) + task_filters = [ + ["project", "is", {"type": "Project", "id": project["id"]}], + ["step", "is_not", None], + ] + tasks = shotgun.find("Task", task_filters, ["step", "entity"]) + for task in tasks: + entity = task.get("entity", {}) + entity_type = entity.get("type") + step = task.get("step") + if entity_type and step: + step_ids_by_entity_type[entity_type].add(step["id"]) + + # Resolve full Step records per entity type + for entity_type, step_ids in step_ids_by_entity_type.items(): + if not step_ids: + continue + steps = shotgun.find( + "Step", + [["id", "in", list(step_ids)], ["entity_type", "is", entity_type]], + ["code", "entity_type", "color"], + order=[{"field_name": "code", "direction": "asc"}], + ) + for sg_step in steps: + cls._step_list[entity_type].append(sg_step) + else: + sg_steps = shotgun.find( + "Step", + [], + ["code", "entity_type", "color"], + order=[{"field_name": "code", "direction": "asc"}], + ) + for sg_step in sg_steps: + cls._step_list[sg_step["entity_type"]].append(sg_step) def select_all_steps(self, value=True): """ From 19c21a068dfb66cfc419f23073028a9772161765 Mon Sep 17 00:00:00 2001 From: Kuldeep Date: Fri, 12 Dec 2025 14:38:24 +0530 Subject: [PATCH 2/9] Retrieve the visible pipeline steps for project from the shotgun schema --- info.yml | 3 +- python/tk_multi_workfiles/step_list_filter.py | 107 +++++++++++------- 2 files changed, 66 insertions(+), 44 deletions(-) diff --git a/info.yml b/info.yml index 0bc3d2b9..b2ef6e1f 100644 --- a/info.yml +++ b/info.yml @@ -127,10 +127,11 @@ configuration: # General preferences # - pipeline_step_filter: + project_visible_pipeline_steps: type: bool description: If True, only Steps visible for the current Project and entity type are listed. default_value: True + entities: type: list description: "This setting defines the different tabs that will show up on the left hand side. diff --git a/python/tk_multi_workfiles/step_list_filter.py b/python/tk_multi_workfiles/step_list_filter.py index 8214a67c..bf7ac1f9 100644 --- a/python/tk_multi_workfiles/step_list_filter.py +++ b/python/tk_multi_workfiles/step_list_filter.py @@ -12,6 +12,7 @@ import sgtk from sgtk.platform.qt import QtCore, QtGui +logger = sgtk.platform.get_logger(__name__) # standard Python logger settings_fw = sgtk.platform.import_framework("tk-framework-shotgunutils", "settings") @@ -115,49 +116,69 @@ def _cache_step_list(cls): Retrieve all Steps from Shotgun and cache them, if they were not already cached. Do nothing if they were already cached. """ - if cls._step_list is None: - bundle = sgtk.platform.current_bundle() - shotgun = bundle.shotgun - limit_visible = bundle.get_setting("pipeline_step_filter", False) - project = getattr(bundle.context, "project", None) - cls._step_list = defaultdict(list) - - if limit_visible and project: - # Build a map: entity_type -> set of step ids used by Tasks in this project - step_ids_by_entity_type = defaultdict(set) - task_filters = [ - ["project", "is", {"type": "Project", "id": project["id"]}], - ["step", "is_not", None], - ] - tasks = shotgun.find("Task", task_filters, ["step", "entity"]) - for task in tasks: - entity = task.get("entity", {}) - entity_type = entity.get("type") - step = task.get("step") - if entity_type and step: - step_ids_by_entity_type[entity_type].add(step["id"]) - - # Resolve full Step records per entity type - for entity_type, step_ids in step_ids_by_entity_type.items(): - if not step_ids: - continue - steps = shotgun.find( - "Step", - [["id", "in", list(step_ids)], ["entity_type", "is", entity_type]], - ["code", "entity_type", "color"], - order=[{"field_name": "code", "direction": "asc"}], - ) - for sg_step in steps: - cls._step_list[entity_type].append(sg_step) - else: - sg_steps = shotgun.find( - "Step", - [], - ["code", "entity_type", "color"], - order=[{"field_name": "code", "direction": "asc"}], - ) - for sg_step in sg_steps: - cls._step_list[sg_step["entity_type"]].append(sg_step) + if cls._step_list is not None: + return + bundle = sgtk.platform.current_bundle() + shotgun_api = bundle.shotgun + # Use the engine's Shotgun instance for schema calls + engine_shotgun_api = sgtk.platform.current_engine().shotgun + limit_steps_to_project_visible = bundle.get_setting("project_visible_pipeline_steps", False) + current_project = getattr(bundle.context, "project", None) + # Fetch all steps once (sorted by code) and organize in-memory + all_steps = shotgun_api.find( + "Step", + [], + ["code", "entity_type", "color"], + order=[{"field_name": "code", "direction": "asc"}], + ) + should_limit_to_project_visible_steps = bool(limit_steps_to_project_visible and current_project) + if not should_limit_to_project_visible_steps: + # Simple case: cache all steps grouped by entity type + steps_by_entity_type = defaultdict(list) + for step in all_steps: + entity_type = step.get("entity_type") + steps_by_entity_type[entity_type].append(step) + cls._step_list = steps_by_entity_type + return + # Limit to steps visible in the current project's schema + # Build lookup: entity_type -> { code -> step } + steps_by_entity_and_code = defaultdict(dict) + for step in all_steps: + code = step.get("code") + if code: + entity_type = step.get("entity_type") + steps_by_entity_and_code[entity_type][code] = step + cls._step_list = defaultdict(list) + project_entity = {"type": "Project", "id": current_project["id"]} + for entity_type, step_lookup_by_code in steps_by_entity_and_code.items(): + schema_fields = engine_shotgun_api.schema_field_read( + entity_type, + project_entity=project_entity, + ) + # Collect visible pipeline step codes from schema (fields named step_*) + visible_step_codes = [] + for field_name, field_schema in schema_fields.items(): + step_name = field_schema.get("name", {}).get("value") + is_field_visible = field_schema.get("visible", {}).get("value") + if ( + field_name.startswith("step_") + and is_field_visible + and step_name + and step_name != "ALL TASKS" + ): + visible_step_codes.append(step_name) + if not visible_step_codes: + continue + # Filter in-memory to avoid additional network calls, keep sort by code + visible_steps = [ + step_lookup_by_code[step_code] + for step_code in visible_step_codes + if step_code in step_lookup_by_code + ] + if not visible_steps: + continue + visible_steps.sort(key=lambda x: x.get("code") or "") + cls._step_list[entity_type].extend(visible_steps) def select_all_steps(self, value=True): """ From 908b53b974382e19c5e60bf342124801523d9936 Mon Sep 17 00:00:00 2001 From: Kuldeep Date: Fri, 12 Dec 2025 14:40:01 +0530 Subject: [PATCH 3/9] removed logger import --- python/tk_multi_workfiles/step_list_filter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/tk_multi_workfiles/step_list_filter.py b/python/tk_multi_workfiles/step_list_filter.py index bf7ac1f9..12eaeae0 100644 --- a/python/tk_multi_workfiles/step_list_filter.py +++ b/python/tk_multi_workfiles/step_list_filter.py @@ -12,7 +12,6 @@ import sgtk from sgtk.platform.qt import QtCore, QtGui -logger = sgtk.platform.get_logger(__name__) # standard Python logger settings_fw = sgtk.platform.import_framework("tk-framework-shotgunutils", "settings") From 5a480446268fbcd88c019f9dba9f771e9a9ba818 Mon Sep 17 00:00:00 2001 From: Kuldeep Date: Fri, 12 Dec 2025 15:34:43 +0530 Subject: [PATCH 4/9] updated default value for the visible pipeline step --- info.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info.yml b/info.yml index b2ef6e1f..80a042b8 100644 --- a/info.yml +++ b/info.yml @@ -130,7 +130,7 @@ configuration: project_visible_pipeline_steps: type: bool description: If True, only Steps visible for the current Project and entity type are listed. - default_value: True + default_value: False entities: type: list From 14e75be7531090eaeb902e152cd4582d6059f8b6 Mon Sep 17 00:00:00 2001 From: Kuldeep Date: Fri, 12 Dec 2025 15:59:19 +0530 Subject: [PATCH 5/9] updated description in info --- info.yml | 4 ++-- python/tk_multi_workfiles/step_list_filter.py | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/info.yml b/info.yml index 80a042b8..80a0e5e5 100644 --- a/info.yml +++ b/info.yml @@ -129,9 +129,9 @@ configuration: # project_visible_pipeline_steps: type: bool - description: If True, only Steps visible for the current Project and entity type are listed. + description: If True, only pipeline Steps visible for the current Project and entity type are listed. default_value: False - + entities: type: list description: "This setting defines the different tabs that will show up on the left hand side. diff --git a/python/tk_multi_workfiles/step_list_filter.py b/python/tk_multi_workfiles/step_list_filter.py index 12eaeae0..45f6b184 100644 --- a/python/tk_multi_workfiles/step_list_filter.py +++ b/python/tk_multi_workfiles/step_list_filter.py @@ -117,11 +117,14 @@ def _cache_step_list(cls): """ if cls._step_list is not None: return + bundle = sgtk.platform.current_bundle() shotgun_api = bundle.shotgun # Use the engine's Shotgun instance for schema calls engine_shotgun_api = sgtk.platform.current_engine().shotgun - limit_steps_to_project_visible = bundle.get_setting("project_visible_pipeline_steps", False) + limit_steps_to_project_visible = bundle.get_setting( + "project_visible_pipeline_steps", False + ) current_project = getattr(bundle.context, "project", None) # Fetch all steps once (sorted by code) and organize in-memory all_steps = shotgun_api.find( @@ -130,7 +133,9 @@ def _cache_step_list(cls): ["code", "entity_type", "color"], order=[{"field_name": "code", "direction": "asc"}], ) - should_limit_to_project_visible_steps = bool(limit_steps_to_project_visible and current_project) + should_limit_to_project_visible_steps = bool( + limit_steps_to_project_visible and current_project + ) if not should_limit_to_project_visible_steps: # Simple case: cache all steps grouped by entity type steps_by_entity_type = defaultdict(list) From 7b59545baf37156bcfb7759011ec810eb55b8f6e Mon Sep 17 00:00:00 2001 From: Kuldeep Date: Sun, 14 Dec 2025 17:31:59 +0530 Subject: [PATCH 6/9] created separate step cache to get the step values based upon the context --- python/tk_multi_workfiles/step_list_filter.py | 155 +++++++++--------- 1 file changed, 81 insertions(+), 74 deletions(-) diff --git a/python/tk_multi_workfiles/step_list_filter.py b/python/tk_multi_workfiles/step_list_filter.py index 45f6b184..5d5dea83 100644 --- a/python/tk_multi_workfiles/step_list_filter.py +++ b/python/tk_multi_workfiles/step_list_filter.py @@ -62,118 +62,88 @@ def get_steps_for_entity_type(entity_type): """ Return cached Shotgun Step dictionaries for a given Entity type. - The list is sourced from StepListWidget's class-level cache, which - respects the app setting 'filter_by_pipeline_step_visible_only' - and the current project context. + The list is sourced from the StepCache, which respects the + 'project_visible_pipeline_steps' app setting and the current project context. :param str entity_type: A Shotgun Entity type (e.g. 'Asset', 'Shot'). :returns: List of Step dictionaries with at least 'id', 'code', 'entity_type' and optionally 'color'. """ - StepListWidget._cache_step_list() - return list(StepListWidget._step_list.get(entity_type, [])) + StepCache.ensure_loaded() + return list(StepCache.get_step_map().get(entity_type, [])) -class StepListWidget(QtCore.QObject): +class StepCache(object): """ - A list widget of Shotgun Pipeline steps per entity type. + Cache Shotgun Pipeline Steps per entity type. """ - _step_list = None - step_filter_changed = QtCore.Signal(object) # List of PTR step dictionaries - - def __init__(self, list_widget): - """ - Instantiate a StepListWidget, collect all Pipeline steps from Shotgun if - they are not already cached. - - :param list_widget: A :class:`QtGui.QListWidget` instance. It is assumed - it has a direct QWidget parent which can be shown or - hidden when showing steps for a given Entity type is - needed or not needed. - """ - super().__init__() - self._list_widget = list_widget - self._cache_step_list() - self._step_widgets = defaultdict(list) - saved_filters = load_step_filters() - # Keep track of filters being changed to only save them if they were - # changed. - self._step_filters_changed = False - if saved_filters is None: - # Settings were never saved before. Select all exsiting steps by - # default. - self._current_filter_step_ids = set() - for step_list in self._step_list.values(): - self._current_filter_step_ids.update([x["id"] for x in step_list]) - else: - self._current_filter_step_ids = set([x["id"] for x in load_step_filters()]) + _step_map = None @classmethod - def _cache_step_list(cls): + def ensure_loaded(cls): """ - Retrieve all Steps from Shotgun and cache them, if they were not already - cached. Do nothing if they were already cached. + Populate the cache for the current context/settings. + Computes a step map on accordingly. """ - if cls._step_list is not None: - return - bundle = sgtk.platform.current_bundle() - shotgun_api = bundle.shotgun - # Use the engine's Shotgun instance for schema calls - engine_shotgun_api = sgtk.platform.current_engine().shotgun - limit_steps_to_project_visible = bundle.get_setting( - "project_visible_pipeline_steps", False - ) - current_project = getattr(bundle.context, "project", None) - # Fetch all steps once (sorted by code) and organize in-memory - all_steps = shotgun_api.find( + all_steps = bundle.shotgun.find( "Step", [], ["code", "entity_type", "color"], order=[{"field_name": "code", "direction": "asc"}], ) - should_limit_to_project_visible_steps = bool( - limit_steps_to_project_visible and current_project - ) - if not should_limit_to_project_visible_steps: - # Simple case: cache all steps grouped by entity type - steps_by_entity_type = defaultdict(list) + project = bundle.context.project + if project and bundle.get_setting("project_visible_pipeline_steps", False): + step_map = cls._build_project_visible_steps( + all_steps, project["id"], sgtk.platform.current_engine().shotgun + ) + else: + step_map = defaultdict(list) for step in all_steps: - entity_type = step.get("entity_type") - steps_by_entity_type[entity_type].append(step) - cls._step_list = steps_by_entity_type - return - # Limit to steps visible in the current project's schema + step_map[step.get("entity_type")].append(step) + cls._step_map = step_map + + @classmethod + def get_step_map(cls): + """ + Return the cached mapping: entity_type -> list of step dicts. + """ + if cls._step_map is None: + cls.ensure_loaded() + return cls._step_map + + @classmethod + def _build_project_visible_steps(cls, all_steps, project_id, engine_shotgun_api): + """ + Build entity_type -> visible steps mapping for a project. + """ # Build lookup: entity_type -> { code -> step } steps_by_entity_and_code = defaultdict(dict) for step in all_steps: - code = step.get("code") - if code: - entity_type = step.get("entity_type") - steps_by_entity_and_code[entity_type][code] = step - cls._step_list = defaultdict(list) - project_entity = {"type": "Project", "id": current_project["id"]} + if step.get("code"): + steps_by_entity_and_code[step.get("entity_type")][ + step.get("code") + ] = step + step_map = defaultdict(list) for entity_type, step_lookup_by_code in steps_by_entity_and_code.items(): schema_fields = engine_shotgun_api.schema_field_read( entity_type, - project_entity=project_entity, + project_entity={"type": "Project", "id": project_id}, ) - # Collect visible pipeline step codes from schema (fields named step_*) visible_step_codes = [] for field_name, field_schema in schema_fields.items(): step_name = field_schema.get("name", {}).get("value") - is_field_visible = field_schema.get("visible", {}).get("value") + is_visible = field_schema.get("visible", {}).get("value") if ( field_name.startswith("step_") - and is_field_visible + and is_visible and step_name and step_name != "ALL TASKS" ): visible_step_codes.append(step_name) if not visible_step_codes: continue - # Filter in-memory to avoid additional network calls, keep sort by code visible_steps = [ step_lookup_by_code[step_code] for step_code in visible_step_codes @@ -182,7 +152,44 @@ def _cache_step_list(cls): if not visible_steps: continue visible_steps.sort(key=lambda x: x.get("code") or "") - cls._step_list[entity_type].extend(visible_steps) + step_map[entity_type].extend(visible_steps) + return step_map + + +class StepListWidget(QtCore.QObject): + """ + A list widget of Shotgun Pipeline steps per entity type. + """ + + step_filter_changed = QtCore.Signal(object) # List of PTR step dictionaries + + def __init__(self, list_widget): + """ + Instantiate a StepListWidget, collect all Pipeline steps from Shotgun if + they are not already cached. + + :param list_widget: A :class:`QtGui.QListWidget` instance. It is assumed + it has a direct QWidget parent which can be shown or + hidden when showing steps for a given Entity type is + needed or not needed. + """ + super().__init__() + self._list_widget = list_widget + StepCache.ensure_loaded() + self._step_list = StepCache.get_step_map() + self._step_widgets = defaultdict(list) + saved_filters = load_step_filters() + # Keep track of filters being changed to only save them if they were + # changed. + self._step_filters_changed = False + if saved_filters is None: + # Settings were never saved before. Select all exsiting steps by + # default. + self._current_filter_step_ids = set() + for step_list in self._step_list.values(): + self._current_filter_step_ids.update([x["id"] for x in step_list]) + else: + self._current_filter_step_ids = set([x["id"] for x in load_step_filters()]) def select_all_steps(self, value=True): """ From b0ee25bfaf8c1a4f7733fd0b70671dba577e8fea Mon Sep 17 00:00:00 2001 From: Kuldeep Date: Sun, 14 Dec 2025 17:48:35 +0530 Subject: [PATCH 7/9] updated discription for the project_visible_pipeline_steps flag --- info.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/info.yml b/info.yml index 80a0e5e5..59ac36f2 100644 --- a/info.yml +++ b/info.yml @@ -129,9 +129,10 @@ configuration: # project_visible_pipeline_steps: type: bool - description: If True, only pipeline Steps visible for the current Project and entity type are listed. default_value: False - + description: If True, pipeline steps marked visible for the current project are available and listed. + This flag is used to filter pipeline steps in the File Open dialog and the Create + New Task dropdown. When False, all pipeline steps will be available. entities: type: list description: "This setting defines the different tabs that will show up on the left hand side. From b215a2237804d4f8613991e497aa1e5f85339ec2 Mon Sep 17 00:00:00 2001 From: Kuldeep Date: Thu, 18 Dec 2025 17:30:21 +0530 Subject: [PATCH 8/9] moved step caching to the shotgunutils --- python/tk_multi_workfiles/step_list_filter.py | 117 +++++------------- 1 file changed, 31 insertions(+), 86 deletions(-) diff --git a/python/tk_multi_workfiles/step_list_filter.py b/python/tk_multi_workfiles/step_list_filter.py index 5d5dea83..0e1143d8 100644 --- a/python/tk_multi_workfiles/step_list_filter.py +++ b/python/tk_multi_workfiles/step_list_filter.py @@ -14,6 +14,9 @@ from sgtk.platform.qt import QtCore, QtGui settings_fw = sgtk.platform.import_framework("tk-framework-shotgunutils", "settings") +shotgun_globals = sgtk.platform.import_framework( + "tk-framework-shotgunutils", "shotgun_globals" +) # Settings name to save the Step filter list _STEP_FILTERS_USER_SETTING = "step_filters" @@ -60,100 +63,43 @@ def get_filter_from_filter_list(step_list): def get_steps_for_entity_type(entity_type): """ - Return cached Shotgun Step dictionaries for a given Entity type. + Return cached Flow Production Tracking (ShotGrid) Step dictionaries for a given Entity type. - The list is sourced from the StepCache, which respects the - 'project_visible_pipeline_steps' app setting and the current project context. + The list is sourced from the framework's schema cache + (`CachedShotgunSchema.get_pipeline_steps_by_entity_type`) and respects the + `project_visible_pipeline_steps` app setting and the current project context. + When project visibility is enabled, only Steps exposed via project schema + 'step_*' fields are included. :param str entity_type: A Shotgun Entity type (e.g. 'Asset', 'Shot'). - :returns: List of Step dictionaries with at least 'id', 'code', - 'entity_type' and optionally 'color'. + :returns: List of Step dictionaries with at least 'id', 'code', 'entity_type' + and optionally 'color'. Returns an empty list if none are available. """ - StepCache.ensure_loaded() - return list(StepCache.get_step_map().get(entity_type, [])) + return list(get_step_map().get(entity_type, [])) -class StepCache(object): +def get_step_map(): """ - Cache Shotgun Pipeline Steps per entity type. - """ - - _step_map = None + Return the cached mapping of entity_type -> list of Step dictionaries. - @classmethod - def ensure_loaded(cls): - """ - Populate the cache for the current context/settings. - Computes a step map on accordingly. - """ - bundle = sgtk.platform.current_bundle() - all_steps = bundle.shotgun.find( - "Step", - [], - ["code", "entity_type", "color"], - order=[{"field_name": "code", "direction": "asc"}], - ) - project = bundle.context.project - if project and bundle.get_setting("project_visible_pipeline_steps", False): - step_map = cls._build_project_visible_steps( - all_steps, project["id"], sgtk.platform.current_engine().shotgun - ) - else: - step_map = defaultdict(list) - for step in all_steps: - step_map[step.get("entity_type")].append(step) - cls._step_map = step_map + The mapping is provided by + `CachedShotgunSchema.get_pipeline_steps_by_entity_type`, scoped to the current + project (when available) and the `project_visible_pipeline_steps` app setting. + Each Step dict contains at least: 'id', 'code', 'entity_type', and may include + 'color'. - @classmethod - def get_step_map(cls): - """ - Return the cached mapping: entity_type -> list of step dicts. - """ - if cls._step_map is None: - cls.ensure_loaded() - return cls._step_map + :returns: dict mapping entity type (str) to a list of Step dictionaries. + """ + bundle = sgtk.platform.current_bundle() + project = bundle.context.project + limit_to_project_visible = bundle.get_setting( + "project_visible_pipeline_steps", False + ) - @classmethod - def _build_project_visible_steps(cls, all_steps, project_id, engine_shotgun_api): - """ - Build entity_type -> visible steps mapping for a project. - """ - # Build lookup: entity_type -> { code -> step } - steps_by_entity_and_code = defaultdict(dict) - for step in all_steps: - if step.get("code"): - steps_by_entity_and_code[step.get("entity_type")][ - step.get("code") - ] = step - step_map = defaultdict(list) - for entity_type, step_lookup_by_code in steps_by_entity_and_code.items(): - schema_fields = engine_shotgun_api.schema_field_read( - entity_type, - project_entity={"type": "Project", "id": project_id}, - ) - visible_step_codes = [] - for field_name, field_schema in schema_fields.items(): - step_name = field_schema.get("name", {}).get("value") - is_visible = field_schema.get("visible", {}).get("value") - if ( - field_name.startswith("step_") - and is_visible - and step_name - and step_name != "ALL TASKS" - ): - visible_step_codes.append(step_name) - if not visible_step_codes: - continue - visible_steps = [ - step_lookup_by_code[step_code] - for step_code in visible_step_codes - if step_code in step_lookup_by_code - ] - if not visible_steps: - continue - visible_steps.sort(key=lambda x: x.get("code") or "") - step_map[entity_type].extend(visible_steps) - return step_map + return shotgun_globals.cached_schema.CachedShotgunSchema.get_pipeline_steps_by_entity_type( + limit_to_project_visible=bool(project and limit_to_project_visible), + project_id=project["id"] if project else None, + ) class StepListWidget(QtCore.QObject): @@ -175,8 +121,7 @@ def __init__(self, list_widget): """ super().__init__() self._list_widget = list_widget - StepCache.ensure_loaded() - self._step_list = StepCache.get_step_map() + self._step_list = get_step_map() self._step_widgets = defaultdict(list) saved_filters = load_step_filters() # Keep track of filters being changed to only save them if they were From 0bea234975383199336cee0062a7994fe4481717 Mon Sep 17 00:00:00 2001 From: Kuldeep Date: Thu, 18 Dec 2025 20:33:06 +0530 Subject: [PATCH 9/9] renamed function and updated scope --- python/tk_multi_workfiles/step_list_filter.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/tk_multi_workfiles/step_list_filter.py b/python/tk_multi_workfiles/step_list_filter.py index 0e1143d8..dc6dcc15 100644 --- a/python/tk_multi_workfiles/step_list_filter.py +++ b/python/tk_multi_workfiles/step_list_filter.py @@ -75,12 +75,12 @@ def get_steps_for_entity_type(entity_type): :returns: List of Step dictionaries with at least 'id', 'code', 'entity_type' and optionally 'color'. Returns an empty list if none are available. """ - return list(get_step_map().get(entity_type, [])) + return list(_get_entity_type_to_steps_map().get(entity_type, [])) -def get_step_map(): +def _get_entity_type_to_steps_map(): """ - Return the cached mapping of entity_type -> list of Step dictionaries. + Return the cached mapping: entity_type -> list of Step dictionaries. The mapping is provided by `CachedShotgunSchema.get_pipeline_steps_by_entity_type`, scoped to the current @@ -121,7 +121,7 @@ def __init__(self, list_widget): """ super().__init__() self._list_widget = list_widget - self._step_list = get_step_map() + self._step_list = _get_entity_type_to_steps_map() self._step_widgets = defaultdict(list) saved_filters = load_step_filters() # Keep track of filters being changed to only save them if they were