operation being performed on previously selected object

I’m looping through a few objects and performing a couple of operations on each. Everything works fine in the first iteration of the loop. However, in the second iteration, I’m finding that the first object is still being operated upon, rather than the second object.

I’m selecting each object via bpy.context.select_pattern(), with extend=False. A subsequent call to bpy.context.selected_objects returns an array containing a single element, namely the object I attempted to select (e.g. the ‘second’ object). When my script fails, I find in the UI that the first object is still selected, and that an operation performed in the second iteration was performed on the first object, even though selected_objects told me it wasn’t selected.

Even though bpy.context.selected_objects returns an empty array, I’ve tried setting the first object’s ‘select’ property to False, and calling bpy.ops.object.select_all(action=‘DESELECT’). I’ve looped through each object and tested its ‘select’ property, and none report being selected. And yet…

What would cause this behavior?

There’s a big chance operator works on the active object.

Here is a code snippet from the console, default file, Camera selected.
Use scene.objects.active to set the object you want as active.
Note the code here I can end up with no selected objects but the Cube remains active and will be the subject of any operator that uses context.active_object or context.object as its target.


>>> C.object
bpy.data.objects['Camera']


>>> C.selected_objects
[bpy.data.objects['Camera']]


>>> ob = D.objects["Cube"]
>>> C.scene.objects.active = ob
>>> C.object
bpy.data.objects['Cube']


>>> C.active_object
bpy.data.objects['Cube']


>>> C.selected_objects
[bpy.data.objects['Camera']]


>>> bpy.ops.object.select_all(action='DESELECT')
{'FINISHED'}


>>> C.selected_objects
[]


>>> C.object
bpy.data.objects['Cube']


>>> 

The API documentation is horrendous. If an operation acts upon the active object, then the writer should have stated that. It seems in most cases that the writer wrote just enough for the space not to be blank. It is not uncommon for a description to convey no more information than did the method or property name.

And then there are the cases where the documentation is just plain wrong.

If I had written much of the API documentation I would be truly ashamed of my work.

@batFINGER Thanks. I had just figured that out and was writing my previous post while you were responding.

So, this leads me to another question, my understanding is that the active object is the last selected object. Is that correct? If so, when I selected the second object during the loop’s second iteration, why didn’t it become the active object?

the API states that operators represent user actions:
http://www.blender.org/documentation/blender_python_api_2_65_9/info_quickstart.html#operators-tools

and that they use the current context:
http://www.blender.org/documentation/blender_python_api_2_65_9/info_gotcha.html#using-operators

But I agree that this should be noted on the bpy.ops page as well…

What an operator works on differs, but most object ops use the active object and/or the selected objects. If you wanna know what they use, then you gotta go to the c-code as most ops are c-written. In most situations, it is enough to see how the operator behaves in blender.

Usually, the object you selected last is selected + the active one. But there can be selected objects and no active one.

Because last selected object becomes active only when you manually select it. It doesn’t work this way in scripts.

“select” is a property of a single object. To make object selected you say:

ob.select = True

(assuming ob is your object)

“active” is a property of a scene.objects, meaning the list of all objects linked to scene. Only one object can be active. So you say:

scene.objects.active = ob

(assuming scene is your scene)

This makes object: “ob” active.

It is possible to have some object active but nor selected. It is possible not to have any active object. Several objects can be selected, but only one can be active.

I’ve already read that. And, if I select a single object through the UI then it becomes both selected and active. Since operators represent user actions, then bpy.ops.select_pattern(pattern=“MyObject”, case-sensitive=True, extend=False) should leave MyObject both selected and active. Except… it doesn’t. And this is behavior is not documented under select_pattern(). So operators don’t really represent user actions. Not really.

I already read that too.

Well, yeah. The question is which does each operator work on. Each operator must document what it works on. Otherwise the API user gets to guess.

Are you a Blender developer? Does this represent the general opinion of Blender developers?

Every user of every operator wants to know what object(s) the operator will operate upon. If each operator acted upon a random object, then the API would be utterly useless. If each operator chose, upon each invocation, to operate either upon the selected object(s) or the active object, then the API would be fairly useless. If each operator deterministically works upon either the selected object(s) or the active object, but which one is unknown, then the API is useless.

You want each API user to go trawling through the C code base to learn what each operator does? Seriously? Life is too short. And what about those who don’t know C? In order to use the Python API one needs to read C?

Perhaps it is. As far as I can tell, bpy.ops.select_pattern() does not behave as selection does in the UI. The actual behavior should have been documented.

Thanks. That’s what I was looking for.

I just can’t get the hang of the Blender API. A programmer with my level of ability and experience simply should not be having this much trouble.

if I select a single object through the UI then it becomes both selected and active

you are right, that is ONE user action but actually TWO things happen. But I take the view, that this kind of object selection isn’t an operator - there is no bpy.ops.object.select_by_click or similar, if it was, then it should act like a selection click of course.

should leave MyObject both selected and active […] select_pattern() does not behave as selection does in the UI

Hm, it would be nicer if select_pattern kept the object active (maybe report as bug, although it will likely be considered a feature request). But the behavior seems consistent between UI and API call?!

Each operator must document what it works on.

most operators should tell what they will do by their name, select_pattern does change selection as the name implies. So you get what you expect, a new/changed selection. The clearing of the active object in case of extend=False and the active object being matched by the pattern is sort of a side-effect, maybe worth mentioning but rather to be fixed in code.

Of course it would be nice to have all involved objects documented, but I worry API pages would get messy, as many ops use quite a lot objects. And these objects may change but the devs may forget to update API or API might simply stay incomplete (some ops explained in detail, others not). And if you really want to know what an operator does, well, I’d prefer to read the code myself - although I will never fully understand it, as I’m by far not a coder - and try to guess from var names (which seemed rather intuitive whenever i tried).

Anyway, if you say each op must be documented, get some help by someone who knows a bit C/Blender code and write docs - everyone would benefit! :slight_smile:

Are you a Blender developer? Does this represent the general opinion of Blender developers?

No and maybe?

If each operator acted upon a random object, […] each operator chose […] each operator deterministically works upon either the selected object(s) or the active object, but which one is unknown, then the API is useless.

only the select_random operator implies that it will randomly chose objects. In all other cases, UI and API behavior appears to be consistent and you can easily see in viewport if the active object is treated differently from selected objects. But well, a hint in the docs if the active object takes a special role wouldn’t hurt.

In order to use the Python API one needs to read C?

would be enough to know that there is a selection state and an active object. You may always set an active object to be sure ops will work, even if they don’t care about the active “state”.