v0.4.0 — the compat-exit release
The compat-exit release. Every surface whose documented removal target was 0.4.0 is gone,
and every deprecation that remains now says when it goes — in the message the caller sees, not
only in a release note. ADR 0005 §4's rule is that an alias carries a tracking issue and a
removal date, because "a facade with no exit date is a failure mode"; this release is that rule
being kept rather than restated. docs/deprecations.md is the new index, and
tests/test_deprecation_dates.py fails any deprecation that names no removal.
Also lands ADR 0016's declared-dimensioning work (#867): a dimension(feature, role) is
referential — it names a measurement and carries no number — and an authored set means omission
is suppression, enforced at the compiled-plan boundary rather than by a flag renderers check.
Read this before upgrading: two removals break without a release that warned you, because
their deprecation never appeared in a shipped version. See Removed (breaking) below and
docs/deprecations.md.
Removed (breaking)
Compat surfaces whose documented removal target was 0.4.0 (#720, ADR 0005 §4 — every alias
carries a tracking issue and a removal date, or the facade is permanent by accident):
-
The seven
Drawingcompat aliases —_named/_anno_view/_pinned/
_build_issues, and_pattern_callouts/_patterned_holes/_dropped_callout_diams.
These were private, and the public reads have existed since #699: usedwg.registry
(in reg,names(),issues,pinned_names()) anddwg.coverage, or theDrawingverbs
annotations()/iter_annotations()/get_annotation()/view_of().
Note the asymmetry. A read —dwg._named— now raisesAttributeError. A write —
dwg._pinned = {...}— does not: these were properties with setters, andDrawinghas
no__slots__, so assignment now quietly creates an unrelated instance attribute that no
longer reaches the registry or coverage owner. Writes therefore fail silently rather than
loudly. Grep for\._(named|anno_view|pinned|build_issues|pattern_callouts|patterned_holes|dropped_callout_diams)\b
before upgrading; mutate throughregistry.add()/pin()/record_issue()/
restore_issues()and theCoverageStatemethods instead. -
The
draftwright.sheet_dslmodule — an import alias fordraftwright.sheetsince the
#640 rename. ImportSheetfromdraftwrightordraftwright.sheet. -
generate_script, including itsdraftwright.__all__entry. It has raised since #940
retired the imperative emitter; it is now simply absent, so the failure is anImportError
at the top of a script rather than aRuntimeErrorpart-way through one. Use
--script/emit_sheet_script. -
The bespoke
--style imperativeerror message.--styleitself is unchanged and still
accepts its sole valuesheet;imperativeis now an unrecognised value like any typo,
rather than one carrying its own explanation of the #940 retirement. -
Bare dimension-role spellings —
sheet.dimension(f, "width"). Use the parameter id,
"width.length";dimension_ids()on a handle lists the valid ones. The bare role is the
family spelling: it selects every parameter carrying it, which is how
dimension(step, "step")quietly declared two measurements. In an authored set, where
omission means suppression, silently declaring an extra one is the mirror image of the rule
— so it now raises rather than resolving. (A discriminated bare role, used withaxis=,
is unaffected: that is how variants likegrid_pitch.length.roware addressed, and it never
warned.) -
The
Sheet.dimension(kind=…, value=…)call shape — useSheet.measured_dimension(...).
dimensionis now solely the ADR 0016 referential verb: it names a feature and a parameter
id and reads the value off the geometry.
Those last two break without a release that warns you. They were deprecated after v0.3.9
and removed in 0.4.0, so the DeprecationWarning never appeared in a released version —
upgrading from v0.3.9 or earlier goes straight from working to a raise. That is deliberate
(ADR 0016); this entry and docs/deprecations.md are the only notice you get, so both
failures name their replacement rather than raising about argument counts.
Deprecated
-
The legacy
Drawing.exportshapes now emitDeprecationWarning(#987) — they were
announced as deprecated in v0.3.1 and then said nothing at runtime for four minor releases,
which would have made their 0.5.0 removal a silent break. Three cases warn:export()withformats=omitted orNone— the legacy default, which writes
SVG + DXF and returns an(svg, dxf)tuple rather than the{format: path}dict.- the
svg=/dxf=booleans. The suggested replacement names the formats that call
selected, so following it cannot change what gets written. - passing a boolean alongside
formats=, where it is silently ignored —formatswins,
and now says so.
If you promote
DeprecationWarningto an error, previously-passing exports will now
raise. Migration:export(out, formats=("svg", "dxf"))and read the dict.make_drawing
is unaffected — it returns the same tuple and does not warn.
Added
sheet.add_dimension(feature, role)— ask the planner to carry one more
measurement (ADR 0016 / #872). Referential: it names a feature and a role and
carries no number, so the value still comes from the geometry and a size lives in
exactly one place. It changes selection, not derivation — a request can never
introduce a number the part does not have. Requesting something the planner already
emits is a deliberate no-op, so a script can ask without first knowing the rule set's
mind.sheet.auto_dimensions()states the source explicitly (optional in this
release; #874 makes it mandatory).- Suppressing a dimension marks it; it no longer leaks into the callout (ADR 0016 /
#875).PlannedDimension.suppressedwas honoured at thirteen render sites but not by
the compound hole-callout path, so a suppressed counterbore still printed. The group
keeps its engineering data either way — what changes is whether a value reaches the
page. Suppressing the bore ⌀ while a counterbore, spotface or countersink segment
remains now raises and names the orphan:⌀20 THRU ⌴ ⌀32 ↓ 1.5has no reading with
its leading term removed, and silently dropping the segments would discard authored
intent while silently restoring the head would make the drawing say something the
script does not. - Addressable dimension identity (#869/#870/#871): every planned measurement now has
a stableDimensionId(feature, parameter), and correlated measurements that must be
named as one — a grid pattern's row and column pitch, a step ladder — group into an
AddressableDimension. This is what adimension(...)line will name, and what
suppression and provenance key on.
Changed
Sheet.dimension(kind=…, value=…)is nowSheet.measured_dimension(...)
(ADR 0016 / #873), andmodel.declare.authored_dimensionis
model.declare.measured_dimensionto match. This reserves the namedimensionfor
the referential verb ADR 0016 defines — name a feature and a role, carry no number, let
the engine read the value off the geometry — whichDrawing.dimensionalready is and
Sheet.dimensionwill become. The verb that carries an explicit number needed a name
saying so first. The old spelling was a transitional overload during development and is
removed in this same release (#720) rather than shipping —Sheet.dimensionis solely
the referential verb, and the old keyword call raises withmeasured_dimensionnamed. See
Removed (breaking) above. Generated AP242 scripts emitmeasured_dimensionand so arrive
un-deprecated.Sheethandles address features by identity, not position (#908/#910/#912). A
handle, tolerance, GD&T origin, section request or dimension intent now follows its
feature through afeaturesreorder instead of naming whatever took the slot.
Reordering withreverse()/sort()preserves every reference; deleting or replacing
a referenced feature raises rather than silently retargeting a neighbour.of()now
accepts a handle, and negative indices resolve uniformly acrossof(),
add_dimension()and the GD&T verbs.
Fixed
-
sheet.envelope()measured the file, not the part (#977). An AP242 STEP import is a
compound of the solid plus its PMI presentation geometry — annotation planes, leader
curves — and the declared verb measured all of it. On the NIST CTC-01 fixture it declared
1170 × 650 where the part is 800 × 450: an envelope 370 mm too wide, silently, in anything
declared by hand.step_level()had the same exposure, offsetting every step position by
the annotation overhang. Both now measure the solid body, sharing the helper the engine
already used for exactly this (_analyseandSheet.model). -
A declared envelope's frame origin sat a half-height below a detected one (#977). It
usedbbox_min.Zwhere the detector uses the bbox centre. Dimension output is unchanged —
envelope sizes derive frombbox_min/bbox_max, and the overall height is compiled from the
model bbox — butframe.originis the generic feature site, so a GD&T control frame,
surface finish or note targeting a hand-declaredsheet.envelope()was anchored at the
bottom face rather than the centre, and its leader now moves to the centre. That is a
visible change on drawings carrying such an annotation; drawings without one are unaffected.
Scripts generated by--scriptwere never affected either way: they bake the detected frame
explicitly rather than calling the verb. -
Front-view dimensions join the placement solve instead of committing to the strip
(#894): they previously took strip space before the global solve ran, so a
higher-ranked dimension could find its space already gone. Priority only ranks
candidates that are in the solve. -
A hole callout reads the feature's own
throughfact (#868) rather than inferring
it from whether a depth parameter happens to be present — so a suppressed depth can no
longer make a blind hole printTHRU. -
The balloon ring clears the view it annotates after a hole-table escalation
(#901/#903).