All notable changes to bimdiff are documented here.
Format follows Keep a Changelog,
and the project adheres to Semantic Versioning.
Adds an opt-in noise filter for real-world IFC pipelines (notably ArchiCAD) that re-stamp housekeeping properties on every save and drown the actual semantic diff in noise.
bimdiff.filtersmodule with two helpers:is_noisy_change(field) -> bool— predicate for known noise patterns:geometry.presence(Plan ↔ Body export flips),properties.AC_Pset_RenovationAndPhasing.*(ArchiCAD phase stamp),properties.None.*(un-named auto-derived quantities), and pset names containing non-printable / non-ASCII bytes (corrupted UTF-8 from exporters that emit project-internal label names).filter_noise(DiffResult) -> DiffResult— strips noisyPropertyChangeentries; modified entities whose changes are all noise are demoted to unchanged. Counts and severity are recomputed.
- CLI:
--hide-noiseflag that routes the diff result throughfilter_noisebefore rendering. On the typical ArchiCAD round-trip this drops 30–60% of the modified count by removing pure export noise.
The diff engine itself stays neutral and keeps reporting every change it can detect — filtering is purely opt-in post-processing.
Hardening release. No behaviour changes for normal diffs; security and operational improvements.
- CSV export now escapes formula injection. Cells starting with
=,+,-,@, tab or CR are prefixed with an apostrophe so that Excel and Google Sheets do not execute them as formulas. Closes a realistic attack surface for shared review CSVs.
logging.disable(logging.CRITICAL)no longer silences user logging. The hot-loop logging suppression is replaced by a_quiet_ifccontext manager that only raises theifcopenshelllogger to ERROR. User loggers, Sentry breadcrumbs andbimdiff._engine.*warnings (such as the duplicate-GlobalIdnotice) keep emitting.
- Soft warning when an input IFC exceeds 200 MB. Non-blocking, but leaves a breadcrumb in the user's logs when a slow/heavy diff is expected.
- PyPI metadata.
classifiersandkeywordsare now set so the package is discoverable when searching for "ifc", "bim", "diff". ifcopenshellis pinned to>=0.8,<0.9to match the API surface the engine is tested against.
- HTML report footer renders the installed package version. Previously
hardcoded as
v0.1.0and drifting with every release.__version__now reads fromimportlib.metadata, makingpyproject.tomlthe single source of truth.
Minor release adding completeness to the diff and a couple of API tweaks.
Output schemas evolve in additive ways, but the change-count totals in
DiffSummary will look different on the same input — see Breaking below.
- Property additions and removals between revisions are now flagged.
_diff_propertiespreviously only compared the intersection of pset keys; a newPset_WallCommon.ThermalTransmittancein v2 was silently ignored. The diff now compares the union and emitsNone → value/value → NonePropertyChangeentries. - IFC type changes with a stable
GlobalIdare now detected. When an element flips fromIfcWalltoIfcBeamwhile keeping the same GUID (Revit family swap, etc.), aPropertyChange(field="ifc_type", ...)is emitted. DiffResult.unchanged_ids: list[str]. Web viewers and downstream tools needed the GlobalIds of unchanged elements to colour them appropriately. Sorted for reproducibility.unchanged_countis kept alongside as a denormalized counter.- Granular geometry change reporting.
_shapes_differ(single bool) is replaced by_shape_changes(list ofPropertyChange). Geometry diffs now surface as up to three categories:geometry.bbox_size,geometry.openings,geometry.projections. If geometry is present on only one side, a singlegeometry.presencechange is emitted ("absent"/"present"). diff_ifc(selector=...)as the canonical name for the ifcopenshell-selector argument. The oldfilter_elementskeyword still works but emits aDeprecationWarning; it will be removed in v0.3.
- CLI
--filter-typenow narrows the diff at the engine level. It is converted to an ifcopenshell selector and passed viaselector=..., avoiding the previous full-diff-then-filter round-trip.--filter-storeyremains post-hoc.
DiffSummary.geometry_changescan grow up to ~3× because each affected element may now contribute multiple granular changes instead of one opaque entry.- Elements that previously appeared as
unchangedmay now appear asmodifiedwhen the only difference is a property added or removed (rather than a value change).unchanged_countadjusts accordingly.
- Geometry tolerance is now unit-aware.
_shapes_differpreviously used a hardcoded 50-model-unit absolute floor below which all shape deltas were ignored. In a file authored in metres that meant a 50-metre delta was silently swallowed; in millimetres it was the intended ~5 cm noise floor. The threshold is now derived fromifcopenshell.util.unit.calculate_unit_scale(...)and the IFC's declared precision, so 1 mm of physical noise stays noise regardless of the file's authored length unit.
- Material changes are now detected. Previously, a wall changing from
CLS 25toCLS 30was silently treated as unchanged because_diff_propertiesonly looked at property sets, while materials are associated viaIfcRelAssociatesMaterial. The material is now extracted via a cached helper and routed through the same diff path as psets. - Element caches no longer collide between old and new files.
IfcCacheMixinkeyed every entry byelement.id()alone, but IFC ids are positional integers that frequently overlap between two revisions of the same model. Entries are now keyed by(file_pointer, element.id()), eliminating false negatives in property/relationship/material diffs that previously passed only by coincidence. CanonicalEntity.propertiesis now JSON-serializable. Wrapped IFC values (IfcLabel,IfcPositiveLengthMeasure, etc.) leaked fromget_psets()into the canonical entity, causingexport_json(result)to fail on real Revit exports. Values are now normalized at extraction time.- Diff output is deterministic across runs. Set iterations in
differ.pyproduced output whose order depended onPYTHONHASHSEED, breaking reproducible CSV/JSON exports and report-hash diffing.added,removedandmodifiedare now sorted byglobal_id. - Duplicate
GlobalIds in source files emit a warning instead of silently overwriting._build_element_indexswitches to first-wins semantics and logs aWARNINGfor each collision, surfacing bad exporter output.
- Added a "Known Limitations" section to
README.mdcovering property add/remove blindness, undetectedIfcTypeswaps, opaque geometry change reporting, and unit-aware tolerance — each with the milestone where it will be addressed.
Initial public release.