Skip to content

pipeline

Mocha Pro AYON pipeline API.

Notes

PLR6301 (can be static method, class method or function) is used there because the parent class IWorkfileHost has different signatures.

AYONJSONEncoder

Bases: JSONEncoder

Custom JSON encoder for dataclasses.

Source code in client/ayon_mocha/api/pipeline.py
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class AYONJSONEncoder(json.JSONEncoder):
    """Custom JSON encoder for dataclasses."""

    def default(self, obj: object) -> Union[dict, object]:
        """Encode dataclasses as dict.

        Args:
            obj (object): Object to encode.

        Returns:
            Union[dict, object]: Encoded object.

        """
        if dataclasses.is_dataclass(obj):
            return dataclasses.asdict(obj)  # type: ignore[arg-type]
        if isinstance(obj, CreatedInstance):
            return dict(obj)
        return super().default(obj)

default(obj)

Encode dataclasses as dict.

Parameters:

Name Type Description Default
obj object

Object to encode.

required

Returns:

Type Description
Union[dict, object]

Union[dict, object]: Encoded object.

Source code in client/ayon_mocha/api/pipeline.py
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def default(self, obj: object) -> Union[dict, object]:
    """Encode dataclasses as dict.

    Args:
        obj (object): Object to encode.

    Returns:
        Union[dict, object]: Encoded object.

    """
    if dataclasses.is_dataclass(obj):
        return dataclasses.asdict(obj)  # type: ignore[arg-type]
    if isinstance(obj, CreatedInstance):
        return dict(obj)
    return super().default(obj)

Container dataclass

Container data class.

Source code in client/ayon_mocha/api/pipeline.py
86
87
88
89
90
91
92
93
94
95
96
97
@dataclasses.dataclass
class Container:
    """Container data class."""

    name: Optional[str] = None
    id: str = AYON_CONTAINER_ID
    namespace: str = ""
    loader: Optional[str] = None
    representation: Optional[str] = None
    objectName: Optional[str] = None  # noqa: N815
    timestamp: int = 0
    version: Optional[str] = None

MochaProHost

Bases: HostBase, IWorkfileHost, ILoadHost, IPublishHost

Mocha Pro host implementation.

