Skip to content

pipeline

Pipeline tools for AYON Zbrush integration.

ZbrushHost

Bases: HostBase, IWorkfileHost, ILoadHost, IPublishHost

Source code in client/ayon_zbrush/api/pipeline.py
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
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
class ZbrushHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
    name = "zbrush"

    def install(self):
        # Create workdir folder if does not exist yet
        workdir = os.getenv("AYON_WORKDIR")
        if not os.path.exists(workdir):
            os.makedirs(workdir)

        plugins_dir = os.path.join(ZBRUSH_HOST_DIR, "plugins")
        publish_dir = os.path.join(plugins_dir, "publish")
        load_dir = os.path.join(plugins_dir, "load")
        create_dir = os.path.join(plugins_dir, "create")

        pyblish.api.register_host("zbrush")
        pyblish.api.register_plugin_path(publish_dir)
        register_loader_plugin_path(load_dir)
        register_creator_plugin_path(create_dir)

        register_event_callback("application.launched", self.initial_app_launch)
        register_event_callback("application.exit", self.application_exit)

    def get_current_project_name(self):
        """
        Returns:
            Union[str, None]: Current project name.
        """

        return self.get_current_context().get("project_name")

    def get_current_folder_path(self):
        """
        Returns:
            Union[str, None]: Current folder path.
        """

        return self.get_current_context().get("folder_path")

    def get_current_task_name(self):
        """
        Returns:
            Union[str, None]: Current task name.
        """

        return self.get_current_context().get("task_name")

    def get_current_context(self):
        context = get_current_workfile_context()
        if not context:
            return get_global_context()
        if "project_name" in context:
            return context
        # This is legacy way how context was stored
        return {
            "project_name": context.get("project_name"),
            "folder_path": context.get("folder_path"),
            "task_name": context.get("task_name")
        }

    # --- Workfile ---
    def open_workfile(self, filepath):
        filepath = filepath.replace("\\", "/")
        execute_zscript(f"""
[IFreeze,
    [FileNameSetNext, "{filepath}"]
    [IKeyPress, 13, [IPress, File:Open:Open]]]
]
    """)
        set_current_file(filepath=filepath)
        return filepath

    def save_workfile(self, filepath=None):
        if not filepath:
            filepath = self.get_current_workfile()
        filepath = filepath.replace("\\", "/")
        # # move the json data to the files
        # # shutil.copy
        copy_ayon_data(filepath)
        set_current_file(filepath=filepath)
        execute_zscript(f"""
[IFreeze,
    [FileNameSetNext, "{filepath}"]
    [IKeyPress, 13, [IPress, File:SaveAs:SaveAs]]]
]
""")
        return filepath

    def get_current_workfile(self):
        work_dir = get_workdir()
        txt_dir = os.path.join(
            work_dir, ".zbrush_metadata").replace(
                "\\", "/"
        )
        with open (f"{txt_dir}/current_file.txt", "r") as current_file:
            content = str(current_file.read())
            filepath = content.rstrip('\x00')
            current_file.close()
            return filepath

    def workfile_has_unsaved_changes(self):
        # Pop-up dialog would be located to ask if users
        # save scene if it has unsaved changes
        return True

    def get_workfile_extensions(self):
        return [".zpr"]

    def list_instances(self):
        """Get all AYON instances."""
        # Figure out how to deal with this
        return get_instance_workfile_metadata()

    def write_instances(self, data):
        """Write all AYON instances"""
        return write_workfile_metadata(ZBRUSH_SECTION_NAME_INSTANCES, data)

    def get_containers(self):
        """Get the data of the containers

        Returns:
            list: the list which stores the data of the containers
        """
        return get_containers()

    def initial_app_launch(self):
        """Triggers on launch of the communication server for Zbrush.

        Usually this aligns roughly with the start of Zbrush.
        """
        #TODO: figure out how to deal with the last workfile issue
        set_current_file()
        context = get_global_context()
        save_current_workfile_context(context)

    def application_exit(self):
        """Logic related to TimerManager.

        Todo:
            This should be handled out of Zbrush integration logic.
        """
        remove_tmp_data()
        data = get_current_project_settings()
        stop_timer = data["zbrush"]["stop_timer_on_application_exit"]

        if not stop_timer:
            return

        # Stop application timer.
        webserver_url = os.environ.get("AYON_WEBSERVER_URL")
        rest_api_url = "{}/timers_manager/stop_timer".format(webserver_url)
        requests.post(rest_api_url)

    def update_context_data(self, data, changes):
        return write_workfile_metadata(ZBRUSH_METADATA_CREATE_CONTEXT, data)

    def get_context_data(self):
        get_load_workfile_metadata(ZBRUSH_METADATA_CREATE_CONTEXT)

