Files
blender-portable-repo/scripts/addons/blender_log/operators/drivers.py
T
2026-03-17 14:58:51 -06:00

124 lines
4.2 KiB
Python

# SPDX-FileCopyrightText: 2025 Blender Studio Tools Authors
#
# SPDX-License-Identifier: GPL-3.0-or-later
import bpy
from bpy.props import StringProperty, IntProperty
from bpy.types import Object
from typing import List
def report_invalid_drivers(context, objects: List[Object]):
blenlog = context.scene.blender_log
cat_leftover = 'Leftover Driver'
blenlog.clear_category(cat_leftover)
cat_invalid = 'Invalid Driver'
blenlog.clear_category(cat_invalid)
counter = 0
for obj in objects:
if obj.library or obj.override_library:
continue
if not obj.animation_data:
continue
for fcurve in obj.animation_data.drivers:
kwargs = {
'icon': 'DRIVER_TRANSFORM',
'operator': BLENLOG_OT_delete_driver.bl_idname,
'op_kwargs': {
'object_name': obj.name,
'driver_path': fcurve.data_path,
'array_index': fcurve.array_index,
},
}
try:
obj.path_resolve(fcurve.data_path)
except ValueError:
# If the RNA path of the driver fails to resolve to some value,
# that means the driver is pointing at nothing; A deleted modifier,
# constraint, bone, whatever.
blenlog.add(
description=f"Driver RNA path leads to nothing: '{fcurve.data_path}'.\nThis can happen when removing modifiers, constraints, bones, etc. that previously had drivers on them. Such driver can be safely deleted, else they will spam the console.",
name=obj.name,
category=cat_leftover,
**kwargs
)
counter += 1
continue
if not fcurve.driver.is_valid:
blenlog.add(
description=f"Invalid Driver: '{fcurve.data_path}'.\nThis can happen when a driver var target datablock is removed, an expression is invalid, etc.",
name=obj.name,
category=cat_invalid,
**kwargs
)
counter += 1
return counter
report_leftover_drivers = report_invalid_drivers
class BLENLOG_OT_report_invalid_drivers(bpy.types.Operator):
"""Report drivers that point to nothing"""
bl_idname = "blenlog.report_invalid_drivers"
bl_label = "Report Leftover Drivers"
bl_options = {'INTERNAL', 'REGISTER', 'UNDO'}
def execute(self, context):
counter = report_invalid_drivers(context, bpy.data.objects)
if counter > 0:
self.report({'WARNING'}, f"Found {counter} invalid drivers.")
else:
self.report({'INFO'}, f"No invalid drivers found.")
return {'FINISHED'}
class BLENLOG_OT_delete_driver(bpy.types.Operator):
"""Delete a driver on a local object"""
bl_idname = "blenlog.delete_driver"
bl_label = "Delete Driver"
bl_options = {'INTERNAL', 'REGISTER', 'UNDO'}
object_name: StringProperty()
driver_path: StringProperty()
array_index: IntProperty()
def execute(self, context):
obj = bpy.data.objects.get((self.object_name, None))
if not obj:
self.report({'INFO'}, f'Object "{self.object_name}" had already been removed.')
return {'CANCELLED'}
if not obj.animation_data or not obj.animation_data.drivers:
self.report(
{'INFO'}, f'All drivers of object "{self.object_name}" had already been removed.'
)
return {'CANCELLED'}
logs = context.scene.blender_log
driver = obj.animation_data.drivers.find(self.driver_path, index=self.array_index)
if driver:
obj.animation_data.drivers.remove(driver)
self.report({'INFO'}, f'Removed driver "{self.driver_path}" from object "{obj.name}"')
else:
self.report(
{'INFO'},
f'Driver "{self.driver_path} on object "{obj.name}" had already been removed.',
)
logs.remove(logs.active_log)
return {'FINISHED'}
registry = [
BLENLOG_OT_report_invalid_drivers,
BLENLOG_OT_delete_driver,
]