Assuming your cutter line is extruded along the Z axis, you can use it in a Boolean modifier and invert its normals to get one part or the other.
It requires duplicating the mesh beforehand, and it seems it works reliably only with the Exact method. It might also break with more complex or non-manifold geometry. It's pretty reliable but very slow on dense meshes.
Starting with this setup :


As a python script :
import bpy
import bmesh
cutter = bpy.context.active_object
cutter_mesh = cutter.data
col = cutter.users_collection[0]
bm = bmesh.new()
bm.from_mesh(cutter_mesh)
bm_flipped = bm.copy()
for f in bm_flipped.faces:
f.normal_flip()
selected_objects = bpy.context.selected_objects
for i in range(2):
for obj in selected_objects:
if obj.type != "MESH" or obj == cutter:
continue
part = obj.copy()
part.data = obj.data.copy()
col.objects.link(part)
mod = part.modifiers.new(type="BOOLEAN", name="Bool")
mod.object = cutter
bpy.ops.object.modifier_apply({"object": part}, modifier="Bool")
bm_flipped.to_mesh(cutter_mesh)
bm.to_mesh(cutter_mesh) # Restore previous normals
bm.free() # Not mandatory, but it can help if the mesh is modified elsewhere in code
Or to modify the object mesh in place (might be more optimized ways) :
import bpy
import bmesh
cutter = bpy.context.active_object
cutter_mesh = cutter.data
col = cutter.users_collection[0]
bm = bmesh.new()
bm.from_mesh(cutter_mesh)
bm_flipped = bm.copy()
for f in bm_flipped.faces:
f.normal_flip()
selected_objects = [o for o in bpy.context.selected_objects if o.type == "MESH" and o != cutter]
parts = []
for i in range(2):
for obj in selected_objects:
part = obj.copy()
part.data = obj.data.copy()
col.objects.link(part)
mod = part.modifiers.new(type="BOOLEAN", name="Bool")
mod.object = cutter
bpy.ops.object.modifier_apply({"object": part}, modifier="Bool")
parts.append(part)
bm_flipped.to_mesh(cutter_mesh)
for i, obj in enumerate(selected_objects):
mesh = obj.data
offset = 0
verts = []
faces = []
for j in range(2):
part_mesh = parts[i * 2 + j].data
verts.extend([v.co for v in part_mesh.vertices])
for face in part_mesh.polygons:
faces.append([idx + offset for idx in face.vertices])
offset = len(part_mesh.vertices)
bpy.data.objects.remove(parts[i* 2 + j])
bpy.data.meshes.remove(part_mesh)
mesh.clear_geometry()
mesh.from_pydata(verts, (), faces)
mesh.update()
bm.to_mesh(cutter_mesh)
bm.free()
bm_flipped.free()