Page MenuHome

Added bpy.types.ID.make_local() that can make a single ID block local.
ClosedPublic

Authored by Sybren A. Stüvel (sybren) on Nov 9 2016, 12:26 PM.

Details

Summary

This new bpy.types.ID.make_local(clear_proxies=True) allows Python code to press the "Make Local" button on any ID block. I chose clear_proxies=True as the default, since it's the default behaviour of id_make_local() (defined in library.c).

The caller does need to take care of ensuring that linked-in objects don't refer to local data, and that proxies aren't broken. Currently I use Python code like this to iterate over all ID blocks that need to be made local:

def bottom_up_from_idblock(idblock):
    """Generator, yields datablocks from the bottom (i.e. uses nothing) upward.

    Stupid in that it doesn't detect cycles yet.

    :param idblock: the idblock whose users to yield.
    """

    visited = set()

    def visit(idblock):
        # Prevent visiting the same idblock multiple times
        if idblock in visited:
            return
        visited.add(idblock)

        user_map = bpy.data.user_map([idblock])
        # There is only one entry here, for the idblock we requested.
        for user in user_map[idblock]:
            yield from visit(user)
        yield idblock

    yield from visit(idblock)

for idblock in bottom_up_from_idblock(idblock_to_make_local):
    if idblock.library is None:
        continue
    idblock.make_local(clear_proxy=False)

@Dalai Felinto (dfelinto) suggested it might be useful to port this to C and have bpy.types.ID.make_local() optionally use it. If anyone knows anything in C (maybe the depsgraph) that can already provide me with this info, without having to call user_map([idblock]) on every iteration, that would be great.

Diff Detail

Repository
rB Blender

Event Timeline

Sybren A. Stüvel (sybren) retitled this revision from to Added bpy.types.ID.make_local() that can make a single ID block local..
Sybren A. Stüvel (sybren) updated this object.
Sybren A. Stüvel (sybren) set the repository for this revision to rB Blender.
Bastien Montagne (mont29) requested changes to this revision.Nov 9 2016, 3:26 PM
Bastien Montagne (mont29) edited edge metadata.

Globally OK and nice addition, main missing stuff imho is that make_local should return local ID (either original one, or copied one)

source/blender/makesrna/intern/rna_ID.c
351

Please avoid underscore when not needed, self is enough here :P

351–360

imho this should return local ID (probably return self->newid ? self->newid : self;)

(and then update rna funx to return that pointer).

1020–1024

We do not want such long text in RNA stuff. And if you return local ID, something like "Make this datablock local, return local one (may be a copy of the original, in case it is also indirectly used)"

1027–1028

Please avoid multiple sentences unless absolutely necessary, here a mere parenthesis (or even a comma) is enough.

Also, picky, but we use US English, so behavior, not behaviour ;)

This revision now requires changes to proceed.Nov 9 2016, 3:26 PM

Regarding your py code and comments, looks to me like you are trying to replicate our 'append' process, i.e. making local a bunch of datablocks at once? Then would suggest you rather use BKE_library_make_local(), which already takes care of all the nasty stuff (including detecting deps cycles etc.).

Sybren A. Stüvel (sybren) marked 4 inline comments as done.Nov 9 2016, 3:48 PM
Sybren A. Stüvel (sybren) edited edge metadata.
Sybren A. Stüvel (sybren) updated this object.
  • returning 'self' or 'self->newid'
  • rewording RNA descriptions

Regarding your py code and comments, looks to me like you are trying to replicate our 'append' process, i.e. making local a bunch of datablocks at once? Then would suggest you rather use BKE_library_make_local(), which already takes care of all the nasty stuff (including detecting deps cycles etc.).

I'm indeed trying to replicate the 'append' process, but then for a single datablock (and do whatever is needed to make it local), rather than an entire library. Wouldn't BKE_library_make_local() make too much local?

When untagged_only is true, all datablocks tagged with LIB_TAG_PRE_EXISTING are left untouched by BKE_library_make_local(), so should just be a matter of tagging everything but the stuff you want to make local?

Bastien Montagne (mont29) edited edge metadata.

Patch LGTM now.

This revision is now accepted and ready to land.Nov 9 2016, 4:01 PM

When untagged_only is true, all datablocks tagged with LIB_TAG_PRE_EXISTING are left untouched by BKE_library_make_local(), so should just be a matter of tagging everything but the stuff you want to make local?

Maybe I take that too literally. If I mark everything with LIB_TAG_PRE_EXISTING except some_idblock, how would it handle idblocks that have to be made local in order to make some_idblock local? Would it do so? Or would it skip them?

This revision was automatically updated to reflect the committed changes.