No need for bases in 2.8 join operator override.
Thought I would also post this here. It appears at 2.80 beta version, there is no need to have the selected editable bases context member, instead use selected editable objects
Testing this in python console. Have duped the default cube 3 times, the last dupe "Cube.003" is active and only object selected.
>>> C.object
bpy.data.objects['Cube.003']
>>> C.selected_objects
[bpy.data.objects['Cube.003']]
A list of all the mesh objects in scene to join
>>> obs = [o for o in C.scene.objects if o.type == 'MESH']
>>> obs
[bpy.data.objects['Cube'], bpy.data.objects['Cube.001'], bpy.data.objects['Cube.002'], bpy.data.objects['Cube.003']]
Make a context override dictionary, with only object, active_object, selected_objects, selected_editable_objects
as members
>>> c = {}
>>> c["object"] = c["active_object"] = C.object
>>> c["selected_objects"] = c["selected_editable_objects"] = obs
Blender 2.8 - 3.1:
Run the operator with this override
>>> bpy.ops.object.join(c)
{'FINISHED'}
Blender 3.2+ :
with C.temp_override(active_object=C.active_object, selected_editable_objects=obs):
bpy.ops.object.join()
Resulting scene after running. All four cubes are joined as one "Cube.003", The result desired
>>> C.scene.objects[:]
[bpy.data.objects['Lamp'], bpy.data.objects['Camera'], bpy.data.objects['Cube.003']]
Risky look at obs since three of the objects no longer exist.
>>> obs
[<bpy_struct, Object invalid>, <bpy_struct, Object invalid>, <bpy_struct, Object invalid>, bpy.data.objects['Cube.003']]
Further to this, can make object copies into the data collection and join them. Here i am copying the object 3 times, and then joining all mesh objects into file as one.
>> for i in range(3):
... o.copy()
...
bpy.data.objects['Cube.000']
bpy.data.objects['Cube.001']
bpy.data.objects['Cube.002']
>>> obs = [o for o in D.objects if o.type == 'MESH']
"Array them to see result"
>> for o in obs:
... o.location.z += ob.dimensions.z
...
>>> c = {}
>>> c["object"] = c["active_object"] = C.object
>>> c["selected_objects"] = c["selected_editable_objects"] = obs
>>> bpy.ops.object.join(c)
{'FINISHED'}
the dupes will remain in data, the object "Cube.003" will be a mesh made of all others.