# How to find out if an object has an action with Python?

How can I use Python to find out if all the selected objects have an action and do something then? If one or more of the selected objects don't have an action, I'd like to print an info/error message saying that "All the selected objects must have an action.".

It's easy to check if an object has shape keys or materials but Terminal says object of type 'Action' has no len()if I try to do this:

import bpy

o = bpy.context.object

if o.animation_data.action:
num_of_actions = len( o.animation_data.action )
print( "Number of actions: ", num_of_actions )


This helps a little bit but isn't the answer to my problem.

This is the best I can do (had some help from Jeremy for the logic bricks):

# This adds the logic bricks to objects that allow them to be playable in BGE, but only to the selected objects that have an action. Actionless objects are ignored.
# Credit goes mostly to Jeremy Behreandt

import bpy

frames_to_be_played = 9999

ops=bpy.ops
context=bpy.context

# Cache shortcuts.
ops_mesh = ops.mesh
ops_object = ops.object
ops_logic = ops.logic
scene = context.scene

selected = bpy.context.selected_objects

for obj in selected:
bpy.context.scene.objects.active = obj

current_object = context.active_object

# Cache shortcut to cube's game engine.
game_engine = current_object.game

#name='Always')
#object=cube_name)
sensor = game_engine.sensors[-1]

#name='And')
#object=cube_name)
controller = game_engine.controllers[-1]

#name='Action',
#object=cube_name)
actuator = game_engine.actuators[-1]

# Set actuator action to cube's animation data action.
actuator.action = current_object.animation_data.action

# Play mode options are:
# ['PLAY', 'PINGPONG', 'FLIPPER', 'LOOPSTOP', 'LOOPEND', 'PROPERTY']
# 'PLAY' is the default.
#actuator.play_mode = play_mode

# Set frame end to scene end.
#actuator.frame_end = scene.frame_end
actuator.frame_end = frames_to_be_played

# Link logic together.


The above script puts the logic bricks to the objects that have an action and ignores the ones that don't have an action, which is good, but not what I'm after.

The ideal case would be to cancel the whole process if even one of the selected objects is missing an action. And notify about that with a message by using this method, which is this snippet code:

import bpy

class RENDER_OT_test(bpy.types.Operator):
bl_idname = 'render.actionerrormessage'
bl_label = 'actionErrorMessage'
bl_options = {'REGISTER', 'UNDO'}

def execute(self, context):
self.report({'INFO'}, 'Cancelling... All the selected objects must have an action.')
return {'FINISHED'}

bpy.utils.register_class(RENDER_OT_test) # test call to the newly defined operator bpy.ops.render.actionerrormessage() - try out by running the script and pressing spacebar and typing actionErrorMessage

• There is only ever one (or no) action associated with an object via ad.action Typically multiple actions for an object are added via the NLA. NLA has a list of tracks ad.nla_tracks each track has strips, a strip has an associated action. – batFINGER Sep 5 '18 at 9:57
• Thanks, batFINGER. I still can't get it to work :/ len( bpy.context.object.animation_data.nla_tracks.data.action ) is just as useless. What would be the correct way to do this? – Manu Järvinen Sep 5 '18 at 11:56
• An action has no length, it is not an iterable. It has an fcurves collection (what you see in the graph editor) Typically a collection name is the give away as it is a plural like objects, materials, nla_tracks. eg len(ad.nla_tracks) From ad.action: it either has one action if ad.action is not None or none. There is no way of telling if other actions not in the animation data "slot" are assoc to the object.. Typically to associate an action with an object the NLA is used. Does your file use NLA to store actions.. if not will be of little use? – batFINGER Sep 5 '18 at 12:20
• Thanks for the comment, batFINGER. But how can I write an if statement that fills the requirements I listed in the original post? This won't work either: goo.gl/vXb21d – Manu Järvinen Sep 5 '18 at 14:10
• Answers here and here might help? – Robin Betts Sep 11 '18 at 17:56

My friend managed to achieve this with a bit nicer code than my artistic approach :)

Code:

import bpy

#########################################################
# INSERT ACTION LOGIC BRICKS TO SELECTED OBJECTS SCRIPT #
#########################################################

#########################################################
# Note:
#
# Each of the selected objects must have a transform
# (Location/Rotation/Scale) action (animation/keyframes)
# before running this script. The action can be empty.
# Otherwise nothing will be inserted to the objects.
#########################################################

############
# Settings #
############

action_brick_start_frame = 0

action_brick_end_frame = 9999

# action_brick_end_frame = bpy.context.scene.frame_end
# Uncomment to set the Action Logic Brick end frame to be
# the end frame of the Timeline.

#############################################################
# Make sure that each of the selected objects has an action #
# Credit goes mostly to Sakari Ekroth                       #
#############################################################

