Rename ifcapi to ifcedit, README and black

This commit is contained in:
Bruno Postle
2026-02-09 22:59:11 +00:00
parent 12ed2d1ec3
commit b1f1de954d
16 changed files with 528 additions and 78 deletions
+208
View File
@@ -0,0 +1,208 @@
# ifcedit
A CLI wrapper that exposes all 350+ `ifcopenshell.api` mutation functions as
shell commands. Functions are auto-discovered at runtime via introspection --
no hardcoded list to maintain.
## Installation
```bash
pip install ifcedit
```
Requires `ifcopenshell`.
## Usage
```
ifcedit <command> [options] [--format json|text]
```
Three subcommands: `list` to discover functions, `docs` to read their
documentation, and `run` to execute them.
## Subcommands
### list
Discover available API modules and their functions.
**List all modules:**
```bash
ifcedit list
```
```json
[
{
"module": "root",
"description": "Functions for creating project-level entities",
"functions": ["create_entity", "remove_product", "copy_class"],
"count": 3
},
{
"module": "spatial",
"description": "Functions for managing spatial relationships",
"functions": ["assign_container", "unassign_container"],
"count": 2
}
]
```
**List functions in a module:**
```bash
ifcedit list root
```
```json
[
{
"name": "create_entity",
"description": "Create an IFC entity with optional initial attributes",
"params": [
{"name": "ifc_class", "type": "str", "required": true},
{"name": "name", "type": "Optional[str]"}
]
}
]
```
### docs
Show full documentation for a specific function, including parameter
descriptions from docstrings and return type.
```bash
ifcedit docs root.create_entity
```
```json
{
"module": "root",
"function": "create_entity",
"description": "Create an IFC entity with optional initial attributes",
"long_description": "This function creates a new entity instance...",
"params": [
{
"name": "ifc_class",
"type": "str",
"required": true,
"description": "The IFC class name (e.g. 'IfcWall', 'IfcProject')"
},
{
"name": "name",
"type": "Optional[str]",
"description": "Optional name attribute"
}
],
"return_type": "ifcopenshell.entity_instance",
"return_description": "The newly created entity instance"
}
```
### run
Execute an API function against an IFC file. Parameters are passed as
`--key value` pairs after the function name.
```bash
ifcedit run model.ifc root.create_entity --ifc_class IfcWall --name "My Wall"
```
```json
{
"ok": true,
"result": {"id": 42, "type": "IfcWall", "name": "My Wall"}
}
```
**Options:**
- `-o, --output <path>` -- write to a different file instead of overwriting the input
- `--dry-run` -- validate parameters without executing or saving
```bash
# Save to a new file
ifcedit run model.ifc root.create_entity -o out.ifc --ifc_class IfcWall
# Validate without executing
ifcedit run model.ifc root.create_entity --dry-run --ifc_class IfcWall
```
Dry-run output shows the resolved parameters:
```json
{
"ok": true,
"dry_run": true,
"module": "root",
"function": "create_entity",
"args": {"ifc_class": "IfcWall", "name": "My Wall"}
}
```
## Parameter type coercion
CLI strings are automatically converted to the types expected by each API
function, using the function's type annotations:
| Type | CLI input | Python value |
|------|-----------|--------------|
| `str` | `"hello"` | `"hello"` |
| `int` | `"42"` or `"#42"` | `42` |
| `float` | `"3.14"` | `3.14` |
| `bool` | `"true"`, `"1"`, `"yes"` | `True` |
| `Optional[X]` | `"none"` | `None` |
| `entity_instance` | `"42"` or `"#42"` | resolved from model by step ID |
| `list[entity_instance]` | `"5,6,7"` or `"[5, 6, 7]"` | list of resolved entities |
| `dict` | `'{"key": "val"}'` | parsed JSON object |
| `Literal["A", "B"]` | `"A"` | validated against allowed values |
## Examples
```bash
# Create a project
ifcedit run model.ifc root.create_entity --ifc_class IfcProject --name "My Project"
# Assign an element to a storey
ifcedit run model.ifc spatial.assign_container --products 10 --relating_structure 4
# Assign multiple elements at once
ifcedit run model.ifc aggregate.assign_object --products "5,6,7" --relating_object 1
# Add a property set
ifcedit run model.ifc pset.add_pset --product 10 --name "Pset_WallCommon"
# Edit properties
ifcedit run model.ifc pset.edit_pset --pset 15 \
--properties '{"IsExternal": true, "FireRating": "2HR"}'
```
## Error handling
Errors are reported in the JSON response:
```json
{
"ok": false,
"error": "Entity #999 not found in model"
}
```
Exit code is 0 on success, 1 on error.
## Relationship to ifcquery
`ifcedit` and `ifcquery` are complementary tools:
- **ifcquery** reads and inspects IFC models (summary, tree, info, select, relations, clash)
- **ifcedit** modifies IFC models by wrapping `ifcopenshell.api` functions
A typical workflow: inspect with `ifcquery`, look up the right API function
with `ifcedit docs`, then apply changes with `ifcedit run`.
## License
LGPLv3+ -- see the IfcOpenShell project license.
@@ -1,19 +1,19 @@
# IfcApi - CLI wrapper for ifcopenshell.api mutation functions
# IfcEdit - CLI wrapper for ifcopenshell.api mutation functions
# Copyright (C) 2025 Bruno Postle <bruno@postle.net>
#
# This file is part of IfcApi.
# This file is part of IfcEdit.
#
# IfcApi is free software: you can redistribute it and/or modify
# IfcEdit is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcApi is distributed in the hope that it will be useful,
# IfcEdit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcApi. If not, see <http://www.gnu.org/licenses/>.
# along with IfcEdit. If not, see <http://www.gnu.org/licenses/>.
__version__ = version = "0.0.0"
@@ -1,20 +1,20 @@
# IfcApi - CLI wrapper for ifcopenshell.api mutation functions
# IfcEdit - CLI wrapper for ifcopenshell.api mutation functions
# Copyright (C) 2025 Bruno Postle <bruno@postle.net>
#
# This file is part of IfcApi.
# This file is part of IfcEdit.
#
# IfcApi is free software: you can redistribute it and/or modify
# IfcEdit is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcApi is distributed in the hope that it will be useful,
# IfcEdit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcApi. If not, see <http://www.gnu.org/licenses/>.
# along with IfcEdit. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
@@ -24,8 +24,8 @@ import sys
import ifcopenshell
from ifcapi.discover import function_docs, list_functions, list_modules
from ifcapi.run import run_api
from ifcedit.discover import function_docs, list_functions, list_modules
from ifcedit.run import run_api
def format_output(data, fmt: str) -> str:
@@ -138,7 +138,7 @@ def _parse_extra_args(extra: list[str]) -> dict[str, str]:
def main():
parser = argparse.ArgumentParser(
prog="ifcapi",
prog="ifcedit",
description="CLI wrapper for ifcopenshell.api IFC model mutation functions",
)
parser.add_argument(
@@ -1,20 +1,20 @@
# IfcApi - CLI wrapper for ifcopenshell.api mutation functions
# IfcEdit - CLI wrapper for ifcopenshell.api mutation functions
# Copyright (C) 2025 Bruno Postle <bruno@postle.net>
#
# This file is part of IfcApi.
# This file is part of IfcEdit.
#
# IfcApi is free software: you can redistribute it and/or modify
# IfcEdit is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcApi is distributed in the hope that it will be useful,
# IfcEdit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcApi. If not, see <http://www.gnu.org/licenses/>.
# along with IfcEdit. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
@@ -1,20 +1,20 @@
# IfcApi - CLI wrapper for ifcopenshell.api mutation functions
# IfcEdit - CLI wrapper for ifcopenshell.api mutation functions
# Copyright (C) 2025 Bruno Postle <bruno@postle.net>
#
# This file is part of IfcApi.
# This file is part of IfcEdit.
#
# IfcApi is free software: you can redistribute it and/or modify
# IfcEdit is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcApi is distributed in the hope that it will be useful,
# IfcEdit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcApi. If not, see <http://www.gnu.org/licenses/>.
# along with IfcEdit. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
@@ -55,12 +55,14 @@ def list_modules() -> list[dict]:
description = ""
if mod.__doc__:
description = mod.__doc__.strip().split("\n")[0]
modules.append({
"module": child.name,
"description": description,
"functions": list(all_names),
"count": len(all_names),
})
modules.append(
{
"module": child.name,
"description": description,
"functions": list(all_names),
"count": len(all_names),
}
)
return modules
@@ -80,11 +82,13 @@ def list_functions(module: str) -> list[dict]:
if fn.__doc__:
description = fn.__doc__.strip().split("\n")[0]
params = _extract_params(fn)
functions.append({
"name": name,
"description": description,
"params": params,
})
functions.append(
{
"name": name,
"description": description,
"params": params,
}
)
return functions
@@ -1,20 +1,20 @@
# IfcApi - CLI wrapper for ifcopenshell.api mutation functions
# IfcEdit - CLI wrapper for ifcopenshell.api mutation functions
# Copyright (C) 2025 Bruno Postle <bruno@postle.net>
#
# This file is part of IfcApi.
# This file is part of IfcEdit.
#
# IfcApi is free software: you can redistribute it and/or modify
# IfcEdit is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IfcApi is distributed in the hope that it will be useful,
# IfcEdit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with IfcApi. If not, see <http://www.gnu.org/licenses/>.
# along with IfcEdit. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
@@ -24,7 +24,7 @@ import typing
import ifcopenshell
from ifcapi.coerce import coerce_value
from ifcedit.coerce import coerce_value
def run_api(
@@ -3,7 +3,7 @@ requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "ifcapi"
name = "ifcedit"
version = "0.0.0"
authors = [
{ name="Bruno Postle", email="bruno@postle.net" },
@@ -23,7 +23,7 @@ Documentation = "https://docs.ifcopenshell.org"
Issues = "https://github.com/IfcOpenShell/IfcOpenShell/issues"
[tool.setuptools.packages.find]
include = ["ifcapi*"]
include = ["ifcedit*"]
exclude = ["test*"]
[tool.ruff]
@@ -5,7 +5,7 @@ import pytest
import ifcopenshell
from ifcapi.coerce import coerce_value
from ifcedit.coerce import coerce_value
class TestStringCoercion:
@@ -1,4 +1,4 @@
from ifcapi.discover import function_docs, list_functions, list_modules
from ifcedit.discover import function_docs, list_functions, list_modules
class TestListModules:
@@ -5,10 +5,10 @@ import sys
import pytest
def run_ifcapi(*args):
"""Run ifcapi as a subprocess and return (stdout, stderr, returncode)."""
def run_ifcedit(*args):
"""Run ifcedit as a subprocess and return (stdout, stderr, returncode)."""
result = subprocess.run(
[sys.executable, "-m", "ifcapi", *args],
[sys.executable, "-m", "ifcedit", *args],
capture_output=True,
text=True,
)
@@ -17,7 +17,7 @@ def run_ifcapi(*args):
class TestListCommand:
def test_list_all_modules(self):
stdout, stderr, rc = run_ifcapi("list")
stdout, stderr, rc = run_ifcedit("list")
assert rc == 0
data = json.loads(stdout)
assert isinstance(data, list)
@@ -26,7 +26,7 @@ class TestListCommand:
assert "spatial" in module_names
def test_list_module_functions(self):
stdout, stderr, rc = run_ifcapi("list", "root")
stdout, stderr, rc = run_ifcedit("list", "root")
assert rc == 0
data = json.loads(stdout)
assert isinstance(data, list)
@@ -34,14 +34,14 @@ class TestListCommand:
assert "create_entity" in names
def test_list_text_format(self):
stdout, stderr, rc = run_ifcapi("--format", "text", "list")
stdout, stderr, rc = run_ifcedit("--format", "text", "list")
assert rc == 0
assert "root" in stdout
class TestDocsCommand:
def test_docs_create_entity(self):
stdout, stderr, rc = run_ifcapi("docs", "root.create_entity")
stdout, stderr, rc = run_ifcedit("docs", "root.create_entity")
assert rc == 0
data = json.loads(stdout)
assert data["module"] == "root"
@@ -49,18 +49,18 @@ class TestDocsCommand:
assert "params" in data
def test_docs_invalid_path(self):
stdout, stderr, rc = run_ifcapi("docs", "invalid_path")
stdout, stderr, rc = run_ifcedit("docs", "invalid_path")
assert rc != 0
assert "module.function" in stderr
def test_docs_unknown_function(self):
stdout, stderr, rc = run_ifcapi("docs", "root.nonexistent")
stdout, stderr, rc = run_ifcedit("docs", "root.nonexistent")
assert rc != 0
class TestRunCommand:
def test_create_entity(self, model_file):
stdout, stderr, rc = run_ifcapi(
stdout, stderr, rc = run_ifcedit(
"run", model_file, "root.create_entity", "--ifc_class", "IfcWall", "--name", "CLIWall"
)
assert rc == 0, f"stderr: {stderr}"
@@ -70,9 +70,7 @@ class TestRunCommand:
assert data["result"]["name"] == "CLIWall"
def test_dry_run(self, model_file):
stdout, stderr, rc = run_ifcapi(
"run", model_file, "root.create_entity", "--dry-run", "--ifc_class", "IfcWall"
)
stdout, stderr, rc = run_ifcedit("run", model_file, "root.create_entity", "--dry-run", "--ifc_class", "IfcWall")
assert rc == 0
data = json.loads(stdout)
assert data["ok"] is True
@@ -80,9 +78,7 @@ class TestRunCommand:
def test_output_to_different_file(self, model_file, tmp_path):
output = str(tmp_path / "output.ifc")
stdout, stderr, rc = run_ifcapi(
"run", model_file, "root.create_entity", "-o", output, "--ifc_class", "IfcSlab"
)
stdout, stderr, rc = run_ifcedit("run", model_file, "root.create_entity", "-o", output, "--ifc_class", "IfcSlab")
assert rc == 0, f"stderr: {stderr}"
data = json.loads(stdout)
assert data["ok"] is True
@@ -92,10 +88,10 @@ class TestRunCommand:
assert os.path.exists(output)
def test_run_error_bad_function(self, model_file):
stdout, stderr, rc = run_ifcapi("run", model_file, "root.nonexistent")
stdout, stderr, rc = run_ifcedit("run", model_file, "root.nonexistent")
assert rc != 0
def test_run_invalid_function_path(self, model_file):
stdout, stderr, rc = run_ifcapi("run", model_file, "invalid_path")
stdout, stderr, rc = run_ifcedit("run", model_file, "invalid_path")
assert rc != 0
assert "module.function" in stderr
@@ -1,7 +1,7 @@
import ifcopenshell.api.pset
import ifcopenshell.api.root
from ifcapi.run import run_api, serialize_result
from ifcedit.run import run_api, serialize_result
class TestRunApi:
+252
View File
@@ -0,0 +1,252 @@
# ifcquery
A CLI tool for querying and inspecting IFC building models. All output is
structured JSON (or human-readable text), making it easy to pipe into other
tools or scripts.
## Installation
```bash
pip install ifcquery
```
Requires `ifcopenshell`. The `clash` subcommand additionally requires the
IfcOpenShell C++ geometry bindings (`ifcopenshell.geom`).
## Usage
```
ifcquery <ifc_file> <command> [options] [--format json|text]
```
The `--format` flag controls output. Default is `json`; use `text` for
indented human-readable output.
## Subcommands
### summary
Get a model overview: schema version, entity counts, and project info.
```bash
ifcquery model.ifc summary
```
```json
{
"schema": "IFC4",
"total_entities": 1847,
"project": {
"id": 1,
"name": "Office Building",
"description": null
},
"types": {
"IfcWall": 42,
"IfcSlab": 12,
"IfcWindow": 36
}
}
```
### tree
Display the spatial hierarchy from IfcProject down through sites, buildings,
storeys, and their contained elements.
```bash
ifcquery model.ifc tree
```
```json
{
"id": 1,
"type": "IfcProject",
"name": "Office Building",
"children": [
{
"id": 2,
"type": "IfcSite",
"name": "Default Site",
"children": [
{
"id": 3,
"type": "IfcBuilding",
"name": "Main Building",
"children": [
{
"id": 4,
"type": "IfcBuildingStorey",
"name": "Ground Floor",
"elements": [
{"id": 10, "type": "IfcWall", "name": "Wall001"},
{"id": 11, "type": "IfcSlab", "name": "Floor001"}
]
}
]
}
]
}
]
}
```
### info
Get detailed information about a specific element by step ID.
```bash
ifcquery model.ifc info 10
ifcquery model.ifc info '#10'
```
Returns attributes, property sets, type relationship, material assignment,
spatial container, and placement matrix.
```json
{
"id": 10,
"type": "IfcWall",
"attributes": {
"Name": "Wall001",
"Description": null,
"ObjectType": "LOADBEARING"
},
"property_sets": {
"Pset_WallCommon": {
"IsExternal": true,
"FireRating": "2HR"
}
},
"element_type": {"id": 50, "type": "IfcWallType", "name": "Standard"},
"material": {"id": 60, "type": "IfcMaterial", "name": "Concrete"},
"container": {"id": 4, "type": "IfcBuildingStorey", "name": "Ground Floor"},
"placement": [
[1.0, 0.0, 0.0, 5.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0]
]
}
```
### select
Filter elements using the ifcopenshell selector syntax.
```bash
ifcquery model.ifc select 'IfcWall'
ifcquery model.ifc select 'IfcWall, IfcSlab'
```
```json
[
{"id": 10, "type": "IfcWall", "name": "Wall001"},
{"id": 11, "type": "IfcWall", "name": "Wall002"},
{"id": 20, "type": "IfcSlab", "name": "Floor001"}
]
```
Results are sorted by ID.
### relations
Show all relationships for an element, organized by category: hierarchy,
children, type relationships, groups, systems, material, and connections.
```bash
ifcquery model.ifc relations 10
```
```json
{
"id": 10,
"type": "IfcWall",
"name": "Wall001",
"hierarchy": {
"parent": {"id": 4, "type": "IfcBuildingStorey", "name": "Ground Floor"},
"container": {"id": 4, "type": "IfcBuildingStorey", "name": "Ground Floor"}
},
"children": {
"openings": [{"id": 30, "type": "IfcOpeningElement", "name": "Opening01"}]
},
"type_relationship": {
"type_of": {"id": 50, "type": "IfcWallType", "name": "Standard"}
},
"material": {"id": 60, "type": "IfcMaterial", "name": "Concrete"}
}
```
Empty categories are omitted from output.
Use `--traverse up` to walk the spatial hierarchy from the element up to
IfcProject:
```bash
ifcquery model.ifc relations 10 --traverse up
```
```json
[
{"id": 10, "type": "IfcWall", "name": "Wall001"},
{"id": 4, "type": "IfcBuildingStorey", "name": "Ground Floor"},
{"id": 3, "type": "IfcBuilding", "name": "Main Building"},
{"id": 2, "type": "IfcSite", "name": "Default Site"},
{"id": 1, "type": "IfcProject", "name": "Office Building"}
]
```
### clash
Check a single element for geometric intersections and clearance violations
against other elements.
```bash
ifcquery model.ifc clash 10
ifcquery model.ifc clash 10 --clearance 0.5
ifcquery model.ifc clash 10 --scope all --tolerance 0.001
```
Options:
- `--clearance <meters>` -- minimum clearance distance to check
- `--tolerance <meters>` -- intersection tolerance (default: 0.002)
- `--scope {storey,all}` -- check against same-storey elements or all elements (default: storey)
```json
{
"element": {"id": 10, "type": "IfcWall", "name": "Wall001"},
"scope": "storey",
"pass": false,
"checks": {
"intersection": {
"pass": false,
"tolerance": 0.002,
"clashes": [
{
"element": {"id": 11, "type": "IfcWall", "name": "Wall002"},
"type": "intersection",
"distance": 0.0,
"p1": [2.5, 2.5, 1.5],
"p2": [2.5, 2.5, 1.5]
}
]
},
"clearance": {
"pass": true,
"clearance": 0.5,
"clashes": []
}
}
}
```
Requires the IfcOpenShell C++ geometry bindings.
## Error handling
Errors are written to stderr. Exit code is 0 on success, 1 on error.
## License
LGPLv3+ -- see the IfcOpenShell project license.
+4 -12
View File
@@ -62,9 +62,7 @@ def _get_scope_elements(
return elements, "all"
def _build_tree(
model: ifcopenshell.file, elements: set[ifcopenshell.entity_instance]
) -> ifcopenshell.geom.tree | None:
def _build_tree(model: ifcopenshell.file, elements: set[ifcopenshell.entity_instance]) -> ifcopenshell.geom.tree | None:
"""Build geometry tree for given elements using iterator.
Returns None if iterator fails to initialize (no geometry available).
@@ -72,9 +70,7 @@ def _build_tree(
geom_settings = ifcopenshell.geom.settings()
geom_settings.set("use-world-coords", True)
geom_tree = ifcopenshell.geom.tree()
iterator = ifcopenshell.geom.iterator(
geom_settings, model, multiprocessing.cpu_count(), include=list(elements)
)
iterator = ifcopenshell.geom.iterator(geom_settings, model, multiprocessing.cpu_count(), include=list(elements))
if not iterator.initialize():
return None
while True:
@@ -84,9 +80,7 @@ def _build_tree(
return geom_tree
def _format_clash(
clash_result, geom_tree: ifcopenshell.geom.tree, model: ifcopenshell.file
) -> dict[str, Any]:
def _format_clash(clash_result, geom_tree: ifcopenshell.geom.tree, model: ifcopenshell.file) -> dict[str, Any]:
"""Format a single clash result to dict."""
# clash result .a/.b are C++ wrapper entity_instances without .Name;
# look up the Python entity from the model by id for proper serialization
@@ -124,9 +118,7 @@ def clash(
if not scope_elements:
result["pass"] = True
result["checks"] = {
"intersection": {"pass": True, "tolerance": tolerance, "clashes": []}
}
result["checks"] = {"intersection": {"pass": True, "tolerance": tolerance, "clashes": []}}
if clearance is not None:
result["checks"]["clearance"] = {"pass": True, "clearance": clearance, "clashes": []}
return result
+1 -3
View File
@@ -142,9 +142,7 @@ class TestNoClashes:
# Create a model with a single wall
f = ifcopenshell.api.project.create_file()
ifcopenshell.api.owner.settings.get_user = lambda ifc: (ifc.by_type("IfcPersonAndOrganization") or [None])[0]
ifcopenshell.api.owner.settings.get_application = lambda ifc: (
ifc.by_type("IfcApplication") or [None]
)[0]
ifcopenshell.api.owner.settings.get_application = lambda ifc: (ifc.by_type("IfcApplication") or [None])[0]
project = ifcopenshell.api.root.create_entity(f, ifc_class="IfcProject", name="P")
ifcopenshell.api.unit.assign_unit(f)
site = ifcopenshell.api.root.create_entity(f, ifc_class="IfcSite", name="S")