Skip to content

v0.4.0 — the compat-exit release

Choose a tag to compare

@pzfreo pzfreo released this 02 Aug 09:57
· 972 commits to main since this release
19acc7d

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 Drawing compat 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: use dwg.registry
    (in reg, names(), issues, pinned_names()) and dwg.coverage, or the Drawing verbs
    annotations() / iter_annotations() / get_annotation() / view_of().
    Note the asymmetry. A read — dwg._named — now raises AttributeError. A write —
    dwg._pinned = {...} — does not: these were properties with setters, and Drawing has
    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 through registry.add() / pin() / record_issue() /
    restore_issues() and the CoverageState methods instead.

  • The draftwright.sheet_dsl module — an import alias for draftwright.sheet since the
    #640 rename. Import Sheet from draftwright or draftwright.sheet.

  • generate_script, including its draftwright.__all__ entry. It has raised since #940
    retired the imperative emitter; it is now simply absent, so the failure is an ImportError
    at the top of a script rather than a RuntimeError part-way through one. Use
    --script / emit_sheet_script.

  • The bespoke --style imperative error message. --style itself is unchanged and still
    accepts its sole value sheet; imperative is 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 with axis=,
    is unaffected: that is how variants like grid_pitch.length.row are addressed, and it never
    warned.)

  • The Sheet.dimension(kind=…, value=…) call shape — use Sheet.measured_dimension(...).
    dimension is 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.export shapes now emit DeprecationWarning (#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() with formats= omitted or None — 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 — formats wins,
      and now says so.

    If you promote DeprecationWarning to 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.suppressed was 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.5 has 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 stable DimensionId(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 a dimension(...) line will name, and what
    suppression and provenance key on.

Changed

  • Sheet.dimension(kind=…, value=…) is now Sheet.measured_dimension(...)
    (ADR 0016 / #873), and model.declare.authored_dimension is
    model.declare.measured_dimension to match. This reserves the name dimension for
    the referential verb ADR 0016 defines — name a feature and a role, carry no number, let
    the engine read the value off the geometry — which Drawing.dimension already is and
    Sheet.dimension will 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.dimension is solely
    the referential verb, and the old keyword call raises with measured_dimension named. See
    Removed (breaking) above. Generated AP242 scripts emit measured_dimension and so arrive
    un-deprecated.
  • Sheet handles 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 a features reorder instead of naming whatever took the slot.
    Reordering with reverse()/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 across of(),
    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 (_analyse and Sheet.model).

  • A declared envelope's frame origin sat a half-height below a detected one (#977). It
    used bbox_min.Z where the detector uses the bbox centre. Dimension output is unchanged —
    envelope sizes derive from bbox_min/bbox_max, and the overall height is compiled from the
    model bbox — but frame.origin is the generic feature site, so a GD&T control frame,
    surface finish or note targeting a hand-declared sheet.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 --script were 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 through fact (#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 print THRU.

  • The balloon ring clears the view it annotates after a hole-table escalation
    (#901/#903).