selection = bpy.context.selected_objects
noActionObjs = []
for obj in selection:
if not obj.animation_data or not obj.animation_data.action:
noActionObjs.append(obj.name)

if len(noActionObjs) > 0:
print ("Objects missing action: %s" % ", ".join(noActionObjs))
def oops(self, context):
self.layout.label("All of the selected objects must have an action. Cancelling... ")

print("All of the selected objects must have an action. Cancelling... ")

####################################################################
# The following adds the Logic Bricks to objects that allow them to
# be playable in Blender Game Engine, but only to the selected
# objects that have an action. Actionless objects are ignored.
# Credit goes mostly to Jeremy Behreandt
####################################################################

else:
print("Inserting some Logic Bricks to the selected objects")
ops = bpy.ops
context = bpy.context

# Cache shortcuts.
ops_mesh = ops.mesh
ops_object = ops.object
ops_logic = ops.logic
scene = context.scene

for obj in selection:
if obj.animation_data and obj.animation_data.action:

bpy.context.scene.objects.active = obj
current_object = context.active_object
# Cache shortcut to cube's game engine.
game_engine = current_object.game

#name='Always')
#object=cube_name)
sensor = game_engine.sensors[-1]

#name='And')
#object=cube_name)
controller = game_engine.controllers[-1]

#name='Action',
#object=cube_name)
actuator = game_engine.actuators[-1]

# Set actuator action to cube's animation data action.
actuator.action = current_object.animation_data.action

# Play mode options are:
# ['PLAY', 'PINGPONG', 'FLIPPER', 'LOOPSTOP', 'LOOPEND', 'PROPERTY']
# 'PLAY' is the default.
#actuator.play_mode = play_mode

# Set frame start to scene end.
actuator.frame_start = action_brick_start_frame

# Set frame end to scene end.
actuator.frame_end = action_brick_end_frame

# Link logic together.


Yay, after some fiddling I managed to do it! :)

Here's a GitHub link.

Here's the code (the quality is what my artist brain can manage to yield, but at least it seemed to work):

import bpy

#########################################################
# INSERT ACTION LOGIC BRICKS TO SELECTED OBJECTS SCRIPT #
#########################################################

#########################################################
# Note:
#
# Each of the selected objects must have a transform
# (Location/Rotation/Scale) action (animation/keyframes)
# before running this script. The action can be empty.
# Otherwise nothing will be inserted to the objects.
#########################################################

############
# Settings #
############

action_brick_start_frame = 0

action_brick_end_frame = 9999

# action_brick_end_frame = bpy.context.scene.frame_end
# Uncomment to set the Action Logic Brick end frame to be
# the end frame of the Timeline.

#############################################################
# Make sure that each of the selected objects has an action #
#############################################################

all_objs_have_action = True

for obj in bpy.context.selected_objects:
if ad == None:
obj.animation_data_create()
all_objs_have_action = False
#print(obj.name,"has no object.animation_data, creating...")
all_objs_have_action = False
#print(obj.name,"does NOT have an action")
#else:
#print(obj.name,"has an action")

if all_objs_have_action == True:
print("Inserting some Logic Bricks to the selected objects")

if all_objs_have_action == False:
def oops(self, context):
self.layout.label("All of the selected objects must have an action. Cancelling... ")

print("All of the selected objects must have an action. Cancelling... ")

####################################################################
# The following adds the Logic Bricks to objects that allow them to
# be playable in Blender Game Engine, but only to the selected
# objects that have an action. Actionless objects are ignored.
# Credit goes mostly to Jeremy Behreandt
####################################################################

if all_objs_have_action == True:
ops=bpy.ops
context=bpy.context

# Cache shortcuts.
ops_mesh = ops.mesh
ops_object = ops.object
ops_logic = ops.logic
scene = context.scene

selected = bpy.context.selected_objects

for obj in selected:
bpy.context.scene.objects.active = obj

current_object = context.active_object

# Cache shortcut to cube's game engine.
game_engine = current_object.game

#name='Always')
#object=cube_name)
sensor = game_engine.sensors[-1]

#name='And')
#object=cube_name)
controller = game_engine.controllers[-1]

#name='Action',
#object=cube_name)
actuator = game_engine.actuators[-1]

# Set actuator action to cube's animation data action.
actuator.action = current_object.animation_data.action

# Play mode options are:
# ['PLAY', 'PINGPONG', 'FLIPPER', 'LOOPSTOP', 'LOOPEND', 'PROPERTY']
# 'PLAY' is the default.
#actuator.play_mode = play_mode

# Set frame start to scene end.
actuator.frame_start = action_brick_start_frame

# Set frame end to scene end.
actuator.frame_end = action_brick_end_frame

# Link logic together.