* Fix ci-bonsai-daily: ProjectLibraryData duplicate parent-library enum parent_libraries_enum() adds an explicit entry for get_root_context(), then loops over cls.data["project_libraries"] (all IfcProjectLibrary entities) and appends each. For a library-only file (no IfcProject), get_root_context falls back to the top-level IfcProjectLibrary itself, so the root is appended twice with the same enum key (its STEP id), which Blender EnumProperty requires to be unique -> the data load asserts. Normal project files are unaffected (root is an IfcProject whose id never collides with a library id). Skip library_id == root.id() in the loop (dedup by id, the colliding key). Verified in headless Blender: test_project_library_data.py::TestLibraryOnlyFile goes from 1 failed / 5 passed to 6 passed. This change was made with the assistance of an AI tool. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Bonsai: repair library files missing the required IfcProject, not just the symptom Per the IFC Project Context concept template, every project data set (library files included) shall contain exactly one IfcProject, and IfcProjectLibrary instances are assigned to it via IfcRelDeclares. There is no such thing as a spec-valid file rooted on IfcProjectLibrary alone. get_root_context() (added in260a387069, #8184) treated a missing IfcProject as license to use the top-level IfcProjectLibrary as the file's root context instead. That invalid premise is why project_libraries() (which walks every IfcProjectLibrary, root included) then re-added that same entity, producing the duplicate, colliding enum key this PR originally papered over with a dedup guard. Add tool.Project.ensure_project_context(), which repairs a file missing IfcProject by creating one and declaring the file's root-level IfcProjectLibrary instances to it, and tool.Project.open_library_file(), which opens a library file through that repair. Route all three IfcStore.library_file load sites in SelectLibraryFile through it. Downstream code (get_root_context, ProjectLibraryData, RefreshLibrary, AddProjectLibrary) now always operates on a spec-valid model, so the duplicate enum entry cannot occur; the previous one-line dedup guard in parent_libraries_enum() is kept only as cheap defense in depth for callers that bypass the load-time repair, not as the fix. Rework test_project_library_data.py: the previous _make_library_only_file() fixture built an invalid library-only model and asserted that as correct behaviour. Replace it with a spec-valid fixture (IfcProject + IfcProjectLibrary declared to it) for the downstream tests, and a malformed fixture used only to exercise the new repair path. Verified live in headless Blender (isolated profile): reproduced the original duplicate-enum-key failure mode, then confirmed ensure_project_context/ open_library_file repair a malformed file and ProjectLibraryData, refresh_library and add_project_library all operate correctly on the result, with no duplicate keys and no regression on already-valid files or IFC2X3. This change was made with the assistance of an AI tool. * Bonsai: stop supporting library-only files, do not repair them Per Moult's feedback: if the IFC is invalid, our default position is to not support it, not to patch around it. A library file with no IfcProject is invalid IFC (Project Context concept template requires exactly one IfcProject), and it is not ubiquitous: every library file bonsai ships under bim/data/libraries has an IfcProject with the IfcProjectLibrary declared to it via IfcRelDeclares. The single #8183 report is an outlier, not a common authoring pattern worth accommodating. Remove tool.Project.ensure_project_context() and open_library_file() (the load-time repair added in the previous commit here) and revert SelectLibraryFile's three load sites to plain ifcopenshell.open. Simplify get_root_context() back to returning ifc_file.by_type("IfcProject")[0] directly, no IfcProjectLibrary fallback: a file without IfcProject now raises IndexError instead of being silently treated as valid. AddProjectLibrary's nest-under-library branch is now dead code (root_context is always an IfcProject) and is removed. The one-line enum dedup guard from the original commit here is also removed: since get_root_context can only return an IfcProject or raise, an IfcProject id can never collide with a library id, so the guard has nothing left to guard against. Rework test_project_library_data.py: drop the invalid _make_library_only_file fixture and its tests, which asserted an unsupported model as correct behaviour. Replace with a single spec-valid fixture matching bonsai's own shipped library files (IfcProject + IfcProjectLibrary declared to it), used for the ci-bonsai-daily regression test and the refresh/add-library operators, plus one explicit test that get_root_context raises for a file without IfcProject, documenting that this input is intentionally unsupported rather than silently tolerated. Verified live in headless Blender (isolated profile, source-loaded, never the real profile): confirmed the removed methods are gone, that a library-only file now raises instead of being handled, that ProjectLibraryData/refresh_library/add_project_library all work correctly on a spec-valid model with unique enum keys, and spot-checked that every library file under bim/data/libraries already has an IfcProject. This change was made with the assistance of an AI tool. * Bonsai: inline get_root_context, trim docstrings, confirm get_parent_library unchanged Per Moult's round 3 review. get_root_context added nothing over ifc_file.by_type("IfcProject")[0], which is guaranteed by the IFC Project Context concept template; remove it and inline the call at its three sites (operator.py's RefreshLibrary and AddProjectLibrary, data.py's parent_libraries_enum). Trim the get_parent_library docstring to one line; its logic is untouched by this PR, byte for byte identical to origin/v0.8.0, and still returns None only when project_library has neither Nests nor HasContext, never for a library declared directly to IfcProject. Rework test_project_library_data.py to match: replace the two get_root_context-specific tests with one that exercises the real call site (ProjectLibraryData.parent_libraries_enum raising IndexError for a file without IfcProject), and add an explicit test that get_parent_library returns None for a genuinely orphaned library. Also drop a long inline comment that restated what the test body already shows. Verified live in headless Blender (isolated profile, source-loaded, never the real profile): all 17 test/bim/module/project tests pass, including the new get_parent_library None-for-orphan case. Ran the full test/bim suite before and after on the identical harness: 82 failed/1335 passed both times, same failing tests (all pre-existing, unrelated to this module). This change was made with the assistance of an AI tool. * Bonsai: fix EditProjectLibrary leaving stale declarations after reparenting Per Moult's round 4 review. The assertion change (get_parent_library(root) now returns the IfcProject instead of None) is correct: in the old library-only test model a top-level library had neither IfcRelNests nor IfcRelDeclares, so None meant "top level". In the new spec-valid model a top-level library is always declared to the guaranteed IfcProject via IfcRelDeclares, so get_parent_library correctly resolves it through the HasContext branch instead of falling through to None. get_project_hierarchy already keys top-level libraries under the project for exactly this reason, so the library tree still renders correctly. Auditing every caller found one real bug in EditProjectLibrary, which Gorgious56 originally wrote for the library-only model. Its move-library logic assumed a top-level library (previous_parent_library is None) needed no cleanup before nesting it under a new parent, and that unnesting a library back to the project needed no new relationship because it was "already assigned by default". Both assumptions relied on a top-level library never actually holding a IfcRelDeclares, which is no longer true. Reproduced live: moving a project-declared library under another library left its old IfcRelDeclares dangling alongside the new IfcRelNests (an invalid double parentage), and moving a nested library back to the project left it with neither relationship, orphaning it out of the tree entirely. Fixed by tearing down whichever of IfcRelDeclares/IfcRelNests the library previously had before establishing whichever one the new parent requires, instead of assuming which prior state applies. Added tests: get_parent_library resolving a nested sub-library to its library parent (the third contract case alongside project-declared and orphaned), and both EditProjectLibrary reparenting directions, which fail without the operator.py fix and pass with it. Verified live in headless Blender (isolated profile, source-loaded, never the real profile): all 20 test/bim/module/project tests pass. Ran the full test/bim suite before and after on the identical harness: 123 failed/1294 passed before, 123 failed/1297 passed after, identical failing test names in both runs (diffed), the extra 3 passes are the new tests above. This change was made with the assistance of an AI tool. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commitd1f9e5243e)
IfcOpenShell
IfcOpenShell is an open source (LGPL) software library for working with Industry Foundation Classes (IFC). Complete parsing support is provided for IFC2x3 TC1, IFC4 Add2 TC1, IFC4x1, IFC4x2, and IFC4x3 Add2. Extensive geometric support is implemented for the IFC releases IFC2x3 TC1 and IFC4 Add2 TC1. Extending with support for arbitrary IFC schemas is possible at compile-time when using C++ and at run-time when using Python.
In addition to a C++ and Python API, IfcOpenShell comes with an ecosystem of tools, notably including IfcConvert (an application to convert IFC models to other formats), Bonsai (an add-on to Blender providing a graphical IFC authoring platform), and many other libraries, CLI apps, and more. Support is also provided for auxiliary standards such as BCF and IDS.
For more information, see:
Development is sponsored through your generous donations!
Contents
| Name | Description | License | Service |
|---|---|---|---|
| bcf | Library to read and write BCF-XML and query OpenCDE BCF-API modules | LGPL-3.0-or-later | |
| bonsai | Add-on to Blender providing a graphical native IFC authoring platform | GPL-3.0-or-later | |
| bsdd | Library to query the bSDD API | LGPL-3.0-or-later | |
| ifc2ca | Utility to convert IFC structural analysis models to Code_Aster | LGPL-3.0-or-later | |
| ifc4d | Convert to and from IFC and project management software | LGPL-3.0-or-later | |
| ifc5d | Report and optimise cost information from IFC | LGPL-3.0-or-later | |
| ifcbimtester | Wrapper for Gherkin based unit testing for IFC models | LGPL-3.0-or-later | |
| ifcblender | Historic Blender IFC import add-on | LGPL-3.0-or-later* | |
| ifccityjson | Convert CityJSON to IFC | LGPL-3.0-or-later | |
| ifcclash | Clash detection library and CLI app | LGPL-3.0-or-later | |
| ifcconvert | CLI app to convert IFC to many other formats | LGPL-3.0-or-later* | |
| ifccsv | Library and CLI app to export and import schedules from IFC | LGPL-3.0-or-later | |
| ifcdiff | Compare changes between IFC models | LGPL-3.0-or-later | |
| ifcedit | CLI wrapper for ifcopenshell.api IFC model mutation functions | LGPL-3.0-or-later | |
| ifcfm | Extract IFC data for FM handover requirements | LGPL-3.0-or-later | |
| ifcmax | Historic extension for IFC support in 3DS Max | LGPL-3.0-or-later* | |
| ifcmcp | MCP server for querying and editing IFC building models | LGPL-3.0-or-later | |
| ifcopenshell-python | Python library for IFC manipulation | LGPL-3.0-or-later* | |
| ifcpatch | Utility to run pre-packaged scripts to manipulate IFCs | LGPL-3.0-or-later | |
| ifcquery | CLI tool for querying and inspecting IFC building models | LGPL-3.0-or-later | |
| ifcsverchok | Blender Add-on for visual node programming with IFC | GPL-3.0-or-later | |
| ifctester | Library, CLI and webapp for IDS model auditing | LGPL-3.0-or-later |
The IfcOpenShell C++ codebase is split into multiple interal libraries:
| Name | Description | License |
|---|---|---|
| ifcgeom | Internal library for IfcOpenShell | LGPL-3.0-or-later* |
| ifcgeom_schema_agnostic | Internal library for IfcOpenShell | LGPL-3.0-or-later* |
| ifcgeomserver | Internal library for IfcOpenShell | LGPL-3.0-or-later* |
| ifcjni | Internal library for IfcOpenShell | LGPL-3.0-or-later* |
| ifcparse | Internal library for IfcOpenShell | LGPL-3.0-or-later* |
| ifcwrap | Internal library for IfcOpenShell | LGPL-3.0-or-later* |
| serializers | Internal library for IfcOpenShell | LGPL-3.0-or-later* |