Skip to content

Document & Layout

Document

@dataclass(frozen=True)
class Document:
    path: str
    version: str
    decode_path: str | None = None
    decode_version: str | None = None
    lineweight_table: Mapping[int, int] | None = None

A DWG document. Created by ezdwg.read().

Properties

Property Type Description
path str Path to the DWG file
version str DWG version code (e.g. "AC1015")
decode_path str \| None Path used for decoding (defaults to path)
decode_version str \| None Version used for decoding (defaults to version)

Methods

modelspace

Document.modelspace() -> Layout

Return the modelspace layout.

Example:

doc = ezdwg.read("drawing.dwg")
msp = doc.modelspace()

graph

Document.graph(limit: int | None = None) -> DocumentGraph

Return the graph-oriented IR for the document. The graph contains object nodes, common entity data, object edges, layer table rows, block header rows, and inferred model/paper space header handles.

header_variables

Document.header_variables() -> dict[str, Any]

Decode a subset of the DWG header variables. Keys: insunits, lunits, luprec, aunits, auprec, ltscale, textsize, extmin, extmax, limmin, limmax. Values are None when the variable is absent for the file version — R14 (AC1014) has no $INSUNITS header variable, so every field is None for R14 files. Raises on unreadable header sections.

doc = ezdwg.read("drawing.dwg")
variables = doc.header_variables()
variables["insunits"]  # 4
variables["extmin"]    # (0.0, 0.0, 0.0)

linetypes

Document.linetypes() -> dict[str, dict[str, Any]]

Linetype table by name. Each entry holds handle, description, pattern_length and dashes: the dash pattern in drawing units at linetype scale 1, with the DXF sign convention (positive = dash, negative = gap, 0 = dot). The built-in ByBlock, ByLayer and Continuous entries have an empty pattern.

doc = ezdwg.read("drawing.dwg")
doc.linetypes()["CENTER"]["dashes"]  # [1.25, -0.25, 0.25, -0.25]

layers

Document.layers -> LayerTable
Document.layers() -> dict[str, dict[str, Any]]

doc.layers is a cached table of immutable Layer snapshots. Iterate over layers, look up names with doc.layers["0"], or use by_handle(handle) and to_records(). Calling the table preserves the legacy dictionary API below. Lineweight is in hundredths of a millimetre; lineweight_index is the stored DWG enum. ezdwg.read(path, lineweight_table={9: 35}) accepts a custom mapping. Transparency is an optional percentage (0 opaque, up to 90 transparent).

