Format Decorators
The @format_reader() and @format_writer() decorators register classes as custom import/export formats in LinkCAD.
@format_reader()
Signature
@format_reader( name: str, extensions: list[str], description: str = "",)class MyReader(FormatReader): def read(self, path: Path, drawing: DrawingContext) -> None: ...Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
name | str | required | Format display name |
extensions | list[str] | required | File patterns (e.g. ["*.gds", "*.gdsii"]) |
description | str | "" | Format description |
FormatReader Base Class
class FormatReader: def read(self, path: Path, drawing: DrawingContext) -> None: """Override to implement file import logic.""" ...
def post_process(self, phase, drawing, resolution) -> bool: """Optional. Take part in the phases LinkCAD runs after parsing.""" return TrueThe DrawingContext provides a builder API for constructing the drawing. Name your working unit once and LinkCAD converts everything you hand it — a reader should not carry its own scale table:
def read(self, path: Path, drawing: DrawingContext) -> None: drawing.units = "um" # coordinates below are microns with drawing.cell("main", main=True) as cell: with cell.layer("metal1") as layer: layer.polygon([(0, 0), (100, 0), (100, 100), (0, 100)]) layer.polyline(10, [(0, 0), (200, 200)], closed=False) layer.circle((500, 500), 200)Accepted units are nm, um, mil, mm, cm, inch, and m, plus aliases such as micron and millimetre. Leaving units unset means raw database units. An unknown name, or a drawing that does not declare its database units, raises ValidationError.
post_process()
post_process() is optional — the same hook the built-in native readers use. It is called once per phase after parsing, on the same instance as read(), so anything you recorded there is still available. Return False to abort the import.
from linkcad.v1.plugin import Phase
class MyReader(FormatReader): def post_process(self, phase, drawing, resolution) -> bool: if phase == Phase.ResolvedRefs: ... # every reference now points at a real cell return True| Phase | Reached when |
|---|---|
Phase.ParsedFile | One input file has been parsed |
Phase.ParsedAll | Every input file has been parsed |
Phase.ClosedOpenCells | Cells left open by the parser have been closed |
Phase.ResolvedRefs | Every reference points at a real cell |
Phase.SelectedMainCell | The main cell has been chosen |
Phase.ResolvedLayersByBlock | ByBlock layer inheritance has been resolved |
Phase.AutoNumberedZ | Layer Z ordering has been assigned |
@format_writer()
Signature
@format_writer( name: str, extensions: list[str], description: str = "",)class MyWriter(FormatWriter): def write(self, path: Path, drawing: WriterContext) -> None: ...Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
name | str | required | Format display name |
extensions | list[str] | required | File patterns |
description | str | "" | Format description |
FormatWriter Base Class
class FormatWriter: def write(self, path: Path, drawing: WriterContext) -> None: """Override to implement file export logic.""" ...The WriterContext provides read access to the drawing. As with readers, name your working unit and the geometry arrives already converted:
def write(self, path: Path, drawing: WriterContext) -> None: drawing.units = "mm" # coordinates below are millimetres drawing.flatten = True # resolve cell references into placed shapes with open(path, "w") as f: for shape in drawing.shapes(): f.write(f"{shape.layer_name}: {len(shape.vertices)} vertices\n")shapes() is the single traversal for geometry. Set flatten before iterating: with flatten = False you get each cell’s own shapes and handle references yourself; with flatten = True the host renders the hierarchy, applies the transformation stack, and tessellates curves along the way.
FormatInfo
Both decorators create a FormatInfo object attached to the class, and replace info() with a static method returning it:
| Field | Description |
|---|---|
name | Format display name |
extensions | List of file patterns |
description | Format description |
options | The Option attributes collected from the class |
Registration
Registered formats automatically appear in LinkCAD’s Open/Save dialogs:
- Readers are listed in the File → Open format dropdown
- Writers are listed in the File → Save As format dropdown
The extensions list determines file type association. For example:
@format_reader(name="My Format", extensions=["*.myf", "*.myfx"])This adds “My Format (*.myf, *.myfx)” to the Open dialog.