application_exit()

Logic related to TimerManager.

Todo

This should be handled out of Zbrush integration logic.

Source code in client/ayon_zbrush/api/pipeline.py
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
def application_exit(self):
    """Logic related to TimerManager.

    Todo:
        This should be handled out of Zbrush integration logic.
    """
    remove_tmp_data()
    data = get_current_project_settings()
    stop_timer = data["zbrush"]["stop_timer_on_application_exit"]

    if not stop_timer:
        return

    # Stop application timer.
    webserver_url = os.environ.get("AYON_WEBSERVER_URL")
    rest_api_url = "{}/timers_manager/stop_timer".format(webserver_url)
    requests.post(rest_api_url)

get_containers()

Get the data of the containers

Returns:

Name Type Description
list

the list which stores the data of the containers

Source code in client/ayon_zbrush/api/pipeline.py
150
151
152
153
154
155
156
def get_containers(self):
    """Get the data of the containers

    Returns:
        list: the list which stores the data of the containers
    """
    return get_containers()

get_current_folder_path()

Returns:

Type Description

Union[str, None]: Current folder path.

Source code in client/ayon_zbrush/api/pipeline.py
64
65
66
67
68
69
70
def get_current_folder_path(self):
    """
    Returns:
        Union[str, None]: Current folder path.
    """

    return self.get_current_context().get("folder_path")

get_current_project_name()

Returns:

Type Description

Union[str, None]: Current project name.

Source code in client/ayon_zbrush/api/pipeline.py
56
57
58
59
60
61
62
def get_current_project_name(self):
    """
    Returns:
        Union[str, None]: Current project name.
    """

    return self.get_current_context().get("project_name")

get_current_task_name()

Returns:

Type Description

Union[str, None]: Current task name.

Source code in client/ayon_zbrush/api/pipeline.py
72
73
74
75
76
77
78
def get_current_task_name(self):
    """
    Returns:
        Union[str, None]: Current task name.
    """

    return self.get_current_context().get("task_name")

initial_app_launch()

Triggers on launch of the communication server for Zbrush.

Usually this aligns roughly with the start of Zbrush.

Source code in client/ayon_zbrush/api/pipeline.py
158
159
160
161
162
163
164
165
166
def initial_app_launch(self):
    """Triggers on launch of the communication server for Zbrush.

    Usually this aligns roughly with the start of Zbrush.
    """
    #TODO: figure out how to deal with the last workfile issue
    set_current_file()
    context = get_global_context()
    save_current_workfile_context(context)

list_instances()

Get all AYON instances.

Source code in client/ayon_zbrush/api/pipeline.py
141
142
143
144
def list_instances(self):
    """Get all AYON instances."""
    # Figure out how to deal with this
    return get_instance_workfile_metadata()

write_instances(data)

Write all AYON instances

Source code in client/ayon_zbrush/api/pipeline.py
146
147
148
def write_instances(self, data):
    """Write all AYON instances"""
    return write_workfile_metadata(ZBRUSH_SECTION_NAME_INSTANCES, data)

copy_ayon_data(filepath)

Copy any ayon-related data( such as instances, create-context, cotnainers) from the previous workfile to the new one when incrementing and saving workfile.

Parameters:

Name Type Description Default
filepath str

the workfile path to be saved