Source code in client/ayon_mocha/api/pipeline.py
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
class MochaProHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
    """Mocha Pro host implementation."""

    name = "mochapro"
    _uninitialized_project_warning_shown = False

    def install(self) -> None:
        """Initialize the host."""
        pyblish.api.register_host(self.name)
        pyblish.api.register_plugin_path(PUBLISH_PATH.as_posix())
        register_loader_plugin_path(LOAD_PATH.as_posix())
        register_creator_plugin_path(CREATE_PATH.as_posix())

        # QtCore.QTimer.singleShot(0, self._install_menu)
        self._install_menu()

    def _install_menu(self) -> None:
        """Install the menu."""
        main_window = get_main_window()

        menu_label = os.getenv("AYON_MENU_LABEL", "AYON")
        menu = main_window.menuBar().addMenu(menu_label)

        action = menu.addAction("Current Context")

        def _on_menu_about_to_show(menu_action: QtWidgets.QAction) -> None:
            """Update the menu."""
            context = self.get_current_context()
            menu_action.setText(
                f"{context['folder_path']}, {context['task_name']}")

        action.setEnabled(False)
        menu.aboutToShow.connect(partial(_on_menu_about_to_show, action))
        menu.addSeparator()

        action = menu.addAction("Create...")
        action.triggered.connect(
            lambda: host_tools.show_publisher(
                parent=main_window, tab="create"))

        action = menu.addAction("Load...")
        action.triggered.connect(
            lambda: host_tools.show_loader(
                parent=main_window, use_context=True))

        action = menu.addAction("Publish...")
        action.triggered.connect(
            lambda: host_tools.show_publisher(
                parent=main_window, tab="publish"))

        action = menu.addAction("Manage...")
        action.triggered.connect(
            lambda: host_tools.show_scene_inventory(parent=main_window))

        action = menu.addAction("Library...")
        action.triggered.connect(
            lambda: host_tools.show_library_loader(parent=main_window))

        menu.addSeparator()

        action = menu.addAction("Work Files...")
        action.triggered.connect(
            lambda: host_tools.show_workfiles(parent=main_window))

        menu.addSeparator()

        action = menu.addAction("Reset Frame Range and FPS")
        action.triggered.connect(
            lambda: reset_frame_range(self.get_current_project()))

        menu.addSeparator()

        action = menu.addAction("Experimental Tools...")
        action.triggered.connect(
            lambda: host_tools.show_experimental_tools_dialog(
                parent=main_window))

    def get_workfile_extensions(self) -> list[str]:  # noqa: PLR6301
        """Get the workfile extensions.

        Returns:
            list[str]: Workfile extensions.

        """
        return file_extensions()

    def save_workfile(self, dst_path: Optional[str] = None) -> None:  # noqa: PLR6301
        """Save the workfile.

        Args:
            dst_path (str, optional): The destination path to save the file to.
                Defaults to None.

        Todo (antirotor): This needs to display error if the project
            isn't initialized yet.
            https://github.com/ynput/ayon-core/issues/1075

        """
        if dst_path:
            save_file(Path(dst_path))
        else:
            save_file(filepath=None)
        if not _get_current_project():
            reset_frame_range(_get_current_project())

    def open_workfile(self, filepath: str) -> None:  # noqa: PLR6301
        """Open the workfile."""
        open_file(Path(filepath))

    def get_current_workfile(self) -> Optional[str]:  # noqa: PLR6301
        """Get the current workfile.

        Returns:
            Optional[str]: The current workfile.

        """
        file_path = current_file()
        return file_path.as_posix() if file_path else None

    def get_containers(self) -> Generator[dict, None, list]:
        """Get containers from the current workfile.

        Yields:
            Generator: Container data.

        """
        # sourcery skip: use-named-expression
        data = self.get_ayon_data()
        if data:
            yield from data.get(MOCHA_CONTAINERS_KEY, [])
        yield {}

    def add_container(self, container: Container) -> None:
        """Add a container to the current workfile.

        Args:
            container (Container): Container to add.

        """
        data = self.get_ayon_data()
        containers_dicts = list(self.get_containers())
        containers = [
            Container(**_container) for _container in containers_dicts
        ]
        to_remove = [
            idx
            for idx, _container in enumerate(containers)
            if _container.name == container.name
            and _container.namespace == container.namespace
        ]
        for idx in reversed(to_remove):
            containers.pop(idx)

        data[MOCHA_CONTAINERS_KEY] = [
            *containers, dataclasses.asdict(container)]

        self.update_ayon_data(data)

    def remove_container(self, container: Container) -> None:
        """Remove a container from the current workfile.

        Args:
            container (Container): Container to remove.

        """
        data = self.get_ayon_data()
        containers_dicts = list(self.get_containers())
        containers = [
            Container(**_container) for _container in containers_dicts
        ]
        to_remove = [
            idx
            for idx, _container in enumerate(containers)
            if _container.name == container.name
            and _container.namespace == container.namespace
        ]
        for idx in reversed(to_remove):
            containers.pop(idx)

        data[MOCHA_CONTAINERS_KEY] = [
            dataclasses.asdict(_container) for _container in containers]

        self.update_ayon_data(data)

    def _create_ayon_data(self) -> None:
        """Create AYON data in the current project."""
        project = self.get_current_project()
        project.notes = (
            f"{project.notes}\n"
            f"{AYON_METADATA_GUARD}\n")

    def get_ayon_data(self) -> dict:
        """Get AYON context data from the current project.

        Mocha Pro doesn't have any custom node or other
        place to store metadata, so we store context data in
        the project notes encoded as JSON and wrapped in a
        special guard string `AYON_CONTEXT::...::AYON_CONTEXT_END`.

        Returns:
            dict: Context data.

        """
        # sourcery skip: use-named-expression
        project = self.get_current_project()
        m = re.search(AYON_METADATA_REGEX, project.notes)
        if not m:
            self._create_ayon_data()
            return {}
        try:
            context = json.loads(m["context"]) if m else {}
        except ValueError:
            self.log.debug("AYON data is not valid json")
            # AYON data not found or invalid, create empty placeholder
            self._create_ayon_data()
            return {}

        return context

    def update_ayon_data(self, data: dict) -> None:
        """Update AYON context data in the current project.

        Serialize context data as json and store it in the
        project notes. If the context data is not found, create
        a placeholder there. See `get_context_data` for more info.

        Args:
            data (dict): Context data.

        """
        project = self.get_current_project()
        original_data = self.get_ayon_data()

        updated_data = original_data.copy()
        updated_data.update(data)
        update_str = json.dumps(
            updated_data or {}, indent=4, cls=AYONJSONEncoder)

        project.notes = re.sub(
                AYON_METADATA_REGEX,
                AYON_METADATA_GUARD.format(update_str),
                project.notes,
            )
        update_ui()

    def get_context_data(self) -> dict:
        """Get context data from the current project.

        Returns:
            dict: Context data.

        """
        data = self.get_ayon_data()

        return data.get(MOCHA_CONTEXT_KEY, {})

    def update_context_data(
            self, data: dict, changes: dict) -> None:
        """Update context data in the current project.

        Args:
            data (dict): Context data.
            changes (dict): Changes to the context data.

        """
        if not data:
            return
        ayon_data = self.get_ayon_data()
        ayon_data[MOCHA_CONTEXT_KEY] = data
        self.update_ayon_data(ayon_data)

    def get_publish_instances(self) -> list[dict]:
        """Get publish instances from the current project.

        Returns:
            list[dict]: Publish instances.

        """
        data = self.get_ayon_data()
        return data.get(MOCHA_INSTANCES_KEY, [])

    def add_publish_instance(self, instance_data: dict) -> None:
        """Add a publish instance to the current project.

        Args:
            instance_data (dict): Publish instance to add.

        """
        data = self.get_ayon_data()
        publish_instances = self.get_publish_instances()
        publish_instances.append(instance_data)
        data[MOCHA_INSTANCES_KEY] = publish_instances

        self.update_ayon_data(data)

    def update_publish_instance(
            self,
            instance_id: str,
            data: dict,
    ) -> None:
        """Update a publish instance in the current project.

        Args:
            instance_id (str): Publish instance id to update.
            data (dict): Data to update.

        """
        ayon_data = self.get_ayon_data()
        publish_instances = self.get_publish_instances()
        for idx, publish_instance in enumerate(publish_instances):
            if publish_instance["instance_id"] == instance_id:
                publish_instances[idx] = data
                break
        ayon_data[MOCHA_INSTANCES_KEY] = publish_instances

        self.update_ayon_data(ayon_data)

    def write_create_instances(
            self, instances: list[dict]) -> None:
        """Write publish instances to the current project."""
        ayon_data = self.get_ayon_data()
        ayon_data[MOCHA_INSTANCES_KEY] = instances
        self.update_ayon_data(ayon_data)

    def remove_create_instance(self, instance_id: str) -> None:
        """Remove a publishing instance from the current project.

        Args:
            instance_id (str): Publish instance id to remove.

        """
        data = self.get_ayon_data()
        publish_instances = self.get_publish_instances()
        publish_instances = [
            publish_instance
            for publish_instance in publish_instances
            if publish_instance["instance_id"] != instance_id
        ]
        data[MOCHA_INSTANCES_KEY] = publish_instances

        self.update_ayon_data(data)

    def get_current_project(self) -> Project:
        """Return the current project."""
        project = _get_current_project()
        if not project:
            if not self._uninitialized_project_warning_shown:
                show_message_dialog(
                    "No project is opened.",
                    (
                        "Please open or save a project first, otherwise "
                        "you won't be able to see the results of any "
                        "operations you'll make."
                    ),
                    parent=get_main_window(),
                )
                self._uninitialized_project_warning_shown = True
            return create_empty_project()
        return project