Layer table by name. Each entry holds handle, color_index, true_color, linetype (the name of the layer's linetype, None when it cannot be read) and the state of the layer:

Key Type Description
off bool The layer is turned off
frozen bool The layer is frozen
locked bool The layer is locked
plot bool The layer is printed. Always True for R13/R14 files, which have no such flag
lineweight int Hundredths of a millimetre; -3 is the default lineweight (always, for R13/R14 files)

The entities of a layer that is off or frozen are not shown.

layers = doc.layers()
layers["Center"]["linetype"]  # "CENTER"

ltscale = doc.header_variables()["ltscale"] or 1.0
for entity in doc.modelspace().query("LINE"):
    name = entity.dxf["linetype"]
    if name == "BYLAYER":
        layer = next(v for v in layers.values() if v["handle"] == entity.dxf["layer_handle"])
        name = layer["linetype"]
    scale = ltscale * entity.dxf["linetype_scale"]

layer states, filters, and viewport overrides

doc = ezdwg.read("drawing.dwg")
print(doc.layer_states.names())
state = doc.layer_state("Saved state")
if state is not None:
    preview = state.apply(doc, dry_run=True)
    result = state.apply(doc)  # updates the cached layer metadata in memory

for layer_filter in doc.layer_filters:
    print(layer_filter.name, layer_filter.name_pattern)
for node in doc.layer_filter_tree.walk():
    print(node.depth, node.name, node.expression)

LayerStateMasks selects properties for diff() / apply(). Use properties=ezdwg.LayerStateMasks.COLOR to select color alone. Unresolved properties are skipped. skip_missing=False raises KeyError before mutation if a referenced layer is missing. doc.diff_layer_state(name, **kwargs) and doc.apply_layer_state(name, **kwargs) offer named-state shortcuts.

Passing viewport=<entity handle> applies freeze/display properties to doc.viewport_overrides. Other flags remain global. Override colors and transparency are decoded; override lineweight is in hundredths of a millimetre. Without a viewport argument, global layer metadata is restored and the summary reports any skipped viewport context.

State/override application changes these metadata tables only. Entity queries, plotting, DWG export, and DXF export continue to read their existing decode paths; they do not consume the modified tables. There is no DWG write-back.

Layer-state decoding is covered by populated AC1027/AC1032 fixtures. Current public fixtures have empty filter/override tables; populated Python table behavior is tested with synthetic rows. Native populated filter/override decoding remains best effort. matches_name() evaluates only a name pattern, not arbitrary AcLy expressions or other filter properties.

Native layer results are cached by canonical path, size, and modification time. Call ezdwg.clear_decode_caches() after batch work or before rereading a file whose size/timestamp was preserved. Existing Document snapshots remain alive.

dimstyles

Document.dimstyles() -> dict[str, dict[str, Any]]

Dimension style table by name. Each entry holds handle, dimscale (the overall scale; 0 for a style that is scaled by the viewport or annotatively), dimtxt (text height) and dimasz (arrow size). The sizes are in drawing units before dimscale.

style = doc.dimstyles()["ISO-25"]
text_height = style["dimtxt"] * (style["dimscale"] or 1.0)

layouts

Document.layouts() -> dict[str, dict[str, Any]]

Layout table by name, in tab order: the model tab and the paper-space sheets.

Key Type Description
handle int Handle of the layout object
tab_order int Position among the tabs; 0 is the model tab
model bool True for the model tab
active bool True for the paper-space sheet that was current when the file was saved
block_record_handle int Block record that owns the entities of the layout
paper_width, paper_height float Paper size in millimetres, before plot_rotation
margins (float, float, float, float) Unprintable margins: left, bottom, right, top; millimetres
paper_size str Name of the paper size
paper_units int 0 inches, 1 millimetres, 2 pixels
plot_rotation int 0-3 quarter turns counter-clockwise
limmin, limmax (float, float) Limits of the layout
extmin, extmax (float, float, float) Extents of the layout
viewport_handles list[int] Viewports of the layout, the sheet's own viewport first (R2004+; empty before)

The entities of the active sheet are stored without an owner handle: entity_placement() gives (1, None) for them. The entities of every other sheet name the block record of their layout as owner.

layouts = doc.layouts()
sheets = {entry["block_record_handle"]: name for name, entry in layouts.items() if not entry["model"]}
active = next((name for name, entry in layouts.items() if entry["active"]), None)

for entity in doc.paperspace().query():
    mode, owner = doc.entity_placement(entity.handle)
    sheet = active if mode == 1 else sheets.get(owner)

Files written before R2000 may hold no layout objects; the table is empty then.

units

Document.units -> str | None

Drawing units name resolved from $INSUNITS (e.g. "millimeters", "inches", "unitless"). Returns None when the code is unavailable (R14, or an unreadable header). Unknown codes are reported as "unknown_<code>". The raw integer code is available as Document.insunits.

doc = ezdwg.read("drawing.dwg")
doc.units     # "millimeters"
doc.insunits  # 4

plot

Document.plot(*args, **kwargs) -> Axes

Plot all entities in the modelspace. Accepts the same parameters as ezdwg.plot().

export_dxf

Document.export_dxf(output_path: str, **kwargs) -> ConvertResult

Export the modelspace to a DXF file. Accepts the same keyword arguments as ezdwg.to_dxf().

export_dwg

Document.export_dwg(output_path: str, **kwargs) -> WriteResult

Export the modelspace to a DWG file using the native writer. Accepts the same keyword arguments as ezdwg.to_dwg().


Layout

@dataclass(frozen=True)
class Layout:
    doc: Document
    name: str

A drawing layout (e.g. modelspace).

Methods

query

Layout.query(types: str | Iterable[str] | None = None) -> Iterator[Entity]

Iterate over entities, optionally filtered by type.

Parameters:

  • types — Space-separated type names (e.g. "LINE ARC"), an iterable of type names, or None for all types.

Returns: Iterator of Entity objects.

Examples:

# All entities
for entity in msp.query():
    print(entity.dxftype)

# Filter by type string
for line in msp.query("LINE"):
    print(line.dxf["start"])

# Multiple types
for entity in msp.query("LINE ARC CIRCLE"):
    print(entity.dxftype, entity.handle)

# From an iterable
for entity in msp.query(["LINE", "ARC"]):
    print(entity.dxftype)

iter_entities

Layout.iter_entities(types: str | Iterable[str] | None = None) -> Iterator[Entity]

Alias for query().

plot

Layout.plot(*args, **kwargs) -> Axes

Plot entities in this layout. Accepts the same parameters as ezdwg.plot().

export_dxf

Layout.export_dxf(output_path: str, **kwargs) -> ConvertResult

Export this layout to a DXF file. Accepts the same keyword arguments as ezdwg.to_dxf().

export_dwg

Layout.export_dwg(output_path: str, **kwargs) -> WriteResult

Export this layout to a DWG file using the native writer. Accepts the same keyword arguments as ezdwg.to_dwg().