required
Source code in client/ayon_zbrush/api/pipeline.py
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
def copy_ayon_data(filepath):
    """Copy any ayon-related data(
        such as instances, create-context, cotnainers)
        from the previous workfile to the new one
        when incrementing and saving workfile.

    Args:
        filepath (str): the workfile path to be saved
    """
    filename = os.path.splitext(os.path.basename(filepath))[0].strip()
    current_file = registered_host().get_current_workfile()
    if current_file:
        current_file = os.path.splitext(
            os.path.basename(current_file))[0].strip()
    work_dir = get_workdir()
    for name in [ZBRUSH_METADATA_CREATE_CONTEXT,
                 ZBRUSH_SECTION_NAME_INSTANCES,
                 ZBRUSH_SECTION_NAME_CONTAINERS]:
        src_json_dir = os.path.join(
            work_dir, ".zbrush_metadata", current_file, name).replace(
                "\\", "/"
            )
        if not os.path.exists(src_json_dir):
            continue
        dst_json_dir = os.path.join(
            work_dir, ".zbrush_metadata", filename, name).replace(
                "\\", "/"
            )
        os.makedirs(dst_json_dir, exist_ok=True)
        all_fname_list = [jfile for jfile in os.listdir(src_json_dir)
                        if jfile.endswith("json")]
        if all_fname_list:
            for fname in all_fname_list:
                src_json = f"{src_json_dir}/{fname}"
                dst_json = f"{dst_json_dir}/{fname}"
                shutil.copy(src_json, dst_json)

get_containers()

Function to get the container data

Returns:

Name Type Description
list

list of container data

Source code in client/ayon_zbrush/api/pipeline.py
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
def get_containers():
    """Function to get the container data

    Returns:
        list: list of container data
    """
    output = get_load_workfile_metadata(ZBRUSH_SECTION_NAME_CONTAINERS)
    if output:
        for item in output:
            if "objectName" not in item and "name" in item:
                members = item["name"]
                if isinstance(members, list):
                    members = "|".join([str(member) for member in members])
                item["objectName"] = members

    return output

get_current_workfile_context()

Function to get the current context data from the related json file in .zbrush_metadata/context folder

The current context data includes thing like project name, folder path and task name.

Returns:

Name Type Description
list

list of context data

Source code in client/ayon_zbrush/api/pipeline.py
289
290
291
292
293
294
295
296
297
298
299
def get_current_workfile_context():
    """Function to get the current context data from the related
    json file in .zbrush_metadata/context folder

    The current context data includes thing like project name,
    folder path and task name.

    Returns:
        list: list of context data
    """
    return get_load_context_metadata()

get_instance_workfile_metadata()

Get instance data from the related metadata json("instances.json") which stores in .zbrush_metadata/{workfile}/instances folder in the project work directory.

Instance data includes the info like the workfile instance and any instances created by the users for publishing.

Returns:

Name Type Description
dict

instance data

Source code in client/ayon_zbrush/api/pipeline.py
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
def get_instance_workfile_metadata():
    """Get instance data from the related metadata json("instances.json")
    which stores in .zbrush_metadata/{workfile}/instances folder
    in the project work directory.

    Instance data includes the info like the workfile instance
    and any instances created by the users for publishing.

    Returns:
        dict: instance data
    """
    file_content = []
    current_file = registered_host().get_current_workfile()
    if current_file:
        current_file = os.path.splitext(
            os.path.basename(current_file))[0].strip()
    work_dir = get_workdir()
    json_dir = os.path.join(
        work_dir, ".zbrush_metadata",
        current_file, ZBRUSH_SECTION_NAME_INSTANCES).replace(
            "\\", "/"
        )
    if not os.path.exists(json_dir) or not os.listdir(json_dir):
        return file_content
    for file in os.listdir(json_dir):
        with open (f"{json_dir}/{file}", "r") as data:
            file_content = json.load(data)

    return file_content

get_load_context_metadata()

Get the context data from the related json file ("context.json") which stores in .zbrush_metadata/context folder in the project work directory.

The context data includes the project name, folder path and task name.

Returns:

Name Type Description
list

context data

Source code in client/ayon_zbrush/api/pipeline.py
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
def get_load_context_metadata():
    """Get the context data from the related json file
    ("context.json") which stores in .zbrush_metadata/context
    folder in the project work directory.

    The context data includes the project name, folder path and
    task name.

    Returns:
        list: context data
    """
    file_content = {}
    work_dir = get_workdir()
    json_dir = os.path.join(
        work_dir, ".zbrush_metadata", ZBRUSH_SECTION_NAME_CONTEXT).replace(
            "\\", "/"
        )
    if not os.path.exists(json_dir):
        return file_content
    file_list = os.listdir(json_dir)
    if not file_list:
        return file_content
    for file in file_list:
        with open (f"{json_dir}/{file}", "r") as data:
            content = ast.literal_eval(str(data.read().strip()))
            file_content.update(content)
            data.close()
    return file_content

