# Calling a method from a string

I am trying to execute a line of code, such as: bpy.ops.object.modifier_add(type='SUBSURF') from a string of text.

My code is:

import bpy
import math

print("~~~Separator~~~")

obj_list = []

class ExportSomeData(bpy.types.Operator):
"""Test exporter which just writes hello world"""
bl_idname = "export.some_data"
bl_label = "Export Some Data"

filepath = bpy.props.StringProperty(subtype="FILE_PATH")

@classmethod
def poll(cls, context):
if not obj_list:
return False
else:
return True

def callMethod(o, name):
getattr(o, name)()

def execute(self, context):
file = open(self.filepath, 'r+')
for line in file:
callMethod("I don't know what to put here", line)
file.close()

return {'FINISHED'}

def invoke(self, context, event):
return {'RUNNING_MODAL'}

class SelectOperator(bpy.types.Operator):
bl_idname = "scene.select_option"
bl_label = "Multi Select Operator"

@classmethod
def poll(cls, context):
if not bpy.context.selected_objects:
return False
else:
return True

def execute(self, context):
global obj_list
obj_list = []
for obj in bpy.context.selected_objects:
obj_list.append(obj)
print(str(obj))
print("Objects in the active list: " + str(obj_list))
return {'FINISHED'}

"""Subdivide and scale a mesh."""

@classmethod
def poll(cls, context):
global obj_list
if not obj_list:
return False
else:
return True

def execute(self, context):
global obj_list

return {'FINISHED'}

class SelectionPanel(bpy.types.Panel):

bl_label = "Multi Selection Options"
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'

def draw(self, context):
layout = self.layout

row = layout.row()

split = layout.split()

col = split.column(align=True)

col.operator("scene.select_option", text = "Set Objects", icon = "MESH_CUBE")

col.operator("export.some_data", text = "Open And Do Task", icon = "FILE")
def register():
bpy.utils.register_class(SelectionPanel)
bpy.utils.register_class(SelectOperator)
bpy.utils.register_class(ExportSomeData)

def unregister():
bpy.utils.unregister_class(SelectionPanel)
bpy.utils.unregister_class(SelectOperator)
bpy.utils.unregister_class(ExportSomeData)

if __name__ == "__main__":
register()


Below is what is causing me trouble:

def callMethod(o, name):
getattr(o, name)()

def execute(self, context):
file = open(self.filepath, 'r+')
for line in file:
callMethod("I don't know what to put here", line)
file.close()

return {'FINISHED'}


line is bpy.ops.object.modifier_add(type='SUBSURF'), but I don't know the object to put for the first parameter. If I am going the wrong direction with this, please correct me.

It looks like you are passing a whole function call to the getattr() function as a string.

getattr() takes an object as first argument and a string a second argument.

What you should do is isolate the object, the function and the params

Once you isolated your object string (ie. str="bpy.ops.object") you can isolate the object with a quick but unsafe myObj = eval(str) or use a safer

import sys

def str_to_class(str):
return getattr(sys.modules[__name__], str)

myObj = str_to_class("bpy.ops.object") #line added from original code


After that you should call getattr in this fashion:
getattr(myObj, 'myFunction')(params)

In the specific case you presented it would look something like this in explicit form
getattr(bpy.ops.object, "modifier_add")(type='SUBSURF')

Note: eval() is a very unsafe to use if there's some kind of user input, since the user could inject malicious code in eval()'s parameter string.

Edit: if security is not a concern, for any reason, you could also just eval() the whole string. Just make sure not to share your code without a proper warning.
If security is a concern, in both of the cases described above, you might want to apply a filter on the strings you pass to the converting function. Something like if str[:3]=="bpy": str_to_class(str) #or eval(). It makes things a little safer.

• I apologize, but I am still having an error. getattr(bpy.ops.object, "modifier_add")(type='SUBSURF') works fine. However, import sys def str_to_class(str): return getattr(sys.modules[__name__], str) myObj = str_to_class("bpy.ops.object") #line added from original code gives an error of "AttributeError: 'module' object has no attribute 'bpy.ops.object'" – Tritofic Aug 31 '15 at 14:17
• Yup: Didn't test the code coming from the page I linked, assuming it was working, but it isn't for me either. I've been playing around a bit and worked out something like this: m = __import__("bpy") \ ops = getattr(m, "ops") \ object = getattr(ops, "object") You can easily loop that process with the aid of "my.test.string".split(".") Give a shout out if you need any more help :) – torels Sep 1 '15 at 15:33
• Maybe m = locals().get("bpy", None) , fair to assume bpy would be in locals for a blender script. – batFINGER Jan 1 '17 at 11:41