Blog · DXF · 1 Oct 2026 · 3 min read
How to merge DXF files with Python and ezdxf without losing dimensions
Combining DXF files with ezdxf looks like a copy loop. Then dimensions disappear, blocks go missing, units turn into metres and the audit says zero errors. The traps we hit when an AI agent merged drawings into client files, and the rule for each.
Short answer: do not use ezdxf.addons.Importer for drawings with dimensions, do not pass DIMENSION or INSERT entities to add_foreign_entity, and copy block definitions together with their inserts. Set the units of a new file to millimetres. Then check the result in a CAD program and as an image: ezdxf's audit is not a test.
The traps, one by one
| Trap | What happens | Rule |
|---|---|---|
ezdxf.addons.Importer |
Loses the DIMENSION entities |
Copy entities and their resources yourself |
add_foreign_entity with DIMENSION or INSERT |
They vanish, no error | Copy those with their blocks and styles |
add_foreign_entity copies by default (copy=True) |
Transforming the source afterwards does nothing: 35 cells landed at the source coordinates, with "0 errors" | Transform the copy it returns |
entity.copy() on an INSERT |
Copies the reference, not the block definition | Copy the BLOCK too |
DIMENSION.transform() |
Does not enter the *D block, whose geometry is in absolute coordinates |
Transform the block content as well |
add_entity with a dimension |
Renames its block (*D6606 becomes *D1) |
Do not rely on *D names |
ezdxf.new() |
Sets units to metres ($INSUNITS=6) |
Set $INSUNITS to 4 (millimetres) |
| Filtering by layer | Drops real content on layer 0: 14 machining notes lost, report said "done: 37, 0 problems" |
Select by what the entity is, not by layer |
| Re-importing into the same file | "blocks added: 0" on a re-import means the old ones are still there | Delete the entities, then the blocks, then import |
| Finding "what is ours" by coordinates | Moves or deletes the wrong things | Use a name prefix plus layer |
| Taking the sheet border from the leftmost geometry | Wrong frame | Use $EXTMIN / $EXTMAX |
| The target DXF is open in a CAD program | PermissionError: [WinError 32] |
Close it first |
Units: the one that multiplies by 1000
ezdxf.new() declares metres. 120 cells out of 136 came out declared in metres. Inserted into a drawing with automatic scaling, they were multiplied by 1000. One line fixes it:
doc = ezdxf.new()
doc.header["$INSUNITS"] = 4 # millimetres
Missing blocks that only CAD sees
ezdxf's audit reported 0 errors. BricsCAD reported Empty Record name: <AcDbBlockReference>. The cause: inserts copied without their block definitions. What caught it was a raw text count of the DXF: 12 occurrences of AcDbBlockReference, 0 of BLOCK.
A simple check the agent can run after every merge: every block name used by an INSERT must exist in doc.blocks.
used = {e.dxf.name for e in doc.modelspace().query("INSERT")}
missing = sorted(n for n in used if n not in doc.blocks)
print("missing blocks:", missing or "none")
Names: styles and blocks collide
When drawings are merged, two resources with the same name and different content become one. That moves dimensions and swaps sections between sheets. These two have their own guides:
How to check a merged file
- Open it in a CAD program, not only in ezdxf.
- Count by type per source sheet, before and after: dimensions, inserts, texts.
- Check every insert draws inside its own sheet frame.
- Render it to an image and look. See how to let an AI see a DXF.
Do and don't
Do
- Set millimetres on every new file.
- Copy block definitions with their inserts.
- Mark your own content with a name prefix and a layer.
- Check in CAD and in an image.
Don't
- Don't use the
Importeradd-on for dimensioned drawings. - Don't hand dimensions or inserts to
add_foreign_entity. - Don't filter by layer to decide what to copy.
- Don't take "0 errors" from the audit as proof.
Questions people ask
Which ezdxf version is this? ezdxf 1.4.4 on Python 3.14.
Why not just paste in AutoCAD or BricsCAD? For one sheet, do. For dozens of sheets merged the same way every time, a script is repeatable and can check itself, as long as it checks the right things.