ours: наш оверлей к апстриму 1.5.1 (дельта для переноса в 1.6.0)
10 изменённых файлов + 2 новых (engineering/gost_titleblock.py, _fonts/isocpeur.ttf). Ветка-донор для трёхстороннего переноса в ours-1.6.
This commit is contained in:
+279
-25
@@ -193,6 +193,34 @@ def _msp():
|
||||
return doc.ModelSpace
|
||||
|
||||
|
||||
def _activate_layout(name: str | None) -> None:
|
||||
"""Make the named layout the active tab, so the next COM call draws on it.
|
||||
|
||||
The ezdxf backend takes ``layout`` as a per-call target; COM has one active
|
||||
layout per document, so the equivalent is the same switch
|
||||
``layout_set_current`` performs — and it stays switched, because the sheet is
|
||||
where the drafter carries on. Unknown names are refused instead of silently
|
||||
drawing into model space.
|
||||
"""
|
||||
wanted = str(name or "").strip()
|
||||
if not wanted:
|
||||
return
|
||||
doc = _acad_doc()
|
||||
try:
|
||||
current = str(doc.ActiveLayout.Name)
|
||||
except Exception as exc: # a probe must never block a draw
|
||||
log.debug("ActiveLayout.Name unavailable (%s)", exc)
|
||||
current = ""
|
||||
if current and current.lower() == wanted.lower():
|
||||
return
|
||||
try:
|
||||
doc.ActiveLayout = doc.Layouts.Item(wanted)
|
||||
except Exception as exc:
|
||||
raise RuntimeError(
|
||||
f"layout {wanted!r} does not exist: create it with layout_create first"
|
||||
) from exc
|
||||
|
||||
|
||||
_BUILTIN_LINETYPES = {"continuous", "bylayer", "byblock"}
|
||||
|
||||
|
||||
@@ -815,7 +843,21 @@ class ComBackend(AutoCADBackend):
|
||||
async def drawing_export_dxf(self, path: str) -> dict:
|
||||
return await self.drawing_save_as(path, "dxf")
|
||||
|
||||
async def drawing_export_pdf(self, path: str, layout: str | None = None) -> dict:
|
||||
async def drawing_export_pdf(
|
||||
self,
|
||||
path: str,
|
||||
layout: str | None = None,
|
||||
text_layer: bool | None = None,
|
||||
page_size: str | None = None,
|
||||
) -> dict:
|
||||
# ``text_layer`` is accepted for signature parity with the ezdxf backend:
|
||||
# AutoCAD plots real text natively, so the flag has nothing to switch.
|
||||
# ``page_size`` likewise: PlotToFile plots the layout's own paper at its
|
||||
# own scale (that is what a .pc3 device does), so there is nothing to
|
||||
# choose between "layout" and "extents" here.
|
||||
del text_layer
|
||||
del page_size
|
||||
|
||||
def _sync():
|
||||
doc = _acad_doc()
|
||||
previous = None
|
||||
@@ -1934,8 +1976,12 @@ class ComBackend(AutoCADBackend):
|
||||
layer=None,
|
||||
color=None,
|
||||
linetype=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
# Layout ровно как у ezdxf: COM рисует в активный лист, поэтому
|
||||
# вызов сначала переключает вкладку (см. _activate_layout).
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
line = mspace.AddLine(_apoint(x1, y1, z1), _apoint(x2, y2, z2))
|
||||
_apply_entity_attrs(line, layer, color, linetype)
|
||||
@@ -1951,8 +1997,10 @@ class ComBackend(AutoCADBackend):
|
||||
radius,
|
||||
layer=None,
|
||||
color=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
circle = mspace.AddCircle(_apoint(cx, cy), float(radius))
|
||||
_apply_entity_attrs(circle, layer, color, None)
|
||||
@@ -1970,8 +2018,10 @@ class ComBackend(AutoCADBackend):
|
||||
end_angle,
|
||||
layer=None,
|
||||
color=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
arc = mspace.AddArc(
|
||||
_apoint(cx, cy),
|
||||
@@ -1991,8 +2041,10 @@ class ComBackend(AutoCADBackend):
|
||||
closed=False,
|
||||
layer=None,
|
||||
color=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
flat = []
|
||||
for pt in points:
|
||||
@@ -2014,11 +2066,25 @@ class ComBackend(AutoCADBackend):
|
||||
rotation=0.0,
|
||||
layer=None,
|
||||
color=None,
|
||||
style=None,
|
||||
layout=None,
|
||||
inline_font=True,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
# Layout ровно как у ezdxf: COM рисует в активный лист, поэтому
|
||||
# вызов сначала переключает вкладку (см. _activate_layout).
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
txt = mspace.AddText(text, _apoint(x, y), float(height))
|
||||
txt.Rotation = deg2rad(rotation)
|
||||
if style:
|
||||
# AutoCAD refuses an unknown style name outright; a caller who
|
||||
# asked for a face the drawing does not carry gets the current
|
||||
# style instead of a failed call (matching ezdxf's fallback).
|
||||
try:
|
||||
txt.StyleName = str(style)
|
||||
except Exception:
|
||||
pass
|
||||
_apply_entity_attrs(txt, layer, color, None)
|
||||
_regen()
|
||||
return _entity_info(txt)
|
||||
@@ -2035,13 +2101,26 @@ class ComBackend(AutoCADBackend):
|
||||
rotation=0.0,
|
||||
layer=None,
|
||||
color=None,
|
||||
style=None,
|
||||
layout=None,
|
||||
inline_font=True,
|
||||
) -> EntityInfo:
|
||||
from engineering.annotation import wrap_inline_font
|
||||
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
mt = mspace.AddMText(_apoint(x, y), float(width), text)
|
||||
mt = mspace.AddMText(
|
||||
_apoint(x, y), float(width), wrap_inline_font(text, inline_font)
|
||||
)
|
||||
mt.Height = float(height)
|
||||
if rotation:
|
||||
mt.Rotation = deg2rad(rotation) # NEW-mtext-1: honor caller rotation
|
||||
if style:
|
||||
try:
|
||||
mt.StyleName = str(style)
|
||||
except Exception:
|
||||
pass
|
||||
_apply_entity_attrs(mt, layer, color, None)
|
||||
_regen()
|
||||
return _entity_info(mt)
|
||||
@@ -2059,30 +2138,43 @@ class ComBackend(AutoCADBackend):
|
||||
text_height=2.5,
|
||||
title=None,
|
||||
layer="TEXT",
|
||||
style=None,
|
||||
layout=None,
|
||||
inline_font=True,
|
||||
) -> EntityInfo:
|
||||
from engineering.annotation import prepare_table_layout
|
||||
from engineering.annotation import prepare_table_layout, wrap_inline_font
|
||||
|
||||
layout = prepare_table_layout(rows, headers, column_widths, row_height, text_height, title)
|
||||
table_layout = prepare_table_layout(
|
||||
rows, headers, column_widths, row_height, text_height, title
|
||||
)
|
||||
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
table = mspace.AddTable(
|
||||
_apoint(x, y),
|
||||
layout.row_count,
|
||||
layout.column_count,
|
||||
layout.row_height,
|
||||
layout.column_widths[0],
|
||||
table_layout.row_count,
|
||||
table_layout.column_count,
|
||||
table_layout.row_height,
|
||||
table_layout.column_widths[0],
|
||||
)
|
||||
for column, width in enumerate(layout.column_widths):
|
||||
for column, width in enumerate(table_layout.column_widths):
|
||||
table.SetColumnWidth(column, width)
|
||||
for row_index, row in enumerate(layout.cells):
|
||||
table.SetRowHeight(row_index, layout.row_height)
|
||||
for row_index, row in enumerate(table_layout.cells):
|
||||
table.SetRowHeight(row_index, table_layout.row_height)
|
||||
for column_index, value in enumerate(row):
|
||||
table.SetText(row_index, column_index, value)
|
||||
table.SetText(row_index, column_index, wrap_inline_font(value, inline_font))
|
||||
try:
|
||||
table.TextHeight = layout.text_height
|
||||
table.TextHeight = table_layout.text_height
|
||||
except Exception as exc:
|
||||
log.debug("setting table TextHeight failed: %s", exc)
|
||||
cell_style = None
|
||||
if style:
|
||||
try:
|
||||
table.TextStyle = str(style)
|
||||
cell_style = str(style)
|
||||
except Exception as exc:
|
||||
log.debug("setting table TextStyle failed: %s", exc)
|
||||
_apply_entity_attrs(table, layer, None, None)
|
||||
_regen()
|
||||
info = _entity_info(table)
|
||||
@@ -2093,11 +2185,13 @@ class ComBackend(AutoCADBackend):
|
||||
"representation": "native",
|
||||
"logical_group_id": f"table:{uuid.uuid4().hex}",
|
||||
"child_handles": [info.handle],
|
||||
"rows": layout.row_count,
|
||||
"columns": layout.column_count,
|
||||
"rows": table_layout.row_count,
|
||||
"columns": table_layout.column_count,
|
||||
"text_style": cell_style,
|
||||
"layout": str(layout or ""),
|
||||
"bounds": {
|
||||
"min": [float(x), float(y) - layout.height],
|
||||
"max": [float(x) + layout.width, float(y)],
|
||||
"min": [float(x), float(y) - table_layout.height],
|
||||
"max": [float(x) + table_layout.width, float(y)],
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -2113,8 +2207,10 @@ class ComBackend(AutoCADBackend):
|
||||
landing_gap=1.0,
|
||||
arrow_size=2.5,
|
||||
layer="DIM",
|
||||
layout=None,
|
||||
inline_font=True,
|
||||
) -> EntityInfo:
|
||||
from engineering.annotation import validate_mleader
|
||||
from engineering.annotation import validate_mleader, wrap_inline_font
|
||||
|
||||
normalized = validate_mleader(points, text)
|
||||
if text_height <= 0 or landing_gap < 0 or arrow_size <= 0:
|
||||
@@ -2123,11 +2219,12 @@ class ComBackend(AutoCADBackend):
|
||||
)
|
||||
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
flat = []
|
||||
for px, py in normalized:
|
||||
flat.extend([px, py, 0.0])
|
||||
leader = _msp().AddMLeader(_av(flat), 0)
|
||||
leader.TextString = str(text)
|
||||
leader.TextString = wrap_inline_font(text, inline_font)
|
||||
leader.TextHeight = float(text_height)
|
||||
leader.LandingGap = float(landing_gap)
|
||||
leader.ArrowheadSize = float(arrow_size)
|
||||
@@ -2161,8 +2258,10 @@ class ComBackend(AutoCADBackend):
|
||||
angle=0.0,
|
||||
layer=None,
|
||||
color=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
# acPatternTypePreDefined = 0
|
||||
hatch = mspace.AddHatch(0, pattern, False)
|
||||
@@ -2189,8 +2288,10 @@ class ComBackend(AutoCADBackend):
|
||||
fit_points,
|
||||
layer=None,
|
||||
color=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
flat = []
|
||||
for pt in fit_points:
|
||||
@@ -2215,8 +2316,10 @@ class ComBackend(AutoCADBackend):
|
||||
ratio=0.5,
|
||||
layer=None,
|
||||
color=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
ellipse = mspace.AddEllipse(
|
||||
_apoint(cx, cy),
|
||||
@@ -2235,8 +2338,10 @@ class ComBackend(AutoCADBackend):
|
||||
y,
|
||||
layer=None,
|
||||
color=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
pt = mspace.AddPoint(_apoint(x, y))
|
||||
_apply_entity_attrs(pt, layer, color, None)
|
||||
@@ -2254,8 +2359,10 @@ class ComBackend(AutoCADBackend):
|
||||
scale_y=1.0,
|
||||
rotation=0.0,
|
||||
layer=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
ref = mspace.InsertBlock(
|
||||
_apoint(x, y),
|
||||
@@ -2288,8 +2395,10 @@ class ComBackend(AutoCADBackend):
|
||||
tol_lower=None,
|
||||
tol_mode="none",
|
||||
text_override=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
# The ActiveX API has no AddDimLinear — rotated linear dims are
|
||||
# created with AddDimRotated (GH issue #3).
|
||||
@@ -2316,8 +2425,10 @@ class ComBackend(AutoCADBackend):
|
||||
dim_x,
|
||||
dim_y,
|
||||
layer=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
dim = mspace.AddDimAligned(_apoint(x1, y1), _apoint(x2, y2), _apoint(dim_x, dim_y))
|
||||
if layer:
|
||||
@@ -2338,8 +2449,10 @@ class ComBackend(AutoCADBackend):
|
||||
tx,
|
||||
ty,
|
||||
layer=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
dim = mspace.AddDimAngular(
|
||||
_apoint(vx, vy),
|
||||
@@ -2366,8 +2479,10 @@ class ComBackend(AutoCADBackend):
|
||||
tol_lower=None,
|
||||
tol_mode="none",
|
||||
text_override=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
dim = mspace.AddDimRadial(
|
||||
_apoint(cx, cy), _apoint(chord_x, chord_y), float(leader_length)
|
||||
@@ -2392,8 +2507,10 @@ class ComBackend(AutoCADBackend):
|
||||
tol_lower=None,
|
||||
tol_mode="none",
|
||||
text_override=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
dim = mspace.AddDimDiametric(_apoint(x1, y1), _apoint(x2, y2), float(leader_length))
|
||||
if layer:
|
||||
@@ -2404,6 +2521,73 @@ class ComBackend(AutoCADBackend):
|
||||
|
||||
return await self._run(_sync)
|
||||
|
||||
async def dimstyle_ensure(
|
||||
self,
|
||||
name="СПДС",
|
||||
text_style=None,
|
||||
base=None,
|
||||
set_current=True,
|
||||
text_height=2.5,
|
||||
arrow_size=2.5,
|
||||
) -> dict:
|
||||
"""Создать размерный стиль (по умолчанию СПДС) и/или сделать его текущим.
|
||||
|
||||
COM-эквивалент метода ezdxf: текстовый стиль размера переводим на
|
||||
ГОСТ-начертание (``text_style``), высоту текста и стрелки задаём явно
|
||||
(ГОСТ 2.304: 2.5 мм при 1:1), при ``set_current`` стиль становится
|
||||
активным (``ActiveDimStyle``) — следующий размер выйдет им.
|
||||
"""
|
||||
|
||||
def _sync():
|
||||
doc = _acad_doc()
|
||||
style_name = str(name or "").strip()
|
||||
if not style_name:
|
||||
raise RuntimeError("dimstyle_ensure: name must not be empty")
|
||||
names = [str(doc.DimStyles.Item(i).Name) for i in range(doc.DimStyles.Count)]
|
||||
created = False
|
||||
if style_name in names:
|
||||
style = doc.DimStyles.Item(style_name)
|
||||
else:
|
||||
style = doc.DimStyles.Add(style_name)
|
||||
created = True
|
||||
source = str(base or "").strip() or "Standard"
|
||||
if source in names:
|
||||
try:
|
||||
style.CopyFrom(doc.DimStyles.Item(source))
|
||||
except Exception as exc:
|
||||
log.debug("dimstyle_ensure: CopyFrom %s failed (%s)", source, exc)
|
||||
for attr, value in (("TextStyle", text_style), ("TextHeight", text_height),
|
||||
("ArrowheadSize", arrow_size)):
|
||||
if value in (None, "", 0):
|
||||
continue
|
||||
try:
|
||||
setattr(style, attr, value)
|
||||
except Exception as exc:
|
||||
# AutoCAD отказывает на незнакомое имя стиля — не валим вызов.
|
||||
log.debug("dimstyle_ensure: %s=%s rejected (%s)", attr, value, exc)
|
||||
if set_current:
|
||||
try:
|
||||
doc.ActiveDimStyle = style
|
||||
except Exception as exc:
|
||||
log.debug("dimstyle_ensure: ActiveDimStyle failed (%s)", exc)
|
||||
_regen()
|
||||
current = ""
|
||||
try:
|
||||
current = str(doc.ActiveDimStyle.Name)
|
||||
except Exception:
|
||||
current = ""
|
||||
return {
|
||||
"ok": True,
|
||||
"name": style_name,
|
||||
"created": created,
|
||||
"text_style": str(text_style or ""),
|
||||
"set_current": bool(set_current),
|
||||
"current": current,
|
||||
"dimstyles": names + ([] if style_name in names else [style_name]),
|
||||
}
|
||||
|
||||
return await self._run(_sync)
|
||||
|
||||
# ── entity modification ───────────────────────────────────────────────────
|
||||
|
||||
async def entity_move(self, handle, dx, dy, dz=0.0) -> dict:
|
||||
@@ -3023,8 +3207,11 @@ class ComBackend(AutoCADBackend):
|
||||
rotation=0.0,
|
||||
attributes=None,
|
||||
layer=None,
|
||||
style=None,
|
||||
layout=None,
|
||||
) -> EntityInfo:
|
||||
def _sync():
|
||||
_activate_layout(layout)
|
||||
mspace = _msp()
|
||||
ref = mspace.InsertBlock(
|
||||
_apoint(x, y),
|
||||
@@ -3045,6 +3232,15 @@ class ComBackend(AutoCADBackend):
|
||||
attr.TextString = str(attributes[tag])
|
||||
except Exception as exc:
|
||||
log.debug("Block insert: GetAttributes or attribute setting failed: %s", exc)
|
||||
if style:
|
||||
# The ATTRIB inherits its ATTDEF's text style; a definition made
|
||||
# before the ГОСТ style existed carries ``Standard``, which plots
|
||||
# the block marks in the wrong face.
|
||||
try:
|
||||
for attr in ref.GetAttributes():
|
||||
attr.StyleName = str(style)
|
||||
except Exception as exc:
|
||||
log.debug("Block insert: setting attribute style failed: %s", exc)
|
||||
return _entity_info(ref)
|
||||
|
||||
return await self._run(_sync)
|
||||
@@ -3070,18 +3266,32 @@ class ComBackend(AutoCADBackend):
|
||||
|
||||
return await self._run(_sync)
|
||||
|
||||
async def block_set_attributes(self, handle, attributes) -> dict:
|
||||
async def block_set_attributes(self, handle, attributes, style=None) -> dict:
|
||||
def _sync():
|
||||
doc = _acad_doc()
|
||||
ref = doc.HandleToObject(handle)
|
||||
attrs = ref.GetAttributes()
|
||||
updated = []
|
||||
restyled = 0
|
||||
for attr in attrs:
|
||||
tag = attr.TagString
|
||||
if tag in attributes:
|
||||
attr.TextString = str(attributes[tag])
|
||||
updated.append(tag)
|
||||
return {"ok": True, "updated_tags": updated}
|
||||
if style:
|
||||
# The reference's ATTDEF inherited ``Standard`` when there was
|
||||
# no ГОСТ style yet; a value written into it would still plot
|
||||
# in the wrong face, so the update carries the style with it.
|
||||
try:
|
||||
attr.StyleName = str(style)
|
||||
restyled += 1
|
||||
except Exception:
|
||||
pass
|
||||
result = {"ok": True, "updated_tags": updated}
|
||||
if style:
|
||||
result["style"] = str(style)
|
||||
result["restyled_tags"] = restyled
|
||||
return result
|
||||
|
||||
return await self._run(_sync)
|
||||
|
||||
@@ -3091,26 +3301,70 @@ class ComBackend(AutoCADBackend):
|
||||
handles,
|
||||
base_x=0.0,
|
||||
base_y=0.0,
|
||||
layout=None,
|
||||
) -> dict:
|
||||
"""Build a block definition from entities already in the drawing.
|
||||
|
||||
This used to refuse and point at ``system_run_command`` with ``_BLOCK``,
|
||||
pushing callers through the free-text escape hatch for something ActiveX
|
||||
does directly: ``Blocks.Add`` creates the definition and
|
||||
``Document.CopyObjects`` puts entities into it. The originals stay in
|
||||
model space, matching the headless backend rather than AutoCAD's BLOCK
|
||||
``Document.CopyObjects`` puts entities into it. The originals stay where
|
||||
they were, matching the headless backend rather than AutoCAD's BLOCK
|
||||
command (which consumes them).
|
||||
|
||||
``layout`` matches the headless backend: a definition is document-global
|
||||
(it has no owner sheet), so the parameter constrains the *source* — only
|
||||
handles whose ``OwnerID`` is that layout's own block are taken, and a
|
||||
foreign handle is named in a refusal instead of copied silently.
|
||||
"""
|
||||
|
||||
def _sync():
|
||||
doc = _acad_doc()
|
||||
objects, skipped = [], []
|
||||
owner_id = None
|
||||
space_label = ""
|
||||
if layout is not None:
|
||||
wanted = self._layout_name(layout)
|
||||
if wanted.lower() == "model":
|
||||
space_label = "Model"
|
||||
owner_id = int(doc.ModelSpace.ObjectID)
|
||||
else:
|
||||
resolved = self._find_layout(doc, wanted)
|
||||
if resolved is None:
|
||||
raise RuntimeError(
|
||||
f"layout {wanted!r} does not exist: create it with "
|
||||
f"layout_create first"
|
||||
)
|
||||
space_label = resolved
|
||||
owner_id = int(doc.Layouts.Item(resolved).Block.ObjectID)
|
||||
|
||||
objects, skipped, foreign = [], [], []
|
||||
for handle in handles:
|
||||
try:
|
||||
objects.append(doc.HandleToObject(str(handle)))
|
||||
obj = doc.HandleToObject(str(handle))
|
||||
except Exception as exc:
|
||||
log.debug("resolving %s for block %s: %s", handle, name, exc)
|
||||
skipped.append(str(handle))
|
||||
continue
|
||||
if owner_id is not None:
|
||||
# An unreadable OwnerID is refused with the foreign handles
|
||||
# rather than waved through: the point of layout= is to
|
||||
# guarantee the definition came off that sheet.
|
||||
try:
|
||||
same_space = int(obj.OwnerID) == owner_id
|
||||
except Exception as exc:
|
||||
log.debug("OwnerID of %s unreadable (%s)", handle, exc)
|
||||
same_space = False
|
||||
if not same_space:
|
||||
foreign.append(str(handle))
|
||||
continue
|
||||
objects.append(obj)
|
||||
if foreign:
|
||||
raise RuntimeError(
|
||||
f"block_create_from_entities: handle(s) {', '.join(foreign)} are not in "
|
||||
f"space {space_label!r}; a definition is built from one sheet's entities "
|
||||
f"at a time. Drop layout= to collect drawing-wide, or pass the handles "
|
||||
f"of that sheet. No definition was created."
|
||||
)
|
||||
# Resolve before creating, so a call where every handle was a typo
|
||||
# does not leave an empty definition behind.
|
||||
if not objects:
|
||||
|
||||
Reference in New Issue
Block a user