bpy.context not working as expected

I had a script which included bpy.context. Once I'd built the script up with various other functions, it was no longer working properly.

Using advice from here: Problem with bpy.context.selected_objects I changed various lines to use bpy.context.scene.objects if o.select_get() instead of bpy.context.selected_objects.

That worked nicely when I substituted into several of my def functions. Unfortunately in one function I'm relying on a built-in module (not sure if that is the correct term):

from bl_operators.uvcalc_smart_project import main as uv_smart_project
uv_smart_project(bpy.context, .02, 30, 0.03, True, True)


That one no longer works either, but as it is a built-in module I can't easily go in and update the module to use o.select_get(). I get the error:

ob for ob in context.selected_editable_objects AttributeError: 'Context' object has no attribute 'selected_editable_objects'

If, after the main script fails, I run the two problematic lines in a separate text block, then it runs fine.

Edit:

I have used context = bpy.context throughout, as that seems to be a recurring comment around here. Also called the problematic script via a different text block, but no difference. Finally tried an override like this:

for window in context.window_manager.windows:
screen = window.screen

for area in screen.areas:
if area.type == 'VIEW_3D':
override = {'window': window, 'screen': screen, 'area': area}
uv_smart_project(override, .02, 30, 0.03, True, True)


But that gives me 'dict' object has no attribute 'mode' and I can't see how to add the mode to the override (if that is even a thing).

Is there another way to set the context correctly? Arbitrary selection/activation of an object in the 3D view, maybe?

• AFAIK cannot override edit mode. It either is or isn't in edit mode. Toggle the mesh object into edit mode before calling smart project. Also in what context are you calling from? – batFINGER May 28 '19 at 7:25
• That's my challenge really - I'm not sure what context I'm in. SmartProject is supposed to be acting on a load of meshes that are in object mode, so that they share the same UV space (i.e. a texture atlas), so I can't call it in Edit mode. The script imports meshes and then cleans them up etc, so I'm not sure why the context has shifted from the 3D view where all the previous functions have been operating. Is there a way to test what context I'm currently in and/or change it? – edna May 29 '19 at 3:54
• The last function before it goes awry is to move objects between collections. So maybe that moves the context to the Outliner/Collections? – edna May 29 '19 at 3:58

Thanks to iceythe on BlenderArtists I have resolved my problems in two ways. The first part is this:

for window in context.window_manager.windows:
screen = window.screen

for area in screen.areas:
if area.type == 'VIEW_3D':

tmp = bpy.context.copy()
tmp.update(window=window, screen=screen, area=area)

class Override:
pass

for key, val in tmp.items():
setattr(Override, key, val)
print('Unwrapping ...')
from bl_operators.uvcalc_smart_project import main as uv_smart_project
uv_smart_project(Override, .02, 30, 0.03, True, True)

return


The second part was a problem caused by my using save/reopen to clear orphaned data blocks, whereas this avoids the problem by using the purge function (which I knew about but had struggled to implement via a script):

context = bpy.context

def override():
for window in context.window_manager.windows:
for area in window.screen.areas:
if area.type == 'OUTLINER':
override_dict = {}
override_dict.update(area=area)
return override_dict

def ClearAll():

for c in context.scene.collection.children:

for c in bpy.data.collections:
if not c.users:
bpy.data.collections.remove(c)

for o in bpy.data.objects:
try:
bpy.data.objects.remove(o)
except:
print('All objects deleted')

override_dict = override()
if override_dict is not None:
bpy.ops.outliner.orphans_purge(override_dict)