# Select object and recalculate normals via script?

I have a script that allows to import and export .obj files which is working fine. However, I'd like to perform some operations in between these calls, for example select the mesh and recalculate the normals (outside). If I try that, I get a context error and I'm not sure why...?

RuntimeError: Operator bpy.ops.object.mode_set.poll() failed, context is incorrect

    bpy.ops.import_scene.obj(filepath=source_to_file)

print("Starting--------------------------------------------")
for obj in bpy.data.objects:
bpy.context.scene.objects.active = obj
# go edit mode
bpy.ops.object.mode_set(mode='EDIT')
# select al faces
bpy.ops.mesh.select_all(action='SELECT')
# recalculate outside normals
bpy.ops.mesh.normals_make_consistent(inside=False)
# go object mode again
bpy.ops.object.editmode_toggle()
print("Ending--------------------------------------------")

bpy.ops.export_scene.obj(filepath=target_to_file,use_materials=True)


How is it possible to know the object imported by any operator (there is no return value) and how can I recalculate the normals per object that is triggered by a button?

You can use bpy.context.selected_objects[:] to get all imported objects. Iterate through the list, set the select state of each object to True and make it the active object as well in order to call operators like mesh.normals_make_consistent():

Blender 2.8+

import bpy

bpy.ops.import_scene.obj(filepath=source_to_file)
obj_objects = bpy.context.selected_objects[:]

for obj in obj_objects:
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
# go edit mode
bpy.ops.object.mode_set(mode='EDIT')
# select al faces
bpy.ops.mesh.select_all(action='SELECT')
# recalculate outside normals
bpy.ops.mesh.normals_make_consistent(inside=False)
# go object mode again
bpy.ops.object.editmode_toggle()


Blender 2.7x

import bpy

bpy.ops.import_scene.obj(filepath=source_to_file)
obj_objects = bpy.context.selected_objects[:]

for obj in obj_objects:
bpy.ops.object.select_all(action='DESELECT')
obj.select = True
bpy.context.scene.objects.active = obj
# go edit mode
bpy.ops.object.mode_set(mode='EDIT')
# select al faces
bpy.ops.mesh.select_all(action='SELECT')
# recalculate outside normals
bpy.ops.mesh.normals_make_consistent(inside=False)
# go object mode again
bpy.ops.object.editmode_toggle()


Updated .blend file can be found here:

• I have this error: AttributeError: 'Context' object has no attribute 'selected_objects' (I use 2.78a) Feb 1, 2017 at 0:01
• @D.Giunchi Could you provide your whole script to be able to debug it
– Tak
Feb 1, 2017 at 0:02
• pastebin.com/vpyi29Nq , I also used obj_objects = [ o for o in bpy.context.scene.objects if o.select ] but I got the first error. Feb 1, 2017 at 0:08
• @D.Giunchi I tried this pasteall.org/225375 and it's working totally fine with no errors
– Tak
Feb 1, 2017 at 0:20
• in the console I can see this: location: <unknown location>:-1 Error: Traceback (most recent call last): File "\fix.py", line 73, in <module> File "\fixpy", line 52, in main File "C:\Program Files\Blender Foundation\Blender\2.78\scripts\modules\bpy\ops.py", line 189, in call ret = op_call(self.idname_py(), None, kw) RuntimeError: Operator bpy.ops.object.mode_set.poll() failed, context is incorrect location: <unknown location>:-1 Error: Python script fail, look in the console for now... <!> event has invalid window Feb 1, 2017 at 0:53

Making normals outside can also be done with the bmesh module operator recalc_face_normals(bm, faces)

Sample script

import bpy
import bmesh

from bpy import context

#bpy.ops.import_scene.obj(filepath=source_to_file)
bm = bmesh.new()
meshes = set(o.data for o in context.selected_objects
if o.type == 'MESH')
for mesh in meshes:
bm.from_mesh(mesh)
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
bm.to_mesh(mesh)
bm.clear()
mesh.update()

bm.free()
#bpy.ops.export_scene.obj(filepath=target_to_file, use_materials=True)


Saves the need to flip mode and context object.

• I would upvote this answer 5 times if I could... I hate using the ops functions... Aug 17, 2018 at 19:40