Page MenuHome

Drivers can have multiple variables with same name
Closed, ResolvedPublic

Description

Currently, drivers can get several variables with the same exact name.

Besides being useless and confusing (typically, driver will only use the first one then), this is also a problem for library overrides, since there are several data (driver variables) with the same exact RNA path.

You can check e.g. lib/char/butterfly/butterfly.blend from sprite production files, GEO-butterfly_antennas object's drivers, burnt one has three burnt variables.


LibOverride issue can be fixed by forbidding usage of names for the driver variables collection (only indices would be used then). However this has serious downsides, first one being that if a driver has several valid variables and they get re-arranged, the overrides will need to be resynced.

And in general I don't think such confusing useless situation should be allowed at all.

So think there should be a mechanism (maybe as part of driver_variable_name_validate ?) that should ensure unique names?

NOTE: found while investigating mysterious 'always need to resync overrides' cases from T94059.

Event Timeline

Bastien Montagne (mont29) changed the task status from Needs Triage to Confirmed.Dec 15 2021, 4:24 PM
Bastien Montagne (mont29) created this task.

For the records, in my tests here the drivers use the last variable, not the first one.

@Andy Goralczyk (eyecandy) @Simon Thommes (simonthommes) Also thing you need to know for now imho.

For the time being, this simple script allows to clean things up:

for _name in dir(bpy.data):
    iterable = getattr(bpy.data, _name)
    if not isinstance(iterable, bpy.data.objects.__class__):
        continue
    for id in iterable:
        if not getattr(id, "animation_data", None):
            continue
        for driver in id.animation_data.drivers:
            variable_names = set()
            for variable in driver.driver.variables:
                if variable.name in variable_names:
                    print("ERROR! ID driver '%s.%s' has several variables named '%s', removing the extra ones." % (id.name, driver.data_path, variable.name))
                    driver.driver.variables.remove(variable)
                else:
                    variable_names.add(variable.name)

You actually need to traverse the list in the reverse order. Corrected script using reversed:

import bpy

for _name in dir(bpy.data):
    iterable = getattr(bpy.data, _name)
    if not isinstance(iterable, bpy.data.objects.__class__):
        continue
    for id in iterable:
        if not getattr(id, "animation_data", None):
            continue
        for driver in id.animation_data.drivers:
            variable_names = set()
            for variable in reversed(driver.driver.variables):
                if variable.name in variable_names:
                    print("ERROR! ID driver '%s.%s' has several variables named '%s', removing the extra ones." % (id.name, driver.data_path, variable.name))
                    driver.driver.variables.remove(variable)
                else:
                    variable_names.add(variable.name)

Sample file:

This is indeed something to address. There is no use for multiple variables when they all overwrite each other's value anyway.

So think there should be a mechanism (maybe as part of driver_variable_name_validate ?) that should ensure unique names?

I agree, but not in that function. That now has a clear, single purpose, and I don't want to add more things to it.

Bastien Montagne (mont29) moved this task from Backlog to Bugs on the Core board.Dec 17 2021, 12:31 PM
Bastien Montagne (mont29) moved this task from Bugs to Other Modules Responsibility on the Core board.