add_container(container)

Add a container to the current workfile.

Parameters:

Name Type Description Default
container Container

Container to add.

required
Source code in client/ayon_mocha/api/pipeline.py
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
def add_container(self, container: Container) -> None:
    """Add a container to the current workfile.

    Args:
        container (Container): Container to add.

    """
    data = self.get_ayon_data()
    containers_dicts = list(self.get_containers())
    containers = [
        Container(**_container) for _container in containers_dicts
    ]
    to_remove = [
        idx
        for idx, _container in enumerate(containers)
        if _container.name == container.name
        and _container.namespace == container.namespace
    ]
    for idx in reversed(to_remove):
        containers.pop(idx)

    data[MOCHA_CONTAINERS_KEY] = [
        *containers, dataclasses.asdict(container)]

    self.update_ayon_data(data)

add_publish_instance(instance_data)

Add a publish instance to the current project.

Parameters:

Name Type Description Default
instance_data dict

Publish instance to add.

required
Source code in client/ayon_mocha/api/pipeline.py
381
382
383
384
385
386
387
388
389
390
391
392
393
def add_publish_instance(self, instance_data: dict) -> None:
    """Add a publish instance to the current project.

    Args:
        instance_data (dict): Publish instance to add.

    """
    data = self.get_ayon_data()
    publish_instances = self.get_publish_instances()
    publish_instances.append(instance_data)
    data[MOCHA_INSTANCES_KEY] = publish_instances

    self.update_ayon_data(data)

