Convert mesh created with pydata to curves

Hey all - whilst I’m moderately comfortable with Python, I’m still getting to grips with the Blender Python API, so bear with me! :wink:

I’ve got a script where I create a mesh with pydata. Without going into too much detail, I’ve got an issue coverting this resulting mesh (essentially just a path; just vertices and edges, no faces) into a curve.

The script successfully creates the mesh and in the 3D window I can select it and covert it to a curve. However, in my script I get the error below. Conceptually, I get it… but I don’t know how I can work around it:

Error message:

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

Relevant code:

def create_mesh (self):
        
        
        verts = []
        edges = []
        for t in range (self.age):
            verts.append (Vector((self.x[t],self.y[t],self.z[t])))
            if t>0:
                edges.append (((t-1),(t)))
        
        mesh = bpy.data.meshes.new("vertice_id"+str(self.id))
        mesh.from_pydata(verts, edges, [])
        ob = bpy.data.objects.new("path_id"+str(self.id), mesh)
        
        bpy.context.scene.collection.objects.link(ob)
        bpy.ops.object.convert(target='CURVE')

I’ve tried various ways to select/make the mesh object active, but nothing seems to work. I’m using Blender 3.2.

Hope this makes sense?

cheers

Hi. Could you share your full script. self.age for example, is not given or stated in your shared script.

1 Like

Hi - I condensed it down to a smaller script that exhibited the error. This also helped me to try to find out what’s going on. I managed to "fix"it, but I have to say, I’m not sure if this is the best/optimal way. In the end it seems it had to do with the way the object was made active. The line below made all the difference:

bpy.context.view_layer.objects.active = ob

Full script:

import bpy

#delete unlinked meshes and objects

for block in bpy.data.meshes:
    if block.users == 0:
        bpy.data.meshes.remove(block)
for block in bpy.data.objects:
    if block.users == 0:
        bpy.data.objects.remove(block)


#create mesh without faces, create object and link 

verts = [((0,0,0)),((0,1,0))]
edges = [(0,1)]
faces = []

mesh = bpy.data.meshes.new("vertice_id")
mesh.from_pydata(verts, edges, faces)
ob = bpy.data.objects.new("Now", mesh)
bpy.context.scene.collection.objects.link(ob)

#select object and convert to curve 

bpy.data.objects[ob.name].select_set(state = True, view_layer = bpy.context.view_layer)
bpy.context.view_layer.objects.active = ob
bpy.ops.object.convert(target='CURVE')

To be honest, I’m still a bit lost on some of the finer aspects of the API! Especially when Googling and finding answers that apply to older APIs etc :wink:

Operators will often need their context overridden.
Additionally, when attempting to use operators on modified scene/view layer data, or sequencing operators, it’s also often necessary to call the view layer update method bpy.context.view_layer.update() between calls.

1 Like

Many thanks for that. I’ll have a bit of reading to do!

If you run the script from the text editor you would have trouble with the context. But if you turn the script into an operator you would get the correct context, since for example you invoke the operator from 3D viewport while in Object Mode usually this allows operators to run normally.

see: blender\3.2\scripts\templates_py\operator_simple.py
1 Like

sorry, I never got a notification…that’s interesting! Thanks so much!

1 Like