Fix calculate_unit_scale() crash on SQLite-linked files

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.
This commit is contained in:
Richard Brice
2026-08-10 10:59:25 -07:00
parent 4cfe1f96f8
commit 2bfcf8ab83
2 changed files with 39 additions and 12 deletions
@@ -729,18 +729,13 @@ def calculate_unit_scale(ifc_file: ifcopenshell.file, unit_type: str = "LENGTHUN
# non-length dimensions (PASCAL, NEWTON, GRAM, ...) keep the linear
# multiplier, as there the prefix scales the derived unit itself.
# https://github.com/IfcOpenShell/IfcOpenShell/issues/9278
dimensions = unit.Dimensions
length_exponent = dimensions.LengthExponent
if length_exponent > 0 and not any(
(
dimensions.MassExponent,
dimensions.TimeExponent,
dimensions.ElectricCurrentExponent,
dimensions.ThermodynamicTemperatureExponent,
dimensions.AmountOfSubstanceExponent,
dimensions.LuminousIntensityExponent,
)
):
#
# Dimensions is looked up from si_dimensions by name rather than via
# unit.Dimensions (the schema-derived IfcDimensionalExponents), since
# the derived attribute isn't computed for SQLite-linked files and
# would return None there.
length_exponent, *other_exponents = get_si_dimensions(unit.Name.replace("METER", "METRE"))
if length_exponent > 0 and not any(other_exponents):
prefix_multiplier **= length_exponent
unit_scale *= prefix_multiplier
return unit_scale