get_ayon_data()

Get AYON context data from the current project.

Mocha Pro doesn't have any custom node or other place to store metadata, so we store context data in the project notes encoded as JSON and wrapped in a special guard string AYON_CONTEXT::...::AYON_CONTEXT_END.

Returns:

Name Type Description
dict dict

Context data.

Source code in client/ayon_mocha/api/pipeline.py
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
def get_ayon_data(self) -> dict:
    """Get AYON context data from the current project.

    Mocha Pro doesn't have any custom node or other
    place to store metadata, so we store context data in
    the project notes encoded as JSON and wrapped in a
    special guard string `AYON_CONTEXT::...::AYON_CONTEXT_END`.

    Returns:
        dict: Context data.

    """
    # sourcery skip: use-named-expression
    project = self.get_current_project()
    m = re.search(AYON_METADATA_REGEX, project.notes)
    if not m:
        self._create_ayon_data()
        return {}
    try:
        context = json.loads(m["context"]) if m else {}
    except ValueError:
        self.log.debug("AYON data is not valid json")
        # AYON data not found or invalid, create empty placeholder
        self._create_ayon_data()
        return {}

    return context

get_containers()

Get containers from the current workfile.

Yields:

Name Type Description
Generator dict

Container data.

Source code in client/ayon_mocha/api/pipeline.py
219
220
221
222
223
224
225
226
227
228
229
230
def get_containers(self) -> Generator[dict, None, list]:
    """Get containers from the current workfile.

    Yields:
        Generator: Container data.

    """
    # sourcery skip: use-named-expression
    data = self.get_ayon_data()
    if data:
        yield from data.get(MOCHA_CONTAINERS_KEY, [])
    yield {}

get_context_data()

Get context data from the current project.

Returns:

Name Type Description
dict dict

Context data.

Source code in client/ayon_mocha/api/pipeline.py
345
346
347
348
349
350
351
352
353
354
def get_context_data(self) -> dict:
    """Get context data from the current project.

    Returns:
        dict: Context data.

    """
    data = self.get_ayon_data()

    return data.get(MOCHA_CONTEXT_KEY, {})

get_current_project()

Return the current project.

Source code in client/ayon_mocha/api/pipeline.py
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
def get_current_project(self) -> Project:
    """Return the current project."""
    project = _get_current_project()
    if not project:
        if not self._uninitialized_project_warning_shown:
            show_message_dialog(
                "No project is opened.",
                (
                    "Please open or save a project first, otherwise "
                    "you won't be able to see the results of any "
                    "operations you'll make."
                ),
                parent=get_main_window(),
            )
            self._uninitialized_project_warning_shown = True
        return create_empty_project()
    return project

get_current_workfile()

Get the current workfile.

Returns:

Type Description
Optional[str]

Optional[str]: The current workfile.

