"""Board layout elements for KiCad S-expressions - PCB/board design and routing."""
from dataclasses import dataclass, field
from typing import Any, ClassVar, List, Optional, Union
from .advanced_graphics import GrArc, GrLine, GrPoly, GrText
from .base_element import (
NamedFloat,
NamedInt,
NamedObject,
NamedString,
ParseStrictness,
TokenFlag,
)
from .base_types import (
At,
BoardLayers,
End,
Layer,
Layers,
Mid,
Property,
Start,
Uuid,
)
from .footprint_library import Footprint
from .pad_and_drill import Net
from .text_and_documents import Group
from .zone_system import Zone
[docs]
@dataclass
class Nets(NamedObject):
"""Nets section definition token.
The 'nets' token defines nets for the board in the format::
(net
ORDINAL
"NET_NAME"
)
Args:
net_definitions: List of net definitions (ordinal, net_name)
"""
__token_name__: ClassVar[str] = "nets"
net_definitions: List[tuple[Any, ...]] = field(
default_factory=list,
metadata={"description": "List of net definitions (ordinal, net_name)"},
)
[docs]
@dataclass
class PrivateLayers(NamedObject):
"""Private layers definition token.
The 'private_layers' token defines layers private to specific elements in the format::
(private_layers "LAYER_LIST")
Args:
layers: List of private layer names
"""
__token_name__: ClassVar[str] = "private_layers"
layers: List[str] = field(
default_factory=list, metadata={"description": "List of private layer names"}
)
[docs]
@dataclass
class Segment(NamedObject):
"""Track segment definition token.
The 'segment' token defines a track segment in the format::
(segment
(start X Y)
(end X Y)
(width WIDTH)
(layer LAYER_DEFINITION)
[(locked)]
(net NET_NUMBER)
(tstamp UUID)
)
Args:
start: Coordinates of the beginning of the line
end: Coordinates of the end of the line
width: Line width
layer: Layer the track segment resides on
locked: Whether the line cannot be edited (optional)
net: Net ordinal number from net section
tstamp: Unique identifier of the line object (optional)
uuid: Unique identifier
"""
__token_name__: ClassVar[str] = "segment"
start: Start = field(
default_factory=lambda: Start(),
metadata={"description": "Coordinates of the beginning of the line"},
)
end: End = field(
default_factory=lambda: End(),
metadata={"description": "Coordinates of the end of the line"},
)
width: NamedFloat = field(
default_factory=lambda: NamedFloat("width", 0.0),
metadata={"description": "Line width"},
)
layer: Layer = field(
default_factory=lambda: Layer(),
metadata={"description": "Layer the track segment resides on"},
)
locked: TokenFlag = field(
default_factory=lambda: TokenFlag("locked"),
metadata={
"description": "Whether the line cannot be edited",
"required": False,
},
)
net: NamedInt = field(
default_factory=lambda: NamedInt(token="net", value=0),
metadata={"description": "Net ordinal number from net section"},
)
tstamp: NamedString = field(
default_factory=lambda: NamedString("tstamp", ""),
metadata={
"description": "Unique identifier of the line object",
"required": False,
},
) # NEW Variant
uuid: Optional[Uuid] = field(
default_factory=lambda: Uuid(), metadata={"description": "Unique identifier"}
) # Old Variant
[docs]
@dataclass
class Tenting(NamedObject):
"""Tenting configuration for front/back sides.
Args:
sides: List of sides (front/back)
"""
__token_name__: ClassVar[str] = "tenting"
sides: List[str] = field(
default_factory=list, metadata={"description": "List of sides (front/back)"}
)
[docs]
@dataclass
class PcbPlotParams(NamedObject):
"""PCB plot parameters - stores all plotting settings.
Args:
layerselection: Layer selection hex mask (optional)
plot_on_all_layers_selection: Plot on all layers selection (optional)
disableapertmacros: Disable aperture macros (optional)
usegerberextensions: Use gerber extensions (optional)
usegerberattributes: Use gerber attributes (optional)
usegerberadvancedattributes: Use gerber advanced attributes (optional)
creategerberjobfile: Create gerber job file (optional)
dashed_line_dash_ratio: Dashed line dash ratio (optional)
dashed_line_gap_ratio: Dashed line gap ratio (optional)
svgprecision: SVG precision (optional)
plotframeref: Plot frame reference (optional)
mode: Plot mode (optional)
useauxorigin: Use auxiliary origin (optional)
hpglpennumber: HPGL pen number (optional)
hpglpenspeed: HPGL pen speed (optional)
hpglpendiameter: HPGL pen diameter (optional)
pdf_front_fp_property_popups: PDF front footprint property popups (optional)
pdf_back_fp_property_popups: PDF back footprint property popups (optional)
pdf_metadata: PDF metadata (optional)
pdf_single_document: PDF single document (optional)
dxfpolygonmode: DXF polygon mode (optional)
dxfimperialunits: DXF imperial units (optional)
dxfusepcbnewfont: DXF use pcbnew font (optional)
psnegative: PS negative (optional)
psa4output: PS A4 output (optional)
plot_black_and_white: Plot black and white (optional)
plotinvisibletext: Plot invisible text (optional)
sketchpadsonfab: Sketch pads on fab (optional)
plotpadnumbers: Plot pad numbers (optional)
hidednponfab: Hide DNP on fab (optional)
sketchdnponfab: Sketch DNP on fab (optional)
crossoutdnponfab: Cross out DNP on fab (optional)
subtractmaskfromsilk: Subtract mask from silk (optional)
outputformat: Output format (optional)
mirror: Mirror (optional)
drillshape: Drill shape (optional)
scaleselection: Scale selection (optional)
outputdirectory: Output directory (optional)
"""
__token_name__: ClassVar[str] = "pcbplotparams"
layerselection: NamedString = field(
default_factory=lambda: NamedString(
"layerselection", "0x00000000_00000000_55555555_5755f5ff"
),
metadata={"description": "Layer selection hex mask", "required": False},
)
plot_on_all_layers_selection: NamedString = field(
default_factory=lambda: NamedString(
"plot_on_all_layers_selection", "0x00000000_00000000_00000000_00000000"
),
metadata={"description": "Plot on all layers selection", "required": False},
)
disableapertmacros: TokenFlag = field(
default_factory=lambda: TokenFlag("disableapertmacros", "no"),
metadata={"description": "Disable aperture macros", "required": False},
)
usegerberextensions: TokenFlag = field(
default_factory=lambda: TokenFlag("usegerberextensions", "no"),
metadata={"description": "Use gerber extensions", "required": False},
)
usegerberattributes: TokenFlag = field(
default_factory=lambda: TokenFlag("usegerberattributes", "yes"),
metadata={"description": "Use gerber attributes", "required": False},
)
usegerberadvancedattributes: TokenFlag = field(
default_factory=lambda: TokenFlag("usegerberadvancedattributes", "yes"),
metadata={"description": "Use gerber advanced attributes", "required": False},
)
creategerberjobfile: TokenFlag = field(
default_factory=lambda: TokenFlag("creategerberjobfile", "yes"),
metadata={"description": "Create gerber job file", "required": False},
)
dashed_line_dash_ratio: NamedFloat = field(
default_factory=lambda: NamedFloat("dashed_line_dash_ratio", 12.0),
metadata={"description": "Dashed line dash ratio", "required": False},
)
dashed_line_gap_ratio: NamedFloat = field(
default_factory=lambda: NamedFloat("dashed_line_gap_ratio", 3.0),
metadata={"description": "Dashed line gap ratio", "required": False},
)
svgprecision: NamedInt = field(
default_factory=lambda: NamedInt("svgprecision", 4),
metadata={"description": "SVG precision", "required": False},
)
plotframeref: TokenFlag = field(
default_factory=lambda: TokenFlag("plotframeref", "no"),
metadata={"description": "Plot frame reference", "required": False},
)
mode: NamedInt = field(
default_factory=lambda: NamedInt("mode", 1),
metadata={"description": "Plot mode", "required": False},
)
useauxorigin: TokenFlag = field(
default_factory=lambda: TokenFlag("useauxorigin", "no"),
metadata={"description": "Use auxiliary origin", "required": False},
)
hpglpennumber: NamedInt = field(
default_factory=lambda: NamedInt("hpglpennumber", 1),
metadata={"description": "HPGL pen number", "required": False},
)
hpglpenspeed: NamedInt = field(
default_factory=lambda: NamedInt("hpglpenspeed", 20),
metadata={"description": "HPGL pen speed", "required": False},
)
hpglpendiameter: NamedFloat = field(
default_factory=lambda: NamedFloat("hpglpendiameter", 15.0),
metadata={"description": "HPGL pen diameter", "required": False},
)
pdf_front_fp_property_popups: TokenFlag = field(
default_factory=lambda: TokenFlag("pdf_front_fp_property_popups", "yes"),
metadata={
"description": "PDF front footprint property popups",
"required": False,
},
)
pdf_back_fp_property_popups: TokenFlag = field(
default_factory=lambda: TokenFlag("pdf_back_fp_property_popups", "yes"),
metadata={
"description": "PDF back footprint property popups",
"required": False,
},
)
pdf_metadata: TokenFlag = field(
default_factory=lambda: TokenFlag("pdf_metadata", "yes"),
metadata={"description": "PDF metadata", "required": False},
)
pdf_single_document: TokenFlag = field(
default_factory=lambda: TokenFlag("pdf_single_document", "no"),
metadata={"description": "PDF single document", "required": False},
)
dxfpolygonmode: TokenFlag = field(
default_factory=lambda: TokenFlag("dxfpolygonmode", "yes"),
metadata={"description": "DXF polygon mode", "required": False},
)
dxfimperialunits: TokenFlag = field(
default_factory=lambda: TokenFlag("dxfimperialunits", "yes"),
metadata={"description": "DXF imperial units", "required": False},
)
dxfusepcbnewfont: TokenFlag = field(
default_factory=lambda: TokenFlag("dxfusepcbnewfont", "yes"),
metadata={"description": "DXF use pcbnew font", "required": False},
)
psnegative: TokenFlag = field(
default_factory=lambda: TokenFlag("psnegative", "no"),
metadata={"description": "PS negative", "required": False},
)
psa4output: TokenFlag = field(
default_factory=lambda: TokenFlag("psa4output", "no"),
metadata={"description": "PS A4 output", "required": False},
)
plot_black_and_white: TokenFlag = field(
default_factory=lambda: TokenFlag("plot_black_and_white", "yes"),
metadata={"description": "Plot black and white", "required": False},
)
plotinvisibletext: TokenFlag = field(
default_factory=lambda: TokenFlag("plotinvisibletext", "no"),
metadata={"description": "Plot invisible text", "required": False},
)
sketchpadsonfab: TokenFlag = field(
default_factory=lambda: TokenFlag("sketchpadsonfab", "no"),
metadata={"description": "Sketch pads on fab", "required": False},
)
plotpadnumbers: TokenFlag = field(
default_factory=lambda: TokenFlag("plotpadnumbers", "no"),
metadata={"description": "Plot pad numbers", "required": False},
)
hidednponfab: TokenFlag = field(
default_factory=lambda: TokenFlag("hidednponfab", "no"),
metadata={"description": "Hide DNP on fab", "required": False},
)
sketchdnponfab: TokenFlag = field(
default_factory=lambda: TokenFlag("sketchdnponfab", "yes"),
metadata={"description": "Sketch DNP on fab", "required": False},
)
crossoutdnponfab: TokenFlag = field(
default_factory=lambda: TokenFlag("crossoutdnponfab", "yes"),
metadata={"description": "Cross out DNP on fab", "required": False},
)
subtractmaskfromsilk: TokenFlag = field(
default_factory=lambda: TokenFlag("subtractmaskfromsilk", "no"),
metadata={"description": "Subtract mask from silk", "required": False},
)
outputformat: NamedInt = field(
default_factory=lambda: NamedInt("outputformat", 1),
metadata={"description": "Output format", "required": False},
)
mirror: TokenFlag = field(
default_factory=lambda: TokenFlag("mirror", "no"),
metadata={"description": "Mirror", "required": False},
)
drillshape: NamedInt = field(
default_factory=lambda: NamedInt("drillshape", 1),
metadata={"description": "Drill shape", "required": False},
)
scaleselection: NamedInt = field(
default_factory=lambda: NamedInt("scaleselection", 1),
metadata={"description": "Scale selection", "required": False},
)
outputdirectory: NamedString = field(
default_factory=lambda: NamedString("outputdirectory", ""),
metadata={"description": "Output directory", "required": False},
)
[docs]
@dataclass
class StackupLayer(NamedObject):
"""A single layer in the stackup configuration.
Args:
name: Layer name
type: Layer type (optional)
color: Layer color (optional)
thickness: Layer thickness (optional)
material: Material name (optional)
epsilon_r: Relative permittivity (optional)
loss_tangent: Loss tangent (optional)
"""
__token_name__: ClassVar[str] = "layer"
name: str = field(default="", metadata={"description": "Layer name"})
type: NamedString = field(
default_factory=lambda: NamedString("type", ""),
metadata={"description": "Layer type", "required": False},
)
color: NamedString = field(
default_factory=lambda: NamedString("color", ""),
metadata={"description": "Layer color", "required": False},
)
thickness: NamedFloat = field(
default_factory=lambda: NamedFloat("thickness", 0.0),
metadata={"description": "Layer thickness", "required": False},
)
material: NamedString = field(
default_factory=lambda: NamedString("material", ""),
metadata={"description": "Material name", "required": False},
)
epsilon_r: NamedFloat = field(
default_factory=lambda: NamedFloat("epsilon_r", 0.0),
metadata={"description": "Relative permittivity", "required": False},
)
loss_tangent: NamedFloat = field(
default_factory=lambda: NamedFloat("loss_tangent", 0.0),
metadata={"description": "Loss tangent", "required": False},
)
[docs]
@dataclass
class Stackup(NamedObject):
"""PCB stackup configuration.
Args:
layers: List of stackup layers
copper_finish: Copper finish specification (optional)
dielectric_constraints: Dielectric constraints flag (optional)
"""
__token_name__: ClassVar[str] = "stackup"
layers: List[StackupLayer] = field(
default_factory=list,
metadata={"description": "List of stackup layers"},
)
copper_finish: NamedString = field(
default_factory=lambda: NamedString("copper_finish", ""),
metadata={"description": "Copper finish specification", "required": False},
)
dielectric_constraints: TokenFlag = field(
default_factory=lambda: TokenFlag("dielectric_constraints", "no"),
metadata={"description": "Dielectric constraints flag", "required": False},
)
[docs]
@dataclass
class Setup(NamedObject):
"""Board setup definition token.
The 'setup' token stores current settings and options used by the board in the format::
(setup
[(STACK_UP_SETTINGS)]
(pad_to_mask_clearance CLEARANCE)
[(solder_mask_min_width MINIMUM_WIDTH)]
[(pad_to_paste_clearance CLEARANCE)]
[(pad_to_paste_clearance_ratio RATIO)]
[(aux_axis_origin X Y)]
[(grid_origin X Y)]
(PLOT_SETTINGS)
)
Args:
stackup: Stackup configuration (optional)
pad_to_mask_clearance: Pad to mask clearance (optional)
allow_soldermask_bridges_in_footprints: Allow soldermask bridges in footprints (optional)
tenting: Tenting configuration (optional)
pcbplotparams: PCB plot parameters (optional)
"""
__token_name__: ClassVar[str] = "setup"
stackup: "Stackup" = field(
default_factory=lambda: Stackup(),
metadata={"description": "Stackup configuration", "required": False},
)
pad_to_mask_clearance: NamedFloat = field(
default_factory=lambda: NamedFloat("pad_to_mask_clearance", 0.0),
metadata={"description": "Pad to mask clearance", "required": False},
)
allow_soldermask_bridges_in_footprints: TokenFlag = field(
default_factory=lambda: TokenFlag(
"allow_soldermask_bridges_in_footprints", "no"
),
metadata={
"description": "Allow soldermask bridges in footprints",
"required": False,
},
)
tenting: Tenting = field(
default_factory=lambda: Tenting(),
metadata={"description": "Tenting configuration", "required": False},
)
pcbplotparams: PcbPlotParams = field(
default_factory=lambda: PcbPlotParams(),
metadata={"description": "PCB plot parameters", "required": False},
)
[docs]
@dataclass
class General(NamedObject):
"""General board settings definition token.
The 'general' token defines general board settings in the format::
(general
(thickness THICKNESS)
[(legacy_teardrops yes|no)]
)
Args:
thickness: Board thickness
legacy_teardrops: Whether to use legacy teardrops (optional)
"""
__token_name__: ClassVar[str] = "general"
thickness: NamedFloat = field(
default_factory=lambda: NamedFloat("thickness", 1.6),
metadata={"description": "Board thickness"},
)
legacy_teardrops: TokenFlag = field(
default_factory=lambda: TokenFlag("legacy_teardrops"),
metadata={
"description": "Whether to use legacy teardrops",
"required": False,
},
)
[docs]
@dataclass
class Tracks(NamedObject):
"""Tracks container definition token.
The 'tracks' token defines a container for track segments in the format::
(tracks
(segment ...)
...
)
Args:
segments: List of track segments
"""
__token_name__: ClassVar[str] = "tracks"
segments: List[Segment] = field(
default_factory=list, metadata={"description": "List of track segments"}
)
[docs]
@dataclass
class Via(NamedObject):
"""Via definition token.
The 'via' token defines a track via in the format::
(via
[TYPE]
[(locked)]
(at X Y)
(size DIAMETER)
(drill DIAMETER)
(layers LAYER1 LAYER2)
[(remove_unused_layers)]
[(keep_end_layers)]
[(free)]
(net NET_NUMBER)
(tstamp UUID)
)
Args:
type: Via type (blind | micro) (optional)
locked: Whether the line cannot be edited (optional)
at: Coordinates of the center of the via
size: Diameter of the via annular ring
drill: Drill diameter of the via
layers: Layer set the via connects
remove_unused_layers: Remove unused layers flag (optional)
keep_end_layers: Keep end layers flag (optional)
free: Whether via is free to move outside assigned net (optional)
net: Net ordinal number from net section
tstamp: Unique identifier of the line object (optional)
uuid: Unique identifier
"""
__token_name__: ClassVar[str] = "via"
type: Optional[str] = field(
default=None,
metadata={"description": "Via type (blind | micro)", "required": False},
)
locked: TokenFlag = field(
default_factory=lambda: TokenFlag("locked"),
metadata={
"description": "Whether the line cannot be edited",
"required": False,
},
)
at: At = field(
default_factory=lambda: At(),
metadata={"description": "Coordinates of the center of the via"},
)
size: NamedFloat = field(
default_factory=lambda: NamedFloat("size", 0.0),
metadata={"description": "Diameter of the via annular ring"},
)
drill: NamedFloat = field(
default_factory=lambda: NamedFloat("drill", 0.0),
metadata={"description": "Drill diameter of the via"},
)
layers: Layers = field(
default_factory=lambda: Layers(),
metadata={"description": "Layer set the via connects"},
)
remove_unused_layers: TokenFlag = field(
default_factory=lambda: TokenFlag("remove_unused_layers"),
metadata={"description": "Remove unused layers flag", "required": False},
)
keep_end_layers: TokenFlag = field(
default_factory=lambda: TokenFlag("keep_end_layers"),
metadata={"description": "Keep end layers flag", "required": False},
)
free: TokenFlag = field(
default_factory=lambda: TokenFlag("free"),
metadata={
"description": "Whether via is free to move outside assigned net",
"required": False,
},
)
net: NamedInt = field(
default_factory=lambda: NamedInt(token="net", value=0),
metadata={"description": "Net ordinal number from net section"},
)
tstamp: NamedString = field(
default_factory=lambda: NamedString("tstamp", ""),
metadata={
"description": "Unique identifier of the line object",
"required": False,
},
) # NEW Variant
uuid: Optional[Uuid] = field(
default_factory=lambda: Uuid(), metadata={"description": "Unique identifier"}
) # Old Variant
[docs]
@dataclass
class Vias(NamedObject):
"""Vias container definition token.
The 'vias' token defines a container for vias in the format::
(vias
(via ...)
...
)
Args:
vias: List of vias
"""
__token_name__: ClassVar[str] = "vias"
vias: List[Via] = field(
default_factory=list, metadata={"description": "List of vias"}
)
[docs]
@dataclass
class BoardArc(NamedObject):
"""Board arc track segment definition.
The 'arc' token defines an arc-shaped track segment in the format::
(arc
(start X Y)
(mid X Y)
(end X Y)
(width WIDTH)
(layer LAYER)
(net NET_NUMBER)
(uuid UUID)
)
Args:
start: Start point of the arc
mid: Mid point of the arc
end: End point of the arc
width: Track width
layer: Layer name
net: Net number
uuid: Unique identifier (optional)
"""
__token_name__: ClassVar[str] = "arc"
start: Start = field(
default_factory=lambda: Start(),
metadata={"description": "Start point of the arc"},
)
mid: Mid = field(
default_factory=lambda: Mid(),
metadata={"description": "Mid point of the arc"},
)
end: End = field(
default_factory=lambda: End(),
metadata={"description": "End point of the arc"},
)
width: NamedFloat = field(
default_factory=lambda: NamedFloat("width", 0.0),
metadata={"description": "Track width"},
)
layer: NamedString = field(
default_factory=lambda: NamedString("layer", ""),
metadata={"description": "Layer name"},
)
net: NamedInt = field(
default_factory=lambda: NamedInt("net", 0),
metadata={"description": "Net number"},
)
uuid: Optional[Uuid] = field(
default_factory=lambda: Uuid(),
metadata={"description": "Unique identifier", "required": False},
)
[docs]
@dataclass
class KicadPcb(NamedObject):
"""KiCad PCB board file definition.
The 'kicad_pcb' token defines a complete PCB board file in the format::
(kicad_pcb
(version VERSION)
(generator GENERATOR)
(general ...)
(paper "SIZE")
(page ...)
(layers ...)
(setup ...)
[(property ...)]
[(net ...)]
[(footprint ...)]
[(gr_text ...)]
[(segment ...)]
[(via ...)]
[(zone ...)]
)
Args:
version: File format version
generator: Generator application
generator_version: Generator version (optional)
general: General board settings (optional)
page: Page settings (optional)
paper: Paper size specification (optional)
layers: Layer definitions (optional)
setup: Board setup (optional)
embedded_fonts: Whether fonts are embedded (yes/no) (optional)
properties: Board properties
nets: Net definitions
footprints: Footprint instances
gr_elements: List of board graphical elements (optional)
arcs: Arc track segments
groups: Group definitions
segments: Track segments
vias: Via definitions
zones: Zone definitions
"""
__token_name__: ClassVar[str] = "kicad_pcb"
# Required header fields
version: NamedInt = field(
default_factory=lambda: NamedInt("version", 20240101),
metadata={"description": "File format version"},
)
generator: NamedString = field(
default_factory=lambda: NamedString("generator", ""),
metadata={"description": "Generator application"},
)
generator_version: NamedString = field(
default_factory=lambda: NamedString("generator_version", ""),
metadata={"description": "Generator version", "required": False},
)
# Optional sections
general: Optional[General] = field(
default_factory=lambda: General(),
metadata={"description": "General board settings", "required": False},
)
page: NamedString = field(
default_factory=lambda: NamedString("page", ""),
metadata={"description": "Page settings", "required": False},
)
paper: NamedString = field(
default_factory=lambda: NamedString("paper", "A4"),
metadata={"description": "Paper size specification", "required": False},
)
layers: Optional[BoardLayers] = field(
default_factory=lambda: BoardLayers(),
metadata={"description": "Layer definitions", "required": False},
)
setup: Optional[Setup] = field(
default_factory=lambda: Setup(),
metadata={"description": "Board setup", "required": False},
)
embedded_fonts: NamedString = field(
default_factory=lambda: NamedString("embedded_fonts", ""),
metadata={
"description": "Whether fonts are embedded (yes/no)",
"required": False,
},
)
# Multiple elements (lists)
properties: List[Property] = field(
default_factory=list, metadata={"description": "Board properties"}
)
nets: List[Net] = field(
default_factory=list, metadata={"description": "Net definitions"}
)
footprints: List[Footprint] = field(
default_factory=list, metadata={"description": "Footprint instances"}
)
gr_elements: Optional[List[Union[GrText, GrLine, GrArc, GrPoly]]] = field(
default_factory=list,
metadata={
"description": "List of board graphical elements",
"required": False,
},
)
arcs: List[BoardArc] = field(
default_factory=list, metadata={"description": "Arc track segments"}
)
groups: List[Group] = field(
default_factory=list, metadata={"description": "Group definitions"}
)
segments: List[Segment] = field(
default_factory=list, metadata={"description": "Track segments"}
)
vias: List[Via] = field(
default_factory=list, metadata={"description": "Via definitions"}
)
zones: List[Zone] = field(
default_factory=list, metadata={"description": "Zone definitions"}
)
[docs]
@classmethod
def from_file(
cls,
file_path: str,
strictness: ParseStrictness = ParseStrictness.STRICT,
encoding: str = "utf-8",
) -> "KicadPcb":
"""Parse from S-expression file - convenience method for PCB operations."""
if not file_path.endswith(".kicad_pcb"):
raise ValueError("Unsupported file extension. Expected: .kicad_pcb")
with open(file_path, "r", encoding=encoding) as f:
content = f.read()
return cls.from_str(content, strictness)
[docs]
def save_to_file(self, file_path: str, encoding: str = "utf-8") -> None:
"""Save to .kicad_pcb file format.
Args:
file_path: Path to write the .kicad_pcb file
encoding: File encoding (default: utf-8)
"""
if not file_path.endswith(".kicad_pcb"):
raise ValueError("Unsupported file extension. Expected: .kicad_pcb")
content = self.to_sexpr_str()
with open(file_path, "w", encoding=encoding) as f:
f.write(content)