diff --git a/gazu/playlist.py b/gazu/playlist.py index 805aaaf..831c332 100644 --- a/gazu/playlist.py +++ b/gazu/playlist.py @@ -228,12 +228,14 @@ def add_entity_to_playlist( if preview_file is not None: entry["preview_file_id"] = preview_file["id"] + if playlist.get("shots") is None: + playlist["shots"] = [] playlist["shots"].append(entry) if persist: playlist = raw.post( - f"actions/playlists/{playlist['id']}/add-entity", + f"actions/playlists/{playlist['id']}/add-entity", entry, - client=client + client=client, ) return playlist diff --git a/gazu/project.py b/gazu/project.py index 0a498cb..be84238 100644 --- a/gazu/project.py +++ b/gazu/project.py @@ -519,6 +519,39 @@ def remove_metadata_descriptor( ) +def reorder_metadata_descriptors( + project: str | dict, + entity_type: str, + descriptor_ids: list[str | dict], + client: KitsuClient = default, +) -> list[dict]: + """ + Reorder metadata descriptors for a given entity type. Position is set + according to the order of ids in the list. + + Args: + project (dict / ID): The project dict or id. + entity_type (str): One of "Asset", "Shot", "Edit", "Episode", + "Sequence", "Project". + descriptor_ids (list): The descriptors (ids or dicts) in the + desired order. + + Returns: + list: The reordered metadata descriptors. + """ + project = normalize_model_parameter(project) + return raw.post( + f"data/projects/{project['id']}/metadata-descriptors/reorder", + { + "entity_type": entity_type, + "descriptor_ids": normalize_list_of_models_for_links( + descriptor_ids + ), + }, + client=client, + ) + + def get_team(project: str | dict, client: KitsuClient = default) -> list[dict]: """ Get team for project. diff --git a/tests/test_playlist.py b/tests/test_playlist.py index 813cf22..a4277bc 100644 --- a/tests/test_playlist.py +++ b/tests/test_playlist.py @@ -260,6 +260,51 @@ def test_add_entity_to_playlist(self): ) self.assertEqual(playlist["shots"], []) + def test_add_entity_to_playlist_with_null_shots(self): + """Regression test for #386: a fresh playlist has shots=None.""" + with requests_mock.mock() as mock: + mock.get( + gazu.client.get_full_url( + f"data/playlists/entities/{fakeid('shot-1')}/preview-files" + ), + text=json.dumps({}), + ) + mock.post( + gazu.client.get_full_url( + f"actions/playlists/{fakeid('playlist-1')}/add-entity" + ), + text=json.dumps( + { + "id": fakeid("playlist-1"), + "shots": [{"entity_id": fakeid("shot-1")}], + } + ), + ) + playlist = {"id": fakeid("playlist-1"), "shots": None} + shot = {"id": fakeid("shot-1")} + playlist = gazu.playlist.add_entity_to_playlist(playlist, shot) + self.assertEqual( + playlist["shots"], [{"entity_id": fakeid("shot-1")}] + ) + + def test_add_entity_to_playlist_no_persist_with_null_shots(self): + """Without persist=True, the local dict must still be usable.""" + playlist = {"id": fakeid("playlist-1"), "shots": None} + shot = {"id": fakeid("shot-1")} + with requests_mock.mock() as mock: + mock.get( + gazu.client.get_full_url( + f"data/playlists/entities/{fakeid('shot-1')}/preview-files" + ), + text=json.dumps({}), + ) + playlist = gazu.playlist.add_entity_to_playlist( + playlist, shot, persist=False + ) + self.assertEqual( + playlist["shots"], [{"entity_id": fakeid("shot-1")}] + ) + def test_delete_playlist(self): with requests_mock.mock() as mock: mock.delete( diff --git a/tests/test_project.py b/tests/test_project.py index e1c3534..9c97f43 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -429,6 +429,43 @@ def test_remove_metadata_descriptor(self): ) self.assertEqual(response, "") + def test_reorder_metadata_descriptors(self): + with requests_mock.mock() as mock: + mock_route( + mock, + "POST", + f"data/projects/{fakeid('project-1')}/metadata-descriptors/reorder", + text=[ + { + "id": fakeid("metadata-descriptor-1"), + "position": 1, + }, + { + "id": fakeid("metadata-descriptor-2"), + "position": 2, + }, + ], + ) + result = gazu.project.reorder_metadata_descriptors( + fakeid("project-1"), + "Shot", + [ + fakeid("metadata-descriptor-1"), + {"id": fakeid("metadata-descriptor-2")}, + ], + ) + self.assertEqual(len(result), 2) + self.assertEqual( + mock.last_request.json(), + { + "entity_type": "Shot", + "descriptor_ids": [ + fakeid("metadata-descriptor-1"), + fakeid("metadata-descriptor-2"), + ], + }, + ) + def test_add_task_status(self): with requests_mock.mock() as mock: mock_route(