I took Harry McKenzie's answer and added some of my needs:
- needed a for loop to process all of the keying set members added
- detect the type of the property for the Custom Property and set up some values
- enabled the Library Override in the created custom property
import bpy
# ========================================================================
# Function declarations
# ========================================================================
def get_property_name(obj,data_path) -> str:
s = data_path
i = s.find('.')
data_path_1 = ""
data_path_2 = data_path
if i > 0:
ri = s.rindex('.')
data_path_1 = '.' + s[0:ri]
data_path_2 = s[ri+1:len(s)]
data = eval("bpy.context.object" + data_path_1)
print('get_property_name data=',data)
return data.rna_type.properties[data_path_2].name if hasattr(data, data_path_2) else ''
def get_property_type(obj,data_path) -> type:
print(obj,'....',data_path)
#getattr(obj,data_path)
return type(obj.path_resolve(data_path))
def clear_drivers(obj, data_path, index):
if obj.animation_data is None:
return
drivers = obj.animation_data.drivers
for d in drivers:
if d.data_path != data_path:
continue
if index < 0:
for idx in range(-1,3):
obj.driver_remove(d.data_path, idx)
else:
obj.driver_remove(d.data_path, index)
def create_driver(fcurve, obj, custom_prop):
d = fcurve.driver
v = d.variables.new()
v.name = "myvar"
target = v.targets[0]
target.id_type = 'OBJECT'
target.id = obj
target.data_path = '["' + custom_prop + '"]'
d.expression = "myvar"
print('create_driver for ',custom_prop)
# ========================================================================
# Initialize properties from first keying set
# ========================================================================
def keySetToDrivers():
if(len(bpy.context.scene.keying_sets) == 0):
print('First right click property and select "Add to Keying Set".')
return
ksPaths = bpy.context.scene.keying_sets[0].paths
if(len(ksPaths)==0):
print('First right click property and select "Add to Keying Set"')
bpy.ops.anim.keying_set_remove()
return
for ks in ksPaths:
obj = bpy.data.objects[ks.id.name] # get the object for the custom props
ks_use_entire_array = ks if ks.use_entire_array else False
if(ks_use_entire_array):print('ks_use_entire_array for',ks.id.name)
DATA_PATH = ks.data_path
INDEX = -1 if ks_use_entire_array else ks.array_index
CUSTOM_PROPERTY = get_property_name(obj,DATA_PATH)
if ( CUSTOM_PROPERTY == '' ): continue # skip if error return
print('DATA_PATH',DATA_PATH)
if INDEX < 0:
for idx in range(-1,3):
custom_prop = CUSTOM_PROPERTY + ' [' + str(idx) + ']'
if custom_prop in obj:
del obj[custom_prop]
else:
CUSTOM_PROPERTY = CUSTOM_PROPERTY + ' [' + str(INDEX) + ']'
if CUSTOM_PROPERTY in obj:
del obj[CUSTOM_PROPERTY]
# ========================================================================
# Add property and driver
# ========================================================================
if CUSTOM_PROPERTY in obj:
print("WARNING: to prevent overwriting custom property, substituting with data_path name")
continue
clear_drivers(obj, DATA_PATH, INDEX)
print('CUSTOM_PROPERTY',CUSTOM_PROPERTY)
p = bpy.props.BoolProperty(name=CUSTOM_PROPERTY, default=0, options={'ANIMATABLE','LIBRARY_EDITABLE'}, override={'LIBRARY_OVERRIDABLE'}, tags=set())
initVal=0
t=get_property_type(obj, DATA_PATH)
print('get_property_type',t)
if( t is type(bool())):
print('type is bool (int)')
initVal=0
elif( t is type(int())):
print('type is int')
initVal=0
elif( t is type(float())):
print('type is float')
initVal=0.0
elif( t is type(str())):
print('type is string')
initVal=''
obj[CUSTOM_PROPERTY] = initVal # you can add the custom property like this
ui = obj.id_properties_ui(CUSTOM_PROPERTY)
ui.update(description=DATA_PATH)
if( t is type(bool())):
print('type is bool')
ui.update(default=0,min=0,max=1)
elif( t is type(int())):
print('type is int')
ui.update(default=0,min=0)
elif( t is type(float())):
print('type is float')
ui.update(default=0,min=0.0)
elif( t is type(str())):
print('type is string')
#ui.update(default=0,min=0)
#ui.update(default=0,min=0)
obj.property_overridable_library_set('["'+CUSTOM_PROPERTY+'"]', True)
fcurve_or_list = obj.driver_add(DATA_PATH, INDEX)
if type(fcurve_or_list) is list:
for fcurve in fcurve_or_list:
create_driver(fcurve, obj, CUSTOM_PROPERTY)
else:
create_driver(fcurve_or_list, obj, CUSTOM_PROPERTY)
bpy.ops.anim.keying_set_remove() # clean up
keySetToDrivers()