4.1 KiB
ifcopenshell.file
An ifcopenshell.file is the in-memory representation of a parsed IFC file.
It is the central object in every ifcbus operation — all reading, querying,
modifying, and writing go through it.
Opening a file
import ifcopenshell
model = ifcopenshell.open("input.ifc")
# model is an ifcopenshell.file object
ifcopenshell.open() parses the STEP-encoded .ifc file and loads all
entities into memory. The result is a live, mutable object graph.
What it contains
An IFC file is a flat list of entity instances, each identified by a
sequential integer id (#1, #2, …). Entities reference each other by id,
forming a directed graph.
#1 = IfcOrganization(...)
#2 = IfcApplication(#1, ...)
#33 = IfcOwnerHistory(#32, #2, ...)
#514 = IfcSpace('0BTBFw6f90Nfh9rP1dlXrr', #33, 'A101', ...)
The ifcopenshell.file object holds:
- All entity instances (the flat list above)
- Schema — e.g.
IFC2X3,IFC4 - Header — file metadata (author, application, description, timestamp)
Key methods
Querying
# By entity id (integer)
el = model.by_id(514)
# By GlobalId (GUID string)
el = model.by_guid("0BTBFw6f90Nfh9rP1dlXrr")
# All instances of a type (includes subtypes)
walls = model.by_type("IfcWall") # returns list
spaces = model.by_type("IfcSpace")
# Iterate over every entity in the file
for entity in model:
print(entity.id(), entity.is_a())
Relationships
# All entities that reference this element (inverse links)
refs = model.get_inverse(el) # returns set of entity instances
# All entities reachable from this element (deep graph traversal)
graph = model.traverse(el) # returns list, breadth-first
Modifying
# Create a new entity
org = model.create_entity("IfcOrganization", Name="ACME")
# Remove an entity and clean up its relationships
model.remove(el)
# Higher-level removal (cleans containment, placements, etc.)
import ifcopenshell.api
ifcopenshell.api.run("root.remove_product", model, product=el)
Writing
# Write back to a file
model.write("output.ifc")
# Or via ifcpatch (used when the result comes from a recipe)
import ifcpatch
ifcpatch.write(result, "output.ifc")
Schema and header
print(model.schema) # "IFC2X3" or "IFC4"
print(model.header.file_description) # ViewDefinition, ...
print(model.header.file_name.name) # original filename
Entity instances
Each element returned by the methods above is an entity instance
(ifcopenshell.entity_instance). Its attributes are accessed as properties:
wall = model.by_type("IfcWall")[0]
wall.GlobalId # GUID string
wall.Name # element name
wall.is_a() # "IfcWall" — runtime type string
wall.id() # integer entity id (file-local, unstable across extractions)
wall.get_info() # dict of all attribute name → value
Entity ids are not stable — the same physical element will have a different
id after extraction or merging. Always use GlobalId or Name to identify
elements across files.
Relationship to ifcpatch
ifcpatch.execute() takes an ifcopenshell.file as input and returns a new
one as output. The input is never modified in place. ifcpatch.write() is a
thin wrapper around model.write() with some post-processing.
result = ifcpatch.execute({
"input": "input.ifc",
"file": model, # ← ifcopenshell.file
"recipe": "ExtractElements",
"arguments": ["IfcWall"],
})
# result is a new ifcopenshell.file
ifcpatch.write(result, "output.ifc")
Memory model
The entire file is loaded into memory as a C++ object graph (via a Python binding). This means:
- Operations are fast (no re-parsing on each query).
- Large files consume significant RAM.
- The object is not thread-safe — do not share across threads.
- Passing the object to
MergeProjectsas a file path string (instead of the object itself) triggers a segfault in the current version — always pass the live object.