Source code in client/ayon_mocha/api/pipeline.py
209
210
211
212
213
214
215
216
217
def get_current_workfile(self) -> Optional[str]:  # noqa: PLR6301
    """Get the current workfile.

    Returns:
        Optional[str]: The current workfile.

    """
    file_path = current_file()
    return file_path.as_posix() if file_path else None

get_publish_instances()

Get publish instances from the current project.

Returns:

Type Description
list[dict]

list[dict]: Publish instances.

Source code in client/ayon_mocha/api/pipeline.py
371
372
373
374
375
376
377
378
379
def get_publish_instances(self) -> list[dict]:
    """Get publish instances from the current project.

    Returns:
        list[dict]: Publish instances.

    """
    data = self.get_ayon_data()
    return data.get(MOCHA_INSTANCES_KEY, [])

get_workfile_extensions()

Get the workfile extensions.

Returns:

Type Description
list[str]

list[str]: Workfile extensions.

Source code in client/ayon_mocha/api/pipeline.py
177
178
179
180
181
182
183
184
def get_workfile_extensions(self) -> list[str]:  # noqa: PLR6301
    """Get the workfile extensions.

    Returns:
        list[str]: Workfile extensions.

    """
    return file_extensions()

install()

Initialize the host.

Source code in client/ayon_mocha/api/pipeline.py
106
107
108
109
110
111
112
113
114
def install(self) -> None:
    """Initialize the host."""
    pyblish.api.register_host(self.name)
    pyblish.api.register_plugin_path(PUBLISH_PATH.as_posix())
    register_loader_plugin_path(LOAD_PATH.as_posix())
    register_creator_plugin_path(CREATE_PATH.as_posix())

    # QtCore.QTimer.singleShot(0, self._install_menu)
    self._install_menu()

open_workfile(filepath)

Open the workfile.

Source code in client/ayon_mocha/api/pipeline.py
205
206
207
def open_workfile(self, filepath: str) -> None:  # noqa: PLR6301
    """Open the workfile."""
    open_file(Path(filepath))

remove_container(container)

Remove a container from the current workfile.

Parameters:

Name Type Description Default
container Container

Container to remove.

required
Source code in client/ayon_mocha/api/pipeline.py
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
def remove_container(self, container: Container) -> None:
    """Remove a container from the current workfile.

    Args:
        container (Container): Container to remove.

    """
    data = self.get_ayon_data()
    containers_dicts = list(self.get_containers())
    containers = [
        Container(**_container) for _container in containers_dicts
    ]
    to_remove = [
        idx
        for idx, _container in enumerate(containers)
        if _container.name == container.name
        and _container.namespace == container.namespace
    ]
    for idx in reversed(to_remove):
        containers.pop(idx)

    data[MOCHA_CONTAINERS_KEY] = [
        dataclasses.asdict(_container) for _container in containers]

    self.update_ayon_data(data)

remove_create_instance(instance_id)

Remove a publishing instance from the current project.

Parameters:

Name Type Description Default
instance_id str

Publish instance id to remove.

required
Source code in client/ayon_mocha/api/pipeline.py
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
def remove_create_instance(self, instance_id: str) -> None:
    """Remove a publishing instance from the current project.

    Args:
        instance_id (str): Publish instance id to remove.

    """
    data = self.get_ayon_data()
    publish_instances = self.get_publish_instances()
    publish_instances = [
        publish_instance
        for publish_instance in publish_instances
        if publish_instance["instance_id"] != instance_id
    ]
    data[MOCHA_INSTANCES_KEY] = publish_instances

    self.update_ayon_data(data)

save_workfile(dst_path=None)

Save the workfile.

Parameters:

Name Type Description Default
dst_path str

The destination path to save the file to. Defaults to None.

None

Todo (antirotor): This needs to display error if the project isn't initialized yet. https://github.com/ynput/ayon-core/issues/1075

