diff --git a/examples/depsgraph-export/depsgraph_export.py b/examples/depsgraph-export/depsgraph_export.py index 72b5e1f3..df8bb3a0 100644 --- a/examples/depsgraph-export/depsgraph_export.py +++ b/examples/depsgraph-export/depsgraph_export.py @@ -369,22 +369,36 @@ def check(shell, obj_path, unevaluated=False): V, E, F, S = len(me.vertices), len(me.edges), len(me.polygons), len(me.loops) expected = catmull_clark_vcount(V, E, F, S, SUBSURF_LEVELS) - out = obj_path or os.path.join(tempfile.gettempdir(), "depsgraph_export.obj") + # A per-run name, removed before and after: a fixed name let a previous + # run's OBJ satisfy the "file exists" check below when this export wrote + # nothing, and Blender points TMPDIR at the working directory (#404). + out = obj_path or os.path.join(tempfile.gettempdir(), + f"depsgraph_export_{os.getpid()}.obj") os.makedirs(os.path.dirname(os.path.abspath(out)) or ".", exist_ok=True) - # obj_export writes the evaluated (modifier-applied) geometry by default - bpy.ops.wm.obj_export( - filepath=out, - export_selected_objects=False, - apply_modifiers=not unevaluated, - ) - if not (os.path.exists(out) and os.path.getsize(out) > 0): - print("ERROR: no OBJ written", file=sys.stderr) - return 4 - exported = 0 - with open(out, encoding="utf-8") as f: - for line in f: - if line.startswith("v "): - exported += 1 + sidecars = [out, os.path.splitext(out)[0] + ".mtl"] + for path in sidecars: + if os.path.exists(path): + os.remove(path) + try: + # obj_export writes the evaluated (modifier-applied) geometry by default + bpy.ops.wm.obj_export( + filepath=out, + export_selected_objects=False, + apply_modifiers=not unevaluated, + ) + if not (os.path.exists(out) and os.path.getsize(out) > 0): + print("ERROR: no OBJ written", file=sys.stderr) + return 4 + exported = 0 + with open(out, encoding="utf-8") as f: + for line in f: + if line.startswith("v "): + exported += 1 + finally: + if not obj_path: + for path in sidecars: + if os.path.exists(path): + os.remove(path) print(f"shell_cage V={V} E={E} F={F} S={S} levels={SUBSURF_LEVELS} " f"shell_eval_vcount={shell_eval} closed_form={expected}") diff --git a/showcase/hay-bale/hay_bale.py b/showcase/hay-bale/hay_bale.py index ffef53d6..67599dba 100644 --- a/showcase/hay-bale/hay_bale.py +++ b/showcase/hay-bale/hay_bale.py @@ -453,9 +453,11 @@ def belt_seat_depths(me, loaf_comp, belt_comp, station_x, segs): pass if not bm.faces: return [] + # FromBMesh copies the geometry into the tree, so the BMesh can be + # freed here, on the early return and the normal path alike. bvh = BVHTree.FromBMesh(bm) finally: - pass + bm.free() zs = [me.vertices[i].co.z for i in loaf_comp] cz = 0.5 * (min(zs) + max(zs)) buckets = {} @@ -498,7 +500,6 @@ def depth(co): vals = [d for d in (depth(co) for co in buckets[k]) if d is not None] if vals: depths.append(max(vals)) - bm.free() return depths @@ -1142,13 +1143,15 @@ def check(skip_decimate, lift_z=False, stray_vert=False, slack_belt=False, low.data.update() if stray_vert: bm = bmesh.new() - bm.from_mesh(low.data) - # Inside the existing AABB: a stray vertex parked above the bale - # blew the bounding-box budget (exit 8) before the hygiene gate - # could see it, so it proved nothing about hygiene. - bm.verts.new((0.0, 0.0, BALE_Z * 0.5)) - bm.to_mesh(low.data) - bm.free() + try: + bm.from_mesh(low.data) + # Inside the existing AABB: a stray vertex parked above the bale + # blew the bounding-box budget (exit 8) before the hygiene gate + # could see it, so it proved nothing about hygiene. + bm.verts.new((0.0, 0.0, BALE_Z * 0.5)) + bm.to_mesh(low.data) + finally: + bm.free() low.data.update() if low.data is None or len(low.data.polygons) < 6: