mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-13 19:07:57 +00:00
7cd40bf8cb
ifcquery is a new command-line tool for querying and inspecting IFC models. All output is JSON.
Subcommands:
summary — schema version, entity counts, project metadata
tree — full spatial hierarchy (Project → Site → Building → Storeys → Spaces → Elements)
info <id> — deep inspection of any entity by step ID (attributes, psets, placement matrix, type, material)
select <query> — filter elements using ifcopenshell selector syntax
relations <id> — relationships for an element; --traverse up walks to IfcProject
clash <id> — geometric intersection and clearance detection
validate — schema/constraint validation; --rules adds EXPRESS checks
schedule — work schedules with nested task trees
cost — cost schedules with nested cost item trees
schema <class> — IFC class documentation from the model's schema version
plot — SVG plan drawing
render — 3D geometry rendering
contexts — geometric representation contexts
materials — material assignments
Usage:
python3 -m ifcquery <file.ifc> <subcommand> [args]
Generated with the assistance of an AI coding tool.
159 lines
5.5 KiB
Python
159 lines
5.5 KiB
Python
# This file was generated with the assistance of an AI coding tool.
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
|
|
from ifcquery.relations import relations
|
|
|
|
|
|
class TestWallRelations:
|
|
def test_wall_has_container(self, model):
|
|
wall = model.by_type("IfcWall")[0]
|
|
result = relations(model, wall)
|
|
assert result["id"] == wall.id()
|
|
assert result["type"] == "IfcWall"
|
|
assert result["hierarchy"]["container"]["type"] == "IfcBuildingStorey"
|
|
assert result["hierarchy"]["container"]["name"] == "Ground Floor"
|
|
|
|
def test_wall_has_parent(self, model):
|
|
wall = model.by_type("IfcWall")[0]
|
|
result = relations(model, wall)
|
|
assert result["hierarchy"]["parent"]["type"] == "IfcBuildingStorey"
|
|
|
|
def test_wall_no_children(self, model):
|
|
wall = model.by_type("IfcWall")[0]
|
|
result = relations(model, wall)
|
|
assert "children" not in result
|
|
|
|
def test_wall_empty_categories_omitted(self, model):
|
|
wall = model.by_type("IfcWall")[0]
|
|
result = relations(model, wall)
|
|
assert "groups" not in result
|
|
assert "systems" not in result
|
|
assert "zones" not in result
|
|
assert "connections" not in result
|
|
assert "referenced_structures" not in result
|
|
|
|
|
|
class TestStoreyRelations:
|
|
def test_storey_has_contained(self, model):
|
|
storey = model.by_type("IfcBuildingStorey")[0]
|
|
result = relations(model, storey)
|
|
contained_types = {e["type"] for e in result["children"]["contained"]}
|
|
assert "IfcWall" in contained_types
|
|
assert "IfcSlab" in contained_types
|
|
|
|
def test_storey_has_aggregate_parent(self, model):
|
|
storey = model.by_type("IfcBuildingStorey")[0]
|
|
result = relations(model, storey)
|
|
assert result["hierarchy"]["aggregate"]["type"] == "IfcBuilding"
|
|
assert result["hierarchy"]["aggregate"]["name"] == "TestBuilding"
|
|
|
|
|
|
class TestProjectRelations:
|
|
def test_project_has_parts(self, model):
|
|
project = model.by_type("IfcProject")[0]
|
|
result = relations(model, project)
|
|
parts = result["children"]["parts"]
|
|
assert any(p["type"] == "IfcSite" for p in parts)
|
|
|
|
def test_project_no_hierarchy(self, model):
|
|
project = model.by_type("IfcProject")[0]
|
|
result = relations(model, project)
|
|
assert "hierarchy" not in result
|
|
|
|
|
|
class TestTraverseUp:
|
|
def test_wall_to_project(self, model):
|
|
wall = model.by_type("IfcWall")[0]
|
|
chain = relations(model, wall, traverse="up")
|
|
assert isinstance(chain, list)
|
|
assert chain[0]["type"] == "IfcWall"
|
|
assert chain[-1]["type"] == "IfcProject"
|
|
types = [e["type"] for e in chain]
|
|
assert "IfcBuildingStorey" in types
|
|
assert "IfcBuilding" in types
|
|
assert "IfcSite" in types
|
|
|
|
def test_project_traverse(self, model):
|
|
project = model.by_type("IfcProject")[0]
|
|
chain = relations(model, project, traverse="up")
|
|
assert len(chain) == 1
|
|
assert chain[0]["type"] == "IfcProject"
|
|
|
|
def test_storey_to_project(self, model):
|
|
storey = model.by_type("IfcBuildingStorey")[0]
|
|
chain = relations(model, storey, traverse="up")
|
|
assert chain[0]["type"] == "IfcBuildingStorey"
|
|
assert chain[-1]["type"] == "IfcProject"
|
|
assert len(chain) == 4 # storey -> building -> site -> project
|
|
|
|
|
|
class TestJsonSerializable:
|
|
def test_relations_serializable(self, model):
|
|
wall = model.by_type("IfcWall")[0]
|
|
result = relations(model, wall)
|
|
json.dumps(result)
|
|
|
|
def test_traverse_serializable(self, model):
|
|
wall = model.by_type("IfcWall")[0]
|
|
result = relations(model, wall, traverse="up")
|
|
json.dumps(result)
|
|
|
|
|
|
class TestCLI:
|
|
@staticmethod
|
|
def _ifc_path(model):
|
|
f = tempfile.NamedTemporaryFile(suffix=".ifc", delete=False)
|
|
model.write(f.name)
|
|
f.close()
|
|
return f.name
|
|
|
|
def test_relations_json(self, model):
|
|
path = self._ifc_path(model)
|
|
try:
|
|
wall = model.by_type("IfcWall")[0]
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "ifcquery", path, "relations", str(wall.id())],
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
assert result.returncode == 0
|
|
data = json.loads(result.stdout)
|
|
assert data["type"] == "IfcWall"
|
|
assert "hierarchy" in data
|
|
finally:
|
|
os.unlink(path)
|
|
|
|
def test_relations_traverse_up(self, model):
|
|
path = self._ifc_path(model)
|
|
try:
|
|
wall = model.by_type("IfcWall")[0]
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "ifcquery", path, "relations", str(wall.id()), "--traverse", "up"],
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
assert result.returncode == 0
|
|
data = json.loads(result.stdout)
|
|
assert isinstance(data, list)
|
|
assert data[0]["type"] == "IfcWall"
|
|
assert data[-1]["type"] == "IfcProject"
|
|
finally:
|
|
os.unlink(path)
|
|
|
|
def test_relations_bad_id(self, model):
|
|
path = self._ifc_path(model)
|
|
try:
|
|
result = subprocess.run(
|
|
[sys.executable, "-m", "ifcquery", path, "relations", "999999"],
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
assert result.returncode != 0
|
|
assert "Error" in result.stderr
|
|
finally:
|
|
os.unlink(path)
|