Source code in client/ayon_mocha/api/pipeline.py
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
def save_workfile(self, dst_path: Optional[str] = None) -> None:  # noqa: PLR6301
    """Save the workfile.

    Args:
        dst_path (str, optional): The destination path to save the file to.
            Defaults to None.

    Todo (antirotor): This needs to display error if the project
        isn't initialized yet.
        https://github.com/ynput/ayon-core/issues/1075

    """
    if dst_path:
        save_file(Path(dst_path))
    else:
        save_file(filepath=None)
    if not _get_current_project():
        reset_frame_range(_get_current_project())

update_ayon_data(data)

Update AYON context data in the current project.

Serialize context data as json and store it in the project notes. If the context data is not found, create a placeholder there. See get_context_data for more info.

Parameters:

Name Type Description Default
data dict

Context data.

required
Source code in client/ayon_mocha/api/pipeline.py
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
def update_ayon_data(self, data: dict) -> None:
    """Update AYON context data in the current project.

    Serialize context data as json and store it in the
    project notes. If the context data is not found, create
    a placeholder there. See `get_context_data` for more info.

    Args:
        data (dict): Context data.

    """
    project = self.get_current_project()
    original_data = self.get_ayon_data()

    updated_data = original_data.copy()
    updated_data.update(data)
    update_str = json.dumps(
        updated_data or {}, indent=4, cls=AYONJSONEncoder)

    project.notes = re.sub(
            AYON_METADATA_REGEX,
            AYON_METADATA_GUARD.format(update_str),
            project.notes,
        )
    update_ui()

update_context_data(data, changes)

Update context data in the current project.

Parameters:

Name Type Description Default
data dict

Context data.

required
changes dict

Changes to the context data.

required
Source code in client/ayon_mocha/api/pipeline.py
356
357
358
359
360
361
362
363
364
365
366
367
368
369
def update_context_data(
        self, data: dict, changes: dict) -> None:
    """Update context data in the current project.

    Args:
        data (dict): Context data.
        changes (dict): Changes to the context data.

    """
    if not data:
        return
    ayon_data = self.get_ayon_data()
    ayon_data[MOCHA_CONTEXT_KEY] = data
    self.update_ayon_data(ayon_data)

update_publish_instance(instance_id, data)

Update a publish instance in the current project.

Parameters:

Name Type Description Default
instance_id str

Publish instance id to update.

required
data dict

Data to update.

required
Source code in client/ayon_mocha/api/pipeline.py
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
def update_publish_instance(
        self,
        instance_id: str,
        data: dict,
) -> None:
    """Update a publish instance in the current project.

    Args:
        instance_id (str): Publish instance id to update.
        data (dict): Data to update.

    """
    ayon_data = self.get_ayon_data()
    publish_instances = self.get_publish_instances()
    for idx, publish_instance in enumerate(publish_instances):
        if publish_instance["instance_id"] == instance_id:
            publish_instances[idx] = data
            break
    ayon_data[MOCHA_INSTANCES_KEY] = publish_instances

    self.update_ayon_data(ayon_data)

write_create_instances(instances)

Write publish instances to the current project.

Source code in client/ayon_mocha/api/pipeline.py
417
418
419
420
421
422
def write_create_instances(
        self, instances: list[dict]) -> None:
    """Write publish instances to the current project."""
    ayon_data = self.get_ayon_data()
    ayon_data[MOCHA_INSTANCES_KEY] = instances
    self.update_ayon_data(ayon_data)

reset_frame_range(project)

Reset frame range to the current task entity.

Source code in client/ayon_mocha/api/pipeline.py
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
def reset_frame_range(project: Optional[Project]) -> None:
    """Reset frame range to the current task entity."""
    task_entity = get_current_task_entity()
    frame_start = task_entity["attrib"]["frameStart"]
    frame_end = task_entity["attrib"]["frameEnd"]
    fps = task_entity["attrib"]["fps"]
    # resolution_width = task_entity["attrib"]["resolutionWidth"]
    # resolution_height = task_entity["attrib"]["resolutionHeight"]
    # pixel_aspect = task_entity["attrib"]["pixelAspect"]

    if not project:
        host: MochaProHost = registered_host()
        project = host.get_current_project()

    project.length = int(frame_end) - int(frame_start) + 1
    project.first_frame_offset = int(frame_start)
    project.frame_rate = fps