Validating linked data blocks via python

When you open a scene and a linked datablock has been removed from the linked .blend file, a little warning shows up in the console:
Info: LIB: Material: 'MyCoolMaterial' missing from 'C:\Whatever\SomeFile.blend'

How would one go about finding that same information via python (without uber hacky crap like scraping the console stdout, please don’t suggest it :slight_smile: )

In this hypothetical example, the library itself is still valid. The file still exists, and has plenty of valid data being linked into the scene- only a specific material was removed (and is still being used in the other scene). Looking at the outliner in “File mode” there’s even a special icon for data blocks with broken links, so that information exists somewhere, but I cannot find it.

There doesn’t appear to be anything in bpy.types.id that would check a linked datablock against its original location on demand, and the library class itself is a really bare bones container for loading/reloading the library itself. It’s possible to figure out which datablocks came from a library by checking library.users_id() but that just points you to the local data, which then points you back to the library (there is nothing on the datablock itself as far as I can tell).

So yeah, any suggestions would be great. So far the best I’ve got is pretty hacky (though not nearly as hacky as scraping stdout)- using ctypes to capture the linked data state based on the icon shown in the outliner, but I’m 99.9% sure that will fail if the outliner is not in file explorer mode so I really don’t want to head down that path unless it’s necessary.

1 Like

Maybe something like this?

import bpy


def check_data(data_name):
    for item in getattr(bpy.data, data_name):
        if item.library:  # None for local data blocks 

            lib_path = item.library.filepath
            with bpy.data.libraries.load(lib_path) as (lib, _):
                if item.name not in getattr(lib, data_name):
                    print(f"{item.name} missing from library: {lib_path}")

if __name__ == "__main__":
    check_data("materials")

Probably not efficient to load on each data block, but the bpy_lib handles from the context manager are hashable and could possibly be mapped in a dictionary to the library path. In this case, I’m not sure if the handles are refcounted or if we need to explicitly call lib.__exit__().

I’m also not sure if keeping the bpy_lib objects around will give a “live” representation of its data, or if it’s just a snapshot from when it was loaded.

1 Like

hrm… yeah this could work. I’m doing my validation pass on scene load anyway, so I could do it all in one shot, wouldn’t need to be per object or anything. thanks for the suggestion, I’ll give it a shot!

1 Like