Page MenuHome

`self is self.id_data` is inconsistent.
Closed, ResolvedPublic

Description

System Information
Operating system: Linux
Graphics card: Intel

Blender Version
Broken: 2.91.0
Worked: never

Short description of error

When the driver code self is self.id_data is evaluated on an Object property (E.G. Transform) in a file that contains in multiple drivers, it will sometimes return True and sometimes return False, for different updates on the same driver channel.

#Test.py
import bpy

bpy.app.driver_namespace["Test"] = lambda self: self is self.id_data

I'm not sure whether this is a bug, as the behaviour seems somewhat reasonable given the strictness of identity comparison and the complexity of Blender's API— The object might get moved around in memory or destroyed and re-made or something.

But on the other hand, I also think it seems reasonable to expect a single code line, executed sequentially, to behave consistently in that regard.

I think I was also confused because the behaviour seems much more consistent when the number of drivers is fewer and their relationship is simpler, and because this behaviour doesn't seem to occur in the interactive console (E.G. all(C.active_object is C.active_object.id_data for i in range(10000)) == True). So when testing the expression to figure out whether it's safe to use, I easily concluded that it seems fine, only to have problems once the scene was complex enough for it to be harder to track down the cause.

Also, if you assign self and self.id_data to variables before comparing them, and you print out the variables, then it will actually show that do in fact they have the same memory address (E.G. a, b = self, self.id_data; c = a is b; print(a, b, c) can produce <bpy_struct, Object("ObjectName") at 0x7f4b07a76208, evaluated> <bpy_struct, Object("ObjectName") at 0x7f4b07a76208, evaluated> False, where both Python objects are apparently at 0x7f4b07a76208.)

Exact steps for others to reproduce the error
Open the attached .blend file, then rapidly click "Update Dependencies" on a transform channel's driver until the Cube's location starts jumping around.

Event Timeline

From the PyAPI:
id_data: The bpy.types.ID object this datablock is from or None, (not available for all data types)

So, on a driver placed on a Constraint property, where self refers to the constraint, self.id_data will refer to the bpy.types.Object that holds the constraint. self != self.id_data.
On a driver placed on an Object property, where self refers to the object, self==self.id_data.

That said, I find the nomenclature around what's an "ID" and what's a "datablock" very confusing, so I would be interested to hear some developer input on that, but I don't think there is a bug here.

Will (WCN) added a comment.EditedMar 2 2021, 2:19 PM

From the PyAPI:
id_data: The bpy.types.ID object this datablock is from or None, (not available for all data types)

So, on a driver placed on a Constraint property, where self refers to the constraint, self.id_data will refer to the bpy.types.Object that holds the constraint. self != self.id_data.
On a driver placed on an Object property, where self refers to the object, self==self.id_data.

Oh yeah, I'm aware of that. Sorry, I should have been clearer in my original post.

The inconsistency occurs when the driver is placed on the Object datablock. As you can see from my screenshots, self is self.id_data will sometimes be True and sometimes be False on drivers for the .location[] property of the object— It's the same driver on the same Object property that evaluates differently every couple updates, even though both sides always refer to the same Blender Object() with apparently the same memory address.

It's a non-issue on Constraints, Modifiers, etc. because, as you note, there it will always return False anyway. Also, I should note that only is is inconsistent (and presumably is not is as well); == seems to work fine as I can tell. (But == is a magic method while is is a language feature, so especially since the memory addresses and str() of self and self.id_data seem to be the same even where is returns False and since is appears to work perfectly in all situations where a user could reasonably test it, there may be an argument for reasonably using is instead of ==.)

Will (WCN) updated the task description. (Show Details)Mar 2 2021, 2:23 PM
Will (WCN) updated the task description. (Show Details)Mar 2 2021, 2:32 PM

Oh I see, thanks for the clarification! That does sound like a bug indeed :)

Philipp Oeser (lichtwerk) changed the task status from Needs Triage to Confirmed.Mar 17 2021, 3:15 PM

Thx for the detailed report.

Also, I should note that only is is inconsistent (and presumably is not is as well); == seems to work fine as I can tell.

For me == can also fail (although apparently less often.