edit_pset()'s unpack_unit_value() couldn't distinguish "no Unit dict was
passed" from "{"Unit": None, ...} passed to explicitly clear an existing
override" -- both collapsed to a bare None, and every consuming call site
checked truthiness, so there was no way to actually clear a previously-set
property Unit override once one existed. Fixed with a private _NO_UNIT
sentinel; bare (unwrapped) values still leave Unit untouched exactly as
before.
edit_qto() had no Unit-handling capability at all: neither
update_existing_property() nor add_new_properties() ever read or wrote a
quantity's Unit attribute. Added the same {"Unit": ..., "NominalValue": ...}
wrapped-dict convention edit_pset() already supports, disambiguated from
the pre-existing IfcPhysicalComplexQuantity dict convention
({"Discrimination": ..., "HasQuantities": ...}) by checking for a "Unit"
key -- a complex-quantity spec never contains one.
ifcopenshell.util.unit gains two small helpers:
- get_unit_scale(unit): dispatches to get_derived_unit_scale/
get_named_unit_scale depending on unit type, also used to de-duplicate
calculate_unit_scale()'s own inline dispatch of the same logic.
- get_candidate_units(ifc_file, unit_type): all units in a file matching a
given unit type, unlike get_project_unit()'s single-default lookup.
Adds regression tests for all of the above, including explicit-clear,
bare-value-preserves-override, and complex-quantity-routing-unaffected
cases.
NominalValue is optional -- IfcPropertySingleValue permits a null value --
but get_property_unit() unconditionally accessed prop.NominalValue.is_a(),
crashing on any single-value property that's legitimately blank.
Also adds a regression test confirming IfcContextDependentUnit symbols
("each", "boxes", etc.) aren't shadowed by the IfcDerivedUnit branch added
in the previous commit.
IfcSIUnit.Dimensions is a schema-derived attribute that isn't computed for
Bonsai's SQLite-linked "large model" file representation, returning None
there instead of an IfcDimensionalExponents entity. #9278 added an
unconditional unit.Dimensions.LengthExponent access to every IfcSIUnit
processed by calculate_unit_scale(), so it crashed project loading for
any linked file, even ones with no unit prefixes at all -- not just the
prefixed-area/volume case the fix targeted.
Fixed by reading dimensions from the existing si_dimensions table (keyed
by the unit's stored Name, not the unresolvable derived attribute) instead
of unit.Dimensions.
See the PR discussion for a standalone reproduction script.
First v0.9.0alpha0 binary set, so the version prefix moves with it.
The bump trackers had drifted (bonsai's OLD pointed at 3e7b739 while
ifcopenshell-python pinned e333c1c), so this was done by hand;
'make bump' works again from here.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- assert isinstance(res, list) was wrong because duplicate_task returns a tuple not a list
- removed overkill assertion anyway as the usecase is already typed.
- setting optional name or reuse planned schedule name
- usecase now returns created baseline work schedule
Most of them are actually correct, but they're not enforced in general on the repo, so using them blocks us from flagging `unused-noqa` for rules that we actually do use.
An SI prefix attaches to the base unit symbol and the prefixed symbol is
raised to the power as a whole: DECI CUBIC_METRE is dm3 = a litre = 1e-3 m3,
not 0.1 m3. The scale factor previously applied the prefix multiplier
linearly for all IfcSIUnits, inflating volumes x100 and areas x10 for such
declarations (produced e.g. by MagiCAD for Revit MEP exports).
Following the reviewer note in #9278, the exponent is taken from the
derived attribute IfcSIUnit.Dimensions rather than from substring matching
on the unit name: the multiplier is raised to LengthExponent only when the
unit's dimensions are a pure power of length, so prefixed derived units
(KILO PASCAL, MEGA NEWTON) and non-length units (KILO GRAM) correctly keep
the linear multiplier. This matches the exponent handling already present
in convert() and named_dimensions in the same module.
Adds regression tests for prefixed AREAUNIT/VOLUMEUNIT and for the
linear-prefix behaviour of PRESSUREUNIT/MASSUNIT.
Apply the rename manifest, normalize serializer filenames to the classes they define, and update includes and CMake source lists.
Generated with the assistance of an AI coding tool.
rocks_db_file_storage already exposes a `g|`-prefixed guid -> instance
name map, but RocksDbSerializer never populated it, so by_guid() on a
converted file always threw.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>