get_load_workfile_metadata(metadata_key)

Get to load the workfile json metadata(such as creator's context data and container data) which stores in zbrush_metadata/{workfile}/{metadata_key} folder in the project work directory. It mainly supports to the metadata_key below: ZBRUSH_METADATA_CREATE_CONTEXT: loading create_context.json where stores the data with publish_attributes(e.g. whether the optional validator is enabled.) ZBRUSH_SECTION_NAME_CONTAINERS: loading {subset_name}.json where includes all the loaded asset data to the zbrush scene.

Parameters:

Name Type Description Default
metadata_key str

name of the metadata key

required

Returns:

Name Type Description
list

list of metadata(create-context data or container data)

Source code in client/ayon_zbrush/api/pipeline.py
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
def get_load_workfile_metadata(metadata_key):
    """Get to load the workfile json metadata(such as
    creator's context data and container data) which stores in
    zbrush_metadata/{workfile}/{metadata_key} folder in the project
    work directory.
    It mainly supports to the metadata_key below:
    ZBRUSH_METADATA_CREATE_CONTEXT: loading create_context.json where
        stores the data with publish_attributes(e.g. whether the
        optional validator is enabled.)
    ZBRUSH_SECTION_NAME_CONTAINERS: loading {subset_name}.json where
        includes all the loaded asset data to the zbrush scene.

    Args:
        metadata_key (str): name of the metadata key

    Returns:
        list: list of metadata(create-context data or container data)
    """
    file_content = []
    current_file = registered_host().get_current_workfile()
    if current_file:
        current_file = os.path.splitext(
            os.path.basename(current_file))[0].strip()
    work_dir = get_workdir()
    json_dir = os.path.join(
        work_dir, ".zbrush_metadata",
        current_file, metadata_key).replace(
            "\\", "/"
        )
    if not os.path.exists(json_dir):
        return file_content
    file_list = os.listdir(json_dir)
    if not file_list:
        return file_content
    for file in file_list:
        with open (f"{json_dir}/{file}", "r") as data:
            content = json.load(data)
            file_content.extend(content)
            data.close()
    return file_content

imprint(container, representation_id)

Function to update the container data from the related json file in .zbrushmetadata/{workfile}/container when updating or switching asset(s)

Parameters:

Name Type Description Default
container str

container

required
representation_id str

representation id

required
Source code in client/ayon_zbrush/api/pipeline.py
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
def imprint(container, representation_id):
    """Function to update the container data from
    the related json file in .zbrushmetadata/{workfile}/container
    when updating or switching asset(s)

    Args:
        container (str): container
        representation_id (str): representation id
    """
    old_container_data = []
    data = {}
    name = container["objectName"]
    current_file = registered_host().get_current_workfile()
    if current_file:
        current_file = os.path.splitext(
            os.path.basename(current_file))[0].strip()
    work_dir = get_workdir()
    json_dir = os.path.join(
        work_dir, ".zbrush_metadata",
        current_file, ZBRUSH_SECTION_NAME_CONTAINERS).replace(
            "\\", "/"
        )
    js_fname = next((jfile for jfile in os.listdir(json_dir)
                     if jfile.endswith(f"{name}.json")), None)
    if js_fname:
        with open(f"{json_dir}/{js_fname}", "r") as file:
            old_container_data = json.load(file)
            print(f"data: {type(old_container_data)}")
            file.close()

        open(f"{json_dir}/{js_fname}", 'w').close()
        for item in old_container_data:
            item["representation"] = representation_id
            data.update(item)
        with open(f"{json_dir}/{js_fname}", "w") as file:
            new_container_data = json.dumps([data])
            file.write(new_container_data)
            file.close()

remove_container_data(name)

Function to remove the specific container data from {subset_name}.json in .zbrush_metadata/{workfile}/containers folder

Parameters:

Name Type Description Default
name str

object name stored in the container

required
Source code in client/ayon_zbrush/api/pipeline.py
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
def remove_container_data(name):
    """Function to remove the specific container data from
    {subset_name}.json in .zbrush_metadata/{workfile}/containers folder

    Args:
        name (str): object name stored in the container
    """
    current_file = registered_host().get_current_workfile()
    if current_file:
        current_file = os.path.splitext(
            os.path.basename(current_file))[0].strip()
    work_dir = get_workdir()
    json_dir = os.path.join(
        work_dir, ".zbrush_metadata",
        current_file, ZBRUSH_SECTION_NAME_CONTAINERS).replace(
            "\\", "/"
        )
    all_fname_list = os.listdir(json_dir)
    json_file = next((jfile for jfile in all_fname_list
                               if jfile == f"{name}.json"), None)
    if json_file:
        os.remove(f"{json_dir}/{json_file}")

remove_tmp_data()

Remove all temporary data which is created by AYON without saving changes when launching Zbrush without enabling skip opening last workfile

Source code in client/ayon_zbrush/api/pipeline.py
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
def remove_tmp_data():
    """Remove all temporary data which is created by AYON without
    saving changes when launching Zbrush without enabling `skip
    opening last workfile`

    """
    work_dir = get_workdir()
    for name in [ZBRUSH_METADATA_CREATE_CONTEXT,
                 ZBRUSH_SECTION_NAME_INSTANCES,
                 ZBRUSH_SECTION_NAME_CONTAINERS]:
        json_dir = os.path.join(
            work_dir, ".zbrush_metadata", name).replace(
                "\\", "/"
            )
        if not os.path.exists(json_dir):
            continue
        all_fname_list = [jfile for jfile in os.listdir(json_dir)
                          if jfile.endswith("json")]
        for fname in all_fname_list:
            os.remove(f"{json_dir}/{fname}")

save_current_workfile_context(context)

Save current workfile context data to .zbrush_metadata/{workfile}/key

This persists the current in-memory context to be set for a specific workfile on disk. Usually used on save to persist the local sessions' workfile context on save.

The context data includes things like the project name, folder path, etc.

Parameters:

Name Type Description Default
context dict

context data

required
Source code in client/ayon_zbrush/api/pipeline.py
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
def save_current_workfile_context(context):
    """Save current workfile context data to `.zbrush_metadata/{workfile}/key`

    This persists the current in-memory context to be set for a specific
    workfile on disk. Usually used on save to persist the local sessions'
    workfile context on save.

    The context data includes things like the project name, folder path,
    etc.

    Args:
        context (dict): context data

    """
    return write_context_metadata(ZBRUSH_SECTION_NAME_CONTEXT, context)

set_current_file(filepath=None)

Function to store current workfile path

Parameters:

Name Type Description Default
filepath str

current workfile path. Defaults to None.

None
Source code in client/ayon_zbrush/api/pipeline.py
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
def set_current_file(filepath=None):
    """Function to store current workfile path

    Args:
        filepath (str, optional): current workfile path. Defaults to None.
    """
    work_dir = get_workdir()
    txt_dir = os.path.join(
        work_dir, ".zbrush_metadata").replace(
            "\\", "/"
    )
    os.makedirs(txt_dir, exist_ok=True)
    txt_file = f"{txt_dir}/current_file.txt"
    if filepath is None:
        with open(txt_file, "w"):
            pass
        return filepath
    filepath_check = tmp_current_file_check()
    if filepath_check.endswith("zpr"):
        filepath = os.path.join(
            os.path.dirname(filepath), filepath_check).replace("\\", "/")
    with open (txt_file, "w") as current_file:
        current_file.write(filepath)
        current_file.close()

tmp_current_file_check()

Function to find the latest .zpr file used by the user in Zbrush.

Returns:

Name Type Description
file_content str

the filepath in .zpr format. If the filepath does not end with '.zpr' format, it returns None.

Source code in client/ayon_zbrush/api/pipeline.py
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
def tmp_current_file_check():
    """Function to find the latest .zpr file used
    by the user in Zbrush.

    Returns:
        file_content (str): the filepath in .zpr format.
            If the filepath does not end with '.zpr' format,
            it returns None.
    """
    output_file = tempfile.NamedTemporaryFile(
        mode="w", prefix="a_zb_cfc", suffix=".txt", delete=False
    )
    output_file.close()
    output_filepath = output_file.name.replace("\\", "/")
    context_data_zscript = ("""
[IFreeze,
	[MemCreate, currentfile, 1000, 0]
    [VarSet, currentfile, [FileNameExtract, [FileNameGetLastUsed], 2+4]]
	[MemWriteString, currentfile, #filename, 0]
	[MemSaveToFile, currentfile, "{output_filepath}", 0]
	[MemDelete, currentfile]
]
""").format(output_filepath=output_filepath)
    execute_zscript(context_data_zscript)
    with open(output_filepath) as data:
        file_content = str(data.read().strip()).rstrip('\x00')
    os.remove(output_filepath)
    return file_content

write_context_metadata(metadata_key, context)

Write context data into the related json which stores in .zbrush_metadata/key folder in the project work directory.

The context data includes the project name, folder path and task name.

Parameters:

Name Type Description Default
metadata_key str

metadata key

required
context dict

context data

required
Source code in client/ayon_zbrush/api/pipeline.py
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
def write_context_metadata(metadata_key, context):
    """Write context data into the related json
    which stores in .zbrush_metadata/key folder
    in the project work directory.

    The context data includes the project name, folder path
    and task name.

    Args:
        metadata_key (str): metadata key
        context (dict): context data
    """
    work_dir = get_workdir()
    json_dir = os.path.join(
        work_dir, ".zbrush_metadata", metadata_key).replace(
            "\\", "/"
        )
    os.makedirs(json_dir, exist_ok=True)
    json_file = f"{json_dir}/{metadata_key}.json"
    if os.path.exists(json_file):
        with open (json_file, "r") as file:
            value = json.load(file)
            if value == context:
                return
    with open (json_file, "w") as file:
        value = json.dumps(context)
        file.write(value)
        file.close()

write_load_metadata(data)

Write/Edit the container data into the related json file("{subset_name}.json") which stores in .zbrush_metadata/{workfile}/containers folder. This persists the current in-memory containers data to be set for updating and switching assets in scene inventory.

Parameters:

Name Type Description Default
metadata_key str

metadata key for container

required
data list

list of container data

required
Source code in client/ayon_zbrush/api/pipeline.py
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
def write_load_metadata(data):
    """Write/Edit the container data into the related json file("{subset_name}.json")
    which stores in .zbrush_metadata/{workfile}/containers folder.
    This persists the current in-memory containers data
    to be set for updating and switching assets in scene inventory.

    Args:
        metadata_key (str): metadata key for container
        data (list): list of container data
    """
    current_file = registered_host().get_current_workfile()
    if current_file:
        current_file = os.path.splitext(
            os.path.basename(current_file))[0].strip()
    work_dir = get_workdir()
    name = next((d["name"] for d in data), None)
    json_dir = os.path.join(
        work_dir, ".zbrush_metadata",
        current_file, ZBRUSH_SECTION_NAME_CONTAINERS).replace(
            "\\", "/"
        )
    os.makedirs(json_dir, exist_ok=True)
    json_file = f"{json_dir}/{name}.json"
    if os.path.exists(json_file):
        with open(json_file, "w"):
            pass

    with open(json_file, "w") as file:
        value = json.dumps(data)
        file.write(value)
        file.close()

write_workfile_metadata(metadata_key, data=None)

Function to write workfile metadata(such as creator's context data and instance data) in .zbrushmetadata/{workfile}/{metadata_key} folder This persists the current in-memory instance/creator's context data to be set for a specific workfile on disk. Usually used on save to persist updating instance data and context data used in publisher.

Parameters:

Name Type Description Default
metadata_key str

metadata key

required
data list

metadata. Defaults to None.

None
Source code in client/ayon_zbrush/api/pipeline.py
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
def write_workfile_metadata(metadata_key, data=None):
    """Function to write workfile metadata(such as creator's context data
    and instance data) in .zbrushmetadata/{workfile}/{metadata_key} folder
    This persists the current in-memory instance/creator's context data
    to be set for a specific workfile on disk. Usually used on save to
    persist updating instance data and context data used in publisher.

    Args:
        metadata_key (str): metadata key
        data (list, optional): metadata. Defaults to None.
    """
    if data is None:
        data = []
    current_file = registered_host().get_current_workfile()
    if current_file:
        current_file = os.path.splitext(
            os.path.basename(current_file))[0].strip()
    work_dir = get_workdir()
    json_dir = os.path.join(
        work_dir, ".zbrush_metadata",
        current_file, metadata_key).replace(
            "\\", "/"
        )
    os.makedirs(json_dir, exist_ok=True)
    with open (f"{json_dir}/{metadata_key}.json", "w") as file:
        value = json.dumps(data)
        file.write(value)
        file.close()