Is there a simple/concise explanation out there of script manipulation of mesh objects?
it's simple in that case.

ob = bpy.ops.mesh.primitive_uv_sphere_add()
print(ob)
&gt;&gt;&gt; {'FINISHED'}


The docs for mesh.primitive_uv_sphere_add don't explicitly mention a return type, and that's a first hint that it won't have a very useful return value.

There are 2 main ways to get object references. Either by:

# getting the reference by object name 
ob = bpy.data.objects['Sphere']

# or using the fact that calls to bpy.ops.mesh_xxxxx
# place new objects as the active_object.
bpy.ops.mesh.primitive_uv_sphere_add()
ob = bpy.context.active_object


unlike objects of type BlendDataObjects. These are found in bpy.data.

data.objects
data.meshes
data.materials
# etc


The new() method for those Objects does return an Object reference.

ob = bpy.data.objects.new('tim_the_object', me)




A good approach to learning the bpy is to use that print() statement on objects, or dir(). I'm fairly confident in my bpy-knowledge, but I still use those methods to understand the return values on occasion, and I use dir(whatever) constantly.

Hit control+space after typing this in the python console:

&gt;&gt;&gt; bpy.ops.mesh.primitive_uv_sphere_add(   


It will return a lot of information about the function signature, and that works for most functions. But not all functions have elaborate docstrings to tell us the return values (then you use print() )

active_material

your code

ao.active_material = purple  # Nope!
bpy.ops.object.shade_smooth()  # Nope!


assumes that purple is a reference to a material, if that failed, then the next line will also fail.

# this assumes you have a material, called 'purple'
ao.active_material = bpy.data.materials['purple']
bpy.ops.object.shade_smooth()  # probably works with an active object.


this does work:

import bpy

bpy.ops.mesh.primitive_uv_sphere_add(size=1, location=(3,3,3))
ao = bpy.context.active_object
ao.active_material = bpy.data.materials['purple']
bpy.ops.object.shade_smooth()