Append/change assets from working file to library

Hi! I know that Blender doesn’t allow editing asset library L working from file F directly as mentioned here and I’m looking for some other ways to do it.

It seems indeed possible to append from L to F with bpy.data.libraries.load and write from to F to L with bpy.data.libraries.write as explained here and this is what pose library addon does.

But using bpy.data.libraries.write seems to remove everything from the L file. Not sure if it’s intended behaviour but this method is not that useful then. And this method won’t allow me to edit the assets from L, just append from F to L.

import bpy

def print_all_data_blocks(path):
    with bpy.data.libraries.load(path) as (data_from, data_to):
        for data_block_type in dir(data_from):
            print(data_block_type, getattr(data_from, data_block_type))

print('\nBefore .write:')
print_all_data_blocks(path)

write_data_blocks = set(bpy.data.materials)
bpy.data.libraries.write(
    path, 
    datablocks=write_data_blocks,
    path_remap="NONE",
    fake_user=True,
    compress=False,  # Single-datablock blend file, likely little need to diff.
)

print('\nAfter .write:')

print_all_data_blocks(path) # only `write_data_blocks` are presented

In documentation mentioned that it’s possible using BAT (Blender Asset Tracer) - any example code how to append an asset from one .blend to another using BAT?

And are there other ways to do it? Any ways to do it with just bpy?

I did not know there was a bpy.data.libraries.write method so you got me all excited, but it seems it does remove every data block and saved data when it is run on a file, I don’t think there is a way to simply append or update data.

I think the only safe way to do it is to open blend file B, then append the asset from blend file A, then save and close B.

The way I approached it in my asset browser utilities addon is to spawn a new thread, then run a custom script with a command line instruction (something like blender "path/to/blend.blend" --background --python my_script.py) to open the file, append the asset, save the file, quit the file, then join the thread to the main thread.

I’m pretty sure Johhny Matthews does something similar in his asset browser addon.

Basically the operator spawns as many threads as there are files to update, and each thread is tasked with a custom instruction. The code is way too convoluted for its own good but it kinda does the job.

That’s quite nice - in the worst case scenario user may end up with opened second Blender window and it shouldn’t corrupt anything. Though it would nice to keep it in one instance to make it somehow more mananagable…

I’ve got another idea - Blender has general bpy module that’s possible to run outside of Blender. I wonder if it’s possible to start another bpy module inside current Blender session and make the required changes.

Yup I chose this solution because I dealt with hundreds of different assets in different files and atomic opeations (like add a specific tag or set the copyright to something) and it doesn’t lock the interface since it happens in other threads. But if you only want to transfer a single asset in a single session it will lock the inerface for a few seconds at most which is bearable I guess.

What I did at first was save the working blend file, open the export blend file, append the asset, save file, open working blend file, done. But UX wise it’s quite weird.

But as you mentioned on Osarch it’s working as designed by the devs, they don’t really want users to update assets back to the library from a working file, I guess because it doesn’t happen in movie studios where all the work is separated in sub-files and aggregated in a production file. IMO that’s a bit short-sighted because there are many workflows that rely on ever-evolving assets that are used in production files.

I would wager there a many more 1-person team working with the asset browser than fully-fledged movie studio teams but that is up for debate. I think we miss an asset version control system to make it fool proof though.