openbim_ifc

Read, edit and write IFC STEP files.

Python bindings for the openbim-ifc Rust crates (ADR 0013). An IfcModel holds entities, each a type name plus positional attributes. Attribute values are the frozen dataclasses in openbim_ifc.values, which keep every distinction IFC makes -- $ from *, .U. from .F., integer from real, and typed wrappers such as IFCLENGTHMEASURE(2.5) from their payload -- so a file read and written back through Python is unchanged.

An Entity view reads and writes attributes by name with plain Python values (wall.Name), and wall.psets maps property sets (openbim_ifc.entity).

>>> import openbim_ifc
>>> model = openbim_ifc.open("model.ifc")  # doctest: +SKIP
>>> walls = model.by_type("IfcWall")  # doctest: +SKIP
def open( path: Union[str, os.PathLike[str]], *, mapped: bool = False, options: Optional[ParseOptions] = None) -> IfcModel:

Read a STEP (.ifc) file from disk: IfcModel.open().

def convert_unit(value: float, from_unit: str, to_unit: str) -> float:

Convert value between two units named as text (#469): an SI unit with its prefix written before it ("METRE", "MILLIMETRE", "MILLI METRE", "SQUARE_MILLIMETRE", "KILOGRAM") or a named unit of IFC4 Table 673 with exact factors ("inch", "foot", "square foot", "gallon US", "pound", "degree" ...).

Raises type-mismatch for units of different dimensions, invalid-value for text that names no unit, and unsupported for a unit with an offset (degree Fahrenheit, #110).

def format_length( value: float, unit: str, *, style: str = 'decimal', places: Optional[int] = None, display_unit: Optional[str] = None, suppress_zero_inches: bool = False) -> str:

Write value, a length in unit, as text (#469).

style is "decimal" (in display_unit, default unit, with places digits, default 2), "feet-inches" (5' - 6 1/2", rounded to 1/places of an inch, default 8; with suppress_zero_inches a whole foot is 5') or "inches" (66 1/2").

def new_guid() -> str:

A new random GlobalId: an RFC 9562 version-4 UUID from the operating system's generator, in IFC's 22-character form.

def name_based_guid(*parts: str) -> str:

The GlobalId named by parts (RFC 9562 version 8): the same parts give the same GlobalId in every binding and release, for a reproducible export. Choose parts unique together, such as a tool name and a stable key.

def canonical_selector(query: str) -> str:

Selector query in its canonical form (#464): spacing, quoting and aliases normalised, so two spellings of one query compare equal. Raises invalid-selector (with span) when it does not parse against grammar SELECTOR_GRAMMAR_VERSION.

SELECTOR_GRAMMAR_VERSION = '1.0'
SelectedValue = typing.Any
@dataclass(frozen=True)
class DuplicateGlobalId:

A GlobalId several entities carry, which the schema forbids: ids are its holders in file order (IfcModel.duplicate_global_ids()).

DuplicateGlobalId(global_id: str, ids: Tuple[int, ...])
global_id: str
ids: Tuple[int, ...]
class IfcError(builtins.Exception):

A failed IFC operation. code is stable across bindings: parse, write, missing-entity, invalid-value, out-of-range, unsupported-schema, io, unsupported-profile, feature-disabled, invalid-model, missing-reference, budget-exceeded, unsupported, wrong-entity-type, template-violation, missing-property, catalog-not-loaded (JavaScript only: this package embeds the catalog), unknown-attribute, derived-attribute, missing-attribute, still-referenced, type-mismatch, ambiguous-value, invalid-selector (with span, the byte range in the UTF-8 query), inverse-attribute, express-mismatch, invalid-express, history-empty, history-stale.

class IfcModel(openbim_ifc.entity.ModelAccess):

An IFC model: entities keyed by their #id, in file order.

Failures raise openbim_ifc.IfcError, whose code is one of parse, write, missing-entity, invalid-value, out-of-range, unsupported-schema, io, unsupported-profile, feature-disabled, or, from a domain view, invalid-model, missing-reference, budget-exceeded, unsupported or wrong-entity-type, or, from a property edit, template-violation or missing-property, or, from an attribute named rather than numbered, unknown-attribute or derived-attribute, or, from a plain value written by name, type-mismatch or ambiguous-value, or, from authoring, missing-attribute or still-referenced, or, from validation with EXPRESS rules, express-mismatch or invalid-express.

A parsed model decodes each entity the first time it is read: parsing checks every record but builds nothing, so opening a large file is fast and memory holds the file plus what has been touched.

model[id], by_id, by_type, iter(model) and id in model give openbim_ifc.Entity views (openbim_ifc.entity).

IfcModel()

An empty model.

@classmethod
def parse( cls, data: bytes, *, options: Optional[ParseOptions] = None) -> IfcModel:

Parse a STEP (.ifc) file from its bytes.

An ifcZIP archive (.ifczip) is recognized by its ZIP signature and its one model entry read, STEP or ifcXML in either layout, within a decompression budget: an archive with no model or several raises parse, an encrypted entry or a compression other than Stored and Deflate unsupported, and one that inflates past the budget budget-exceeded.

options relaxes the strict read, e.g. ParseOptions.lenient() skips damaged records; each one skipped is listed by diagnostics().

@classmethod
def parse_ifcxml( cls, data: bytes, *, xsd_profile: Optional[str] = None) -> IfcModel:

Parse an ifcXML document.

Without xsd_profile it reads this library's lossless layout; with "IFC4" or "IFC4X3_ADD2" it reads the buildingSMART XSD layout of that release.

@classmethod
def open( cls, path: Union[str, os.PathLike[str]], *, mapped: bool = False, options: Optional[ParseOptions] = None) -> IfcModel:

Read a STEP (.ifc) file, or an ifcZIP archive as parse() reads one, from disk.

Cheaper than IfcModel.parse(Path(path).read_bytes()): the file is read once, straight into the model, with the GIL released.

mapped=True memory-maps the file instead of reading it: nothing is copied, and the pages belong to the OS page cache. The model keeps decoding from the file while it is alive, so the file must not be modified or truncated until the model is gone -- a truncated file can terminate the interpreter (SIGBUS), and a rewritten one makes reads fail or return other content. Use it only for files that stay put, such as a read-only export.

options is as for parse().

Raises openbim_ifc.IfcError with code == "io" when the file cannot be read.

def write(self) -> bytes:

Serialize as STEP bytes.

def write_ifcxml(self, *, xsd_profile: Optional[str] = None) -> bytes:

Serialize as ifcXML bytes, in the layout parse_ifcxml reads.

An XSD-layout write needs the header to declare the profile's schema and refuses with write what the layout cannot carry.

def write_ifczip(self, *, inner: str = 'step', xsd_profile: Optional[str] = None) -> bytes:

Serialize as ifcZIP bytes: one Deflate entry holding STEP (model.ifc), or, with inner="ifcxml", ifcXML (model.ifcXML) in the layout xsd_profile names, as for write_ifcxml(). parse() and open() read it back.

Raises invalid-value for another inner, or an xsd_profile with STEP inside.

header: Header

The STEP file header: description, name, time stamp, author, ...

def set_header(self, header: Header) -> None:

Replace the STEP file header, e.g. with dataclasses.replace.

def validate( self, max_findings: Optional[int] = None) -> ValidationReport:

Validate against the schema the header declares.

Findings are sorted by severity, rule, entity and slot. max_findings caps the report (default 10,000) and sets truncated when reached.

def validate_express( self, express: str, max_findings: Optional[int] = None) -> ValidationReport:

Validate with the EXPRESS rules of the declared release.

express is the text of that release's .exp file, which the caller supplies: the schemas are CC BY-ND and not bundled. Every WHERE, type and global rule is evaluated, and INVERSE cardinality is checked; indeterminate counts the rules that evaluated to UNKNOWN. The text is parsed on every call. Raises express-mismatch for text that declares another schema than the model's or disagrees with the release's tables, and invalid-express for text that does not parse. max_findings is as for validate().

def unreachable_products(self) -> List[UnreachableProduct]:

Products no viewer will draw, with a stable reason, in id order.

def property_sets(self, id: int) -> List[PropertySet]:

The property sets, quantity sets and predefined property sets of object id: its own first, then those its type object holds, an occurrence property overriding an inherited one of the same name.

Values keep their declared IFC type, e.g. Typed("IFCLENGTHMEASURE", Real(0.2)). Resolved against the release the header declares (IFC2X3, IFC4 or IFC4X3).

def property_sets_many( self, ids: Optional[Iterable[int]] = None) -> List[openbim_ifc.domains.ObjectPropertySets]:

property_sets() of each of ids, in that order, or, with None, of every object definition (IfcObjectDefinition and its subtypes) in file order, in one pass.

The file's property relationships are validated once for the whole call rather than once per object, so resolving every object is linear in the model. Each ObjectPropertySets holds exactly what property_sets() returns for its object, or, in refusal, the code and message it raises; only a refusal of the whole model (unsupported-schema) raises. No index outlives the call, so a call after an edit sees the edit.

def resolve_unit( self, measure_type: str, unit: Optional[int] = None) -> ResolvedUnit:

The effective unit of a measure_type value ("IFCAREAMEASURE"): unit when given (a property's stated unit), otherwise the project default, resolved exactly to SI.

def set_properties( self, edits: Iterable[PropertyEdit]) -> PropertyEditResult:

Write and remove property and quantity values as one checked transaction: every edit, in order, or none.

A refused batch raises openbim_ifc.IfcError and leaves the model unchanged. A write's value is the read side's Property.value. A value an occurrence inherits from its type is overridden on the occurrence, never changed on the shared type set; pass the type object's id to change that. Values are checked against the declared release (IFC2X3, IFC4 or IFC4X3) and, for a Pset_/Qto_ set, its PSD/QTO catalog template.

def set_property( self, object: int, set: str, name: str, value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], *, set_type: Optional[str] = None) -> int:

Write one value (set_properties() with one edit); returns the id of the entity holding it.

def remove_property(self, object: int, set: str, name: str) -> None:

Remove one property from object's own set (set_properties() with one edit).

def spatial_tree(self) -> SpatialTree:

The spatial containment tree: every container with its parent, sub-containers and contained elements.

def classifications(self, id: int) -> List[Classification]:

The classifications of object id: its own, then its type's.

def material(self, id: int) -> Optional[MaterialAssignment]:

The material association of object id, its own or its type's, or None.

def product_placements( self, ids: Optional[Iterable[int]] = None) -> List[ProductPlacement]:

Each product's world placement (a column-major 4x4 in metres) and the Body representation a viewer draws, for ids or every product with a shape. A product that cannot be placed carries a typed refusal; the call raises only unsupported-schema or feature-disabled.

def product_geometry( self, ids: Optional[Iterable[int]] = None, encoding: str = 'json') -> List[ProductGeometry]:

Each product's Body as Axiolid's neutral geometry graph, exact, for ids or every product with a shape, in Axiolid's versioned wire format: {"format": "axiolid-geometry-graph", "version": "1.0", "graph": {"nodes": [...], "roots": [...]}} (the lowest version the content needs, "1.0" to "1.4"), in world coordinates, metres. encoding "json" gives the payload as a str, "cbor" as bytes; any other raises ValueError. A product that cannot be lowered carries a typed refusal; the call raises only unsupported-schema or feature-disabled.

def product_meshes( self, ids: Optional[Iterable[int]] = None, representation: str = 'Body') -> List[ProductMesh]:

Each product's Body as triangles from the reference backend, for ids or every product with a shape; a product that cannot be meshed carries a typed refusal. representation meshes another one instead (#458): "Surface", or any name product_curves() takes; its curves are left to that call, and closure says "solid" or "surface". Only a Body mesh carries a colour. Needs a wheel built with the mesh feature; the published wheel raises feature-disabled.

def product_curves( self, ids: Optional[Iterable[int]] = None, representation: str = 'Plan') -> List[ProductCurves]:

Each product's curves as polylines from the reference backend (#458), for ids or every product with a shape. representation is "Plan" (the best drawing curves: Plan, Annotation, FootPrint, then Axis, preferring a PLAN_VIEW context), or "Axis", "FootPrint", "Annotation", "Body" or "Surface"; another name raises invalid-value. A product whose curves cannot be compiled carries a typed refusal: a curve the reference compiler has no certified polyline for (an implicit curve, an offset of an offset) is unsupported; trimmed, composite, offset and intrinsic curves compile (#506). Text literals and annotation fill areas beside the curves (a dimension's value) are listed in skipped, not refused (#512). Needs a wheel built with the mesh feature.

def systems(self) -> Systems:

Every system with its members and served structures, and the memberships the reader could not honour.

def cost(self) -> Cost:

Every cost schedule and cost item; values as authored, typed.

def georeferencing(self) -> List[MapConversion]:

Every coordinate operation resolved with the project length unit; empty when the model has none. IFC2X3 is read from its ePSet_MapConversion and ePSet_ProjectedCRS property sets.

schema: Optional[str]

The first FILE_SCHEMA token, e.g. "IFC4", or None.

def diagnostics(self) -> List[str]:

Non-fatal problems found while reading.

def ids(self) -> List[int]:

Every entity id, in file order.

def ids_of_type(self, type_name: str) -> List[int]:

Ids of every entity of exactly type_name (case-insensitive).

def ids_of_type_including_subtypes(self, type_name: str) -> List[int]:

Ids of type_name or any subtype, per the file's schema.

def select_ids( self, query: str, base: Optional[Iterable[Union[int, Entity]]] = None) -> List[int]:

The ids selector query selects, ascending (#464).

"IfcWall, Pset_WallCommon.IsExternal=TRUE + IfcSlab": class facets (subtypes included) add entities, ! removes them, attribute, property and type=, material=, classification=, location= and group= facets filter; , chains facets and + unites lists. With base, facets select from those entities alone. The grammar and its differences from IfcOpenShell's selector are documented in the guide.

Raises invalid-selector (with span, the byte range in the UTF-8 query) for a query that does not parse or names a class or attribute the file's release does not declare.

def select( self, query: str, base: Optional[Iterable[Union[int, Entity]]] = None) -> List[Entity]:

select_ids() as Entity views.

def get_value(self, entity: Union[int, Entity], path: str) -> Any:

The value path reads from entity (#464): "Name", "type.Name", "Pset_WallCommon.FireRating", "materials.Name", "storey.Name", "occurrences.count".

Plain Python values as Entity attributes read them: a reference is an Entity, $ is None, several values a tuple, and a property set a read-only mapping of its properties.

def set_value( self, entity: Union[int, Entity], path: str, value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed, Entity, NoneType, bool, int, float, str, Tuple[ForwardRef('Assignable'), ...], list[ForwardRef('Assignable')]]) -> None:

Write value at path of entity (#464), as one checked transaction: an attribute ("Name", "type.Name") coerced as set_attribute_by_name_plain() coerces it, or a property ("Pset_WallCommon.FireRating") from a typed value, or a plain one when the property already states its type. A refused write changes nothing; a path naming no single value raises invalid-value.

def export_table( self, query: str, columns: Sequence[str], *, format: str = 'csv', key: Optional[str] = None, null: str = '') -> bytes:

The entities selector query selects as a table (#474): format "csv", "tsv" or "xlsx", the key column first ("GlobalId", or "id" with key="id"), then one column per value path of columns ("Name", "type.Name", "Pset_WallCommon.FireRating"), each cell the value the path reads as text and NULL as null.

Raises invalid-selector for a query or path that does not parse, invalid-value for an unknown format or key, and wrong-entity-type for an entity without a GlobalId in a table keyed by it.

def import_table( self, data: Union[bytes, str], *, format: str = 'csv', key: Optional[str] = None, null: str = '', dry_run: bool = False) -> TableImport:

Apply a table (bytes, or str for CSV and TSV) back to the model by its key column (#474), as one checked transaction: every other cell is written by its header's value path, typed by the attribute's declared type or the property's stated one, and a cell that reads what the model holds changes nothing, so an exported table imported unchanged is a no-op.

The answer lists every change and every refusal by row and column; any refusal means nothing was written, as does dry_run. Raises only for a call that cannot start: an unknown format or key, bytes that are no table of the format.

def id_by_guid(self, global_id: str) -> Optional[int]:

The id of the entity whose GlobalId is global_id, or None. The first lookup indexes every GlobalId once; later ones reuse it until the model changes. Raises invalid-value for text that is not a GlobalId and invalid-model when several entities carry it. by_guid() returns the Entity.

def duplicate_global_ids(self) -> List[DuplicateGlobalId]:

Every GlobalId several entities carry, with its holders; empty for a conformant file.

def type_object(self, id: int) -> Optional[int]:

The type object of occurrence id (IfcRelDefinesByType), or None. Raises wrong-entity-type for a non-IfcObject and invalid-model when the file states two types.

def occurrences_of(self, id: int) -> List[int]:

Every object type object id types, in file order.

def openings_of(self, id: int) -> List[int]:

Every opening voiding element id (IfcRelVoidsElement).

def fillings_of(self, id: int) -> List[int]:

Every element filling opening id (IfcRelFillsElement).

def voided_element_of(self, id: int) -> Optional[int]:

The element opening id voids, or None.

def type_of(self, id: int) -> str:

The upper-case type name of entity id.

def attributes( self, id: int) -> List[Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]]:

Every attribute of entity id, in declaration order.

def attribute( self, id: int, index: int) -> Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]:

Attribute index of entity id; Null past the end.

def set_attribute( self, id: int, index: int, value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]) -> Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]:

Set attribute index of entity id; returns the old value.

def attribute_names(self, id: int) -> List[AttributeInfo]:

Every explicit attribute of entity id in slot order, inherited first, as the release the header declares defines them. INVERSE attributes hold no slot and are listed by inverse_attribute_names().

def attribute_by_name( self, id: int, name: str) -> Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]:

Attribute name of entity id, matched case-insensitively ("Name") and resolved against the declared release; Null when the record stops before its slot.

An INVERSE name ("IsDefinedBy", #462) reads the entities referencing id through the release's FOR clause: a List of Ref for a SET or BAG -- SET [0:1] included, so ContainedInStructure is a list of zero or one -- in ascending id order; a Ref or Null for a single-valued inverse (VoidsElements), which two referrers refuse with invalid-model.

def inverse_attribute_names(self, id: int) -> List[InverseAttributeInfo]:

Every INVERSE attribute of entity id, inherited ones first, with its FOR clause and bounds, as the declared release defines them.

def inverse_references(self, id: int) -> List[InverseReference]:

Every reference to entity id: the referencing entity and the attribute index holding the reference, in ascending order, one per entity and attribute. IfcOpenShell's file.get_inverse(entity, allow_duplicate=True, with_attribute_indices=True).

def total_inverses(self, id: int) -> int:

How many distinct entities reference entity id, through any attribute. IfcOpenShell's file.get_total_inverses.

def set_attribute_by_name( self, id: int, name: str, value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]) -> Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]:

Set attribute name of entity id; returns the old value. A derived attribute raises derived-attribute, an INVERSE one inverse-attribute, an unknown name unknown-attribute, and a refused write changes nothing.

def set_attribute_by_name_plain( self, id: int, name: str, value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed, Entity, NoneType, bool, int, float, str, Tuple[ForwardRef('Assignable'), ...], list[ForwardRef('Assignable')]]) -> Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]:

Set attribute name of entity id from a plain Python value, coerced against the attribute's declared type in the declared release; returns the old tagged value. wall.Name = "x" calls this.

A str becomes a label (written bare, 'x') or the enumeration item it names in any case (.STANDARD.); an int an INTEGER or a REAL as declared; a float a REAL; a bool a BOOLEAN or LOGICAL; a list or tuple an aggregate, element by element; an openbim_ifc.Entity a reference, checked to exist and to be of an accepted type; None $. In a SELECT the one member that takes the value is written as its typed parameter (IFCDESCRIPTIVEMEASURE('by layer')). A tagged value (Text, Enum, Typed, ...) is written exactly as given.

Raises type-mismatch for a value that does not fit, ambiguous-value when several SELECT members would take it (the message names them; pass a Typed value instead), and otherwise as set_attribute_by_name(). A refused write changes nothing.

def add( self, type_name: str, attributes: Iterable[Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]]) -> int:

Append an entity; returns its new id.

def remove(self, id: int) -> None:

Remove entity id, leaving references to it dangling.

Deprecated since version 0.9: A file with dangling references parses and is wrong. Use remove_with_relationships() for one entity, or remove_product() for a product with what it solely owns. It keeps working, with a DeprecationWarning.

def author( self, ops: Iterable[AuthorOp]) -> AuthoringResult:

Apply authoring operations as one checked transaction against the release the header declares: every operation, in order, or none.

A refused batch raises openbim_ifc.IfcError and leaves the model unchanged. An operation names the entity an earlier one produced by openbim_ifc.handle(); result.ids holds, per operation, the id the produced entity received.

def create_entity( self, type_name: str, attributes: Optional[Mapping[str, Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]]] = None) -> int:

Create one entity of type_name from named attributes, checked against the declared release (author() with one AuthorOp.create()); returns its id.

def remove_with_relationships(self, id: int) -> None:

Remove entity id with the relationships that reference it, leaving nothing dangling (author() with one AuthorOp.remove()). Raises still-referenced while an entity other than a relationship needs it.

def set_history_limit(self, limit: int) -> None:

Keep at most limit undo entries; 0 (the default) turns history off and drops what is held. While it is on, every method that changes the model is one entry (author() is one entry for its whole batch).

def history(self) -> HistoryState:

The history bound and how many entries each direction holds.

def undo(self) -> HistoryChange:

Restore the model to the state before the last change: entities under their ids and at their file positions, the header included. Undoing a creation frees its id again.

Raises history-empty with nothing to undo (also while history is off) and history-stale when the model changed outside the history; the model is unchanged then.

def redo(self) -> HistoryChange:

Reverse the last undo(). Raises history-empty with nothing to redo and history-stale as undo() does.

def clear_history(self) -> None:

Drop every undo and redo entry, keeping the limit.

def remove_product( self, id: int, *, rebase_placements: bool = False, untype_occurrences: bool = False, dry_run: bool = False) -> RemovalReport:

Remove product (or type object) id with everything it solely owns -- its placement, representation, own property and quantity sets, material usage, openings and ports, and the relationships left without an end -- as one checked transaction. Shared data stays: a property set another object uses, a type's representation maps, a style used elsewhere. The report says what went and what stayed, and why; with dry_run nothing changes.

Raises still-referenced while other placements are relative to its placement (rebase_placements re-bases them, composing the transforms so nothing moves) or while a type object types objects (untype_occurrences unassigns the type), wrong-entity-type for an entity that is neither an IfcProduct nor an IfcTypeObject, and unsupported for a placement that cannot be re-based.

def purge( self, classes: Sequence[str] = (), *, include_roots: bool = False, include_owner_history: bool = False, dry_run: bool = False) -> RemovalReport:

Remove unreferenced entities as one checked transaction; with dry_run, only report.

Without classes: every resource entity no IfcRoot reaches (nor annotates something reached, as a styled item does). With classes (subtypes included, any case): the entities of those classes nothing references; an IfcRoot among them only with include_roots. The owner history with its actors stays unless include_owner_history. Raises unsupported-schema for a class the release does not declare.

def remove_representation( self, id: int, *, dry_run: bool = False) -> RemovalReport:

Remove shape representation id with what only it uses, as one checked transaction: it is taken off its product definition shape (which goes when left empty), representation map or shape aspects, then removed with its items down to what nothing else uses. Shared items, profiles, points and styles stay, and the report says why; with dry_run nothing changes.

Raises still-referenced for a representation map an IfcMappedItem still maps, and wrong-entity-type for an entity that is not an IfcShapeModel.

def copy_product( self, id: int, *, offset: Optional[Tuple[float, float, float]] = None, placement: Optional[int] = None, openings: bool = True, fillings: bool = True, container: bool = True, aggregate: bool = True, dry_run: bool = False) -> CopyReport:

Copy product (or type object) id with everything it solely owns, as one checked transaction (#479): what remove_product() would remove with it is copied, what it would keep is shared.

Copied, each with a new GlobalId: its placement (relative to the same parent; moved by offset, in the parent's frame, or replaced by placement), its representation (items and profiles copied, the context, styles and type geometry shared), its own property and quantity sets, its material usage, its ports and, with openings and fillings, its openings and the doors and windows filling them. Shared, the copy joining the relationship: its type, shared property sets, material definitions, classification and, with container and aggregate, its spatial container and its whole. The report maps every original to its copy; with dry_run nothing changes.

Raises wrong-entity-type for neither an IfcProduct nor an IfcTypeObject, invalid-value for both offset and placement, and unsupported for an offset onto a placement that is not a local placement with a Cartesian location, or a moved copy whose openings or fillings are not placed relative to it.

def append( self, source: IfcModel, ids: Iterable[int], *, global_ids: str = 'keep', reuse: Iterable[str] = ('units', 'contexts', 'owner_history', 'materials', 'styles'), dry_run: bool = False) -> CopyReport:

Copy entities ids of source into this model with what belongs to them, as one checked transaction (#479): what they reference, their property sets, type, material and classification, their openings, fillings and ports, and what attaches to their geometry. Units, contexts, the owner history, materials and styles equal to this model's are reused, for the kinds reuse names. Relationships to objects not copied (a spatial container) are skipped and reported; relate the copies afterwards.

global_ids: keep (a GlobalId this model holds is refused), merge (an IfcRoot this model holds by GlobalId and type is reused, its relationships joined), regenerate or regenerate-colliding.

Raises unsupported when the models' length or plane angle units differ (convert one with convert_length_unit() first), unsupported-schema for an entity this model's release cannot hold (a type or attribute it lacks, a constant it does not know), invalid-value for a kept GlobalId this model holds. With dry_run nothing changes.

def convert_unit_value(self, value: float, from_unit: int, to_unit: int) -> float:

Convert value from unit entity from_unit to unit entity to_unit of this model (an IfcSIUnit, IfcConversionBasedUnit or IfcDerivedUnit), exactly: prefixes convert by a power of ten, conversion-based units through their factor, derived units by their exponents.

Raises type-mismatch for units of different dimensions, unsupported for a monetary or context-dependent unit or one with an offset (#110), and missing-entity for an id the model lacks.

def convert_length_unit( self, target: str, *, area_and_volume: bool = True, remove_replaced_units: bool = True, dry_run: bool = False) -> LengthUnitReport:

Convert the model's length unit to target (an SI METRE with any prefix, such as "MILLIMETRE", or "inch", "foot", "yard", "mile", "US survey foot"), rescaling every length, area and volume value -- geometry, placements, quantities and property values -- as one checked transaction.

Which values are lengths is read from the release's measure types; values with a unit of their own keep it, and curve parameters that are angles, knots or multiples stay. With area_and_volume the area and volume units become the square and cube of the new length unit; with dry_run nothing changes and the report says what would.

Raises unsupported naming every value the conversion cannot carry (a p-curve off a plane, a polynomial curve, a parameter on an undefined parameter space), invalid-value for a target that is not a length unit, invalid-model when the project length unit cannot be resolved and unsupported-schema for a release other than IFC2X3, IFC4 or IFC4X3. A refusal leaves the model unchanged.

def dangling_references(self) -> List[Tuple[int, int]]:

Every (from, to) pair where to does not exist.

class Entity:

One entity of a model, read and written by attribute name.

wall.Name reads attribute Name as a plain value (see PlainValue) and wall.Name = "W1" writes it, coerced against the declared type (Text("W1") writes exactly), both through the model's attribute_by_name/set_attribute_by_name, so names match ASCII case-insensitively against the declared release. An unknown name raises AttributeError, chained from the unknown-attribute openbim_ifc.IfcError. An INVERSE name reads too (#462): wall.IsDefinedBy is a tuple of the relationship Entity views, wall.ContainedInStructure (SET [0:1]) a tuple of zero or one, and a single-valued inverse such as opening.VoidsElements an Entity or None; writing one raises inverse-attribute. The view holds no data: every read sees the model as it is then. Two views are equal when they name the same id of the same model.

Entity(model: IfcModel, id: int)

A view of entity id; IfcModel.by_id() checks it exists.

id: int

The entity's #id.

model: IfcModel

The model the entity belongs to.

type: str

The upper-case type name, e.g. "IFCWALL".

def is_a(self, type_name: str) -> bool:

Whether the entity is a type_name or a subtype of it, per the file's schema; case-insensitive. A name the schema lacks is False.

def get( self, name: str) -> Union[NoneType, bool, int, float, str, Binary, Entity, Tuple[ForwardRef('PlainValue'), ...]]:

Attribute name as a plain value; entity.Name with the precise type. Raises openbim_ifc.IfcError as IfcModel.attribute_by_name() does.

def raw( self, name: str) -> Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]:

Attribute name as the exact tagged value, e.g. Typed("IFCLABEL", Text("W1")) or Derived().

def set( self, name: str, value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed, Entity, NoneType, bool, int, float, str, Tuple[ForwardRef('Assignable'), ...], list[ForwardRef('Assignable')]]) -> Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]:

Write attribute name (entity.Name = value); returns the old tagged value. A plain value is coerced against the declared type (openbim_ifc.IfcModel.set_attribute_by_name_plain()); a tagged one is written as given. A refused write changes nothing.

def attribute_names(self) -> list[AttributeInfo]:

Every explicit attribute, in slot order, as IfcModel.attribute_names() lists them.

def inverse_attribute_names(self) -> list[InverseAttributeInfo]:

Every INVERSE attribute, as IfcModel.inverse_attribute_names() lists them.

def inverse_references(self) -> list[typing.Tuple[Entity, int]]:

Every entity referencing this one, with the attribute index holding the reference: IfcModel.inverse_references() as (Entity, index) pairs.

def total_inverses(self) -> int:

How many distinct entities reference this one: IfcModel.total_inverses().

def property_sets(self) -> list[PropertySet]:

The exact records IfcModel.property_sets() returns.

psets: Mapping[str, Mapping[str, Union[NoneType, bool, int, float, str, Binary, Entity, Tuple[Union[NoneType, bool, int, float, str, Binary, Entity, Tuple[ForwardRef('PlainValue'), ...]], ...], Property, Mapping[str, Union[NoneType, bool, int, float, str, Binary, Entity, Tuple[Union[NoneType, bool, int, float, str, Binary, Entity, Tuple[ForwardRef('PlainValue'), ...]], ...], Property, Mapping[str, ForwardRef('PropertyValue')]]]]]]

Property sets and predefined property sets by name, each a read-only mapping of property name to PropertyValue.

The object's own values and those its type object holds, an occurrence value overriding an inherited one, as IfcModel.property_sets() resolves them; quantity sets are in qtos. A snapshot: read it again after a write. Write with set_property().

qtos: Mapping[str, Mapping[str, Union[NoneType, bool, int, float, str, Binary, Entity, Tuple[Union[NoneType, bool, int, float, str, Binary, Entity, Tuple[ForwardRef('PlainValue'), ...]], ...], Property, Mapping[str, Union[NoneType, bool, int, float, str, Binary, Entity, Tuple[Union[NoneType, bool, int, float, str, Binary, Entity, Tuple[ForwardRef('PlainValue'), ...]], ...], Property, Mapping[str, ForwardRef('PropertyValue')]]]]]]

Quantity sets (IfcElementQuantity) by name, as psets.

def set_property( self, set: str, name: str, value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], *, set_type: Optional[str] = None) -> int:

Write one property or quantity value: IfcModel.set_property() on this entity. value is exact, e.g. Typed("IFCLABEL", Text("F60")). Returns the id of the entity holding it.

def remove_property(self, set: str, name: str) -> None:

Remove one property from the entity's own set: IfcModel.remove_property().

PlainValue = typing.Union[NoneType, bool, int, float, str, Binary, ForwardRef('Entity'), typing.Tuple[ForwardRef('PlainValue'), ...]]
PropertyValue = typing.Union[NoneType, bool, int, float, str, Binary, ForwardRef('Entity'), typing.Tuple[ForwardRef('PlainValue'), ...], Property, typing.Mapping[str, ForwardRef('PropertyValue')]]
Assignable = typing.Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed, ForwardRef('Entity'), NoneType, bool, int, float, str, typing.Tuple[ForwardRef('Assignable'), ...], list['Assignable']]
@dataclass(frozen=True)
class AttributeInfo:

One explicit attribute of an entity, from IfcModel.attribute_names(), as the release the header declares defines it.

name is the schema's spelling (GlobalId); index its slot, the index of IfcModel.attribute(). type_name is the declared type, or an aggregate's element type. A derived attribute is written * and IfcModel.set_attribute_by_name() refuses it. declared_by names the entity that introduces it (IfcRoot).

AttributeInfo( name: str, index: int, type_name: str, optional: bool, aggregate: bool, derived: bool, declared_by: str)
name: str
index: int
type_name: str
optional: bool
aggregate: bool
derived: bool
declared_by: str
@dataclass(frozen=True)
class InverseAttributeInfo:

One INVERSE attribute of an entity, from IfcModel.inverse_attribute_names() (#462), as the release the header declares defines it: name : SET [lower:upper] OF entity FOR for_attribute.

entity is the referencing type (its subtypes count too) and for_attribute its attribute that references this entity, directly or as an aggregate member. An aggregate inverse (a SET or BAG, SET [0:1] included) reads as a List; a single-valued one as a Ref or Null. upper is None for ?; declared_by names the entity that introduces it (IfcObject).

InverseAttributeInfo( name: str, entity: str, for_attribute: str, aggregate: bool, lower: int, upper: Optional[int], declared_by: str)
name: str
entity: str
for_attribute: str
aggregate: bool
lower: int
upper: Optional[int]
declared_by: str
@dataclass(frozen=True)
class InverseReference:

One reference to an entity, from IfcModel.inverse_references() (#462): entity id holds it in attribute index, directly or inside an aggregate.

InverseReference(id: int, index: int)
id: int
index: int
@dataclass(frozen=True)
class AuthorOp:

One operation of IfcModel.author(), built with the class methods below.

Ids are entity ids or handle() values. attributes map attribute names (any case) to openbim_ifc.values values. A builder writes the owner_history it is given on every record it creates; none is invented, and IFC2X3, which requires one, refuses a record without.

AuthorOp(op: str, fields: Tuple[Tuple[str, Any], ...] = ())
op: str
fields: Tuple[Tuple[str, Any], ...] = ()
@classmethod
def create( cls, type_name: str, attributes: Optional[Mapping[str, Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]]] = None) -> AuthorOp:

One entity of type_name from named attributes; an IfcRoot without a GlobalId gets one.

@classmethod
def edit( cls, entity: int, attributes: Mapping[str, Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]]) -> AuthorOp:

Replace named attributes; the whole entity is checked again.

@classmethod
def remove(cls, entity: int) -> AuthorOp:

Remove an entity with the relationships that reference it.

@classmethod
def project( cls, attributes: Optional[Mapping[str, Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]]] = None, *, owner_history: Optional[int] = None) -> AuthorOp:

The model's one IfcProject.

@classmethod
def spatial( cls, type_name: str, parent: int, attributes: Optional[Mapping[str, Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]]] = None, *, placement: Optional[int] = None, owner_history: Optional[int] = None) -> AuthorOp:

A spatial element aggregated under parent (IfcRelAggregates).

@classmethod
def product( cls, type_name: str, attributes: Optional[Mapping[str, Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]]] = None, *, container: Optional[int] = None, placement: Optional[int] = None, type_object: Optional[int] = None, owner_history: Optional[int] = None) -> AuthorOp:

A product, contained in container (IfcRelContainedInSpatialStructure) and typed by type_object (IfcRelDefinesByType).

@classmethod
def type_object( cls, type_name: str, attributes: Optional[Mapping[str, Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]]] = None, *, owner_history: Optional[int] = None) -> AuthorOp:

A type object (IfcWallType, ...).

@classmethod
def assign_type( cls, type_object: int, objects: Sequence[int], *, owner_history: Optional[int] = None, map_representations: bool = False, mapping_target: Optional[int] = None, material_usage: bool = False, layer_set_direction: Optional[str] = None, predefined_type: Optional[str] = None, replace: bool = False) -> AuthorOp:

IfcRelDefinesByType; an object already typed is refused unless replace.

When the type already has an IfcRelDefinesByType the objects join its RelatedObjects and the produced id is that relationship's; owner_history applies only to a relationship that is created (#534).

With map_representations the type's RepresentationMaps are mapped onto each object (IfcMappedItem through mapping_target or an identity operator); with material_usage a layer or profile set usage is derived from the type's set (layer_set_direction "AXIS1".."AXIS3" overrides the class default); predefined_type is "ignore" (default), "validate" or "sync". replace unassigns the previous type and removes what it propagated (#480).

@classmethod
def contain( cls, structure: int, elements: Sequence[int], *, owner_history: Optional[int] = None, replace: bool = False) -> AuthorOp:

IfcRelContainedInSpatialStructure; an element already contained is refused unless replace, which moves it out of its previous container.

@classmethod
def aggregate( cls, parent: int, parts: Sequence[int], *, owner_history: Optional[int] = None, replace: bool = False) -> AuthorOp:

IfcRelAggregates; a part already aggregated is refused unless replace, which moves it out of its previous whole.

@classmethod
def placement( cls, *, relative_to: Optional[int] = None, location: Optional[Sequence[float]] = None, axis: Optional[Sequence[float]] = None, ref_direction: Optional[Sequence[float]] = None) -> AuthorOp:

An IfcLocalPlacement; axis and ref_direction both or neither.

@classmethod
def owner_history( cls, *, organization: str, application_name: str, application_version: str, application_identifier: str, creation_date: int, person_identification: Optional[str] = None, family_name: Optional[str] = None, given_name: Optional[str] = None, change_action: Optional[str] = None, last_modified_date: Optional[int] = None) -> AuthorOp:

An IfcOwnerHistory with its person, organization and application, through ifc-author.

@classmethod
def shape_representation( cls, context: int, items: Sequence[int], *, identifier: Optional[str] = None, representation_type: Optional[str] = None) -> AuthorOp:

An IfcShapeRepresentation of items in context, unassigned. representation_type is checked against the items by the release's CorrectItemsForType rule, or inferred (the most specific type admitting them all); identifier defaults to the context's ContextIdentifier.

@classmethod
def assign_representation(cls, representation: int, to: int) -> AuthorOp:

Assign a shape representation to a product (its IfcProductDefinitionShape, created when missing) or to a type (as a new IfcRepresentationMap). A representation already used is refused.

@classmethod
def unassign_representation(cls, representation: int, from_: int) -> AuthorOp:

Take a shape representation off a product or type; it stays, unassigned, for the batch to assign elsewhere or remove.

@classmethod
def copy_representation(cls, representation: int) -> AuthorOp:

A copy of a shape representation with copies of its items, sharing its context, styles and mapped type geometry.

@classmethod
def remove_representation(cls, representation: int) -> AuthorOp:

Remove a shape representation with what only it uses.

@classmethod
def copy_product( cls, product: int, *, offset: Optional[Tuple[float, float, float]] = None, placement: Optional[int] = None, openings: bool = True, fillings: bool = True, container: bool = True, aggregate: bool = True) -> AuthorOp:

Copy a product or type with what it solely owns (see IfcModel.copy_product()); produces the copy.

@classmethod
def copy_entity( cls, entity: int, *, copy: Sequence[str] = (), share: Sequence[str] = (), copy_roots: bool = False, copy_definitions: bool = False) -> AuthorOp:

Deep-copy an entity and what it references: classes in copy are copied, classes in share (and entities a UNIQUE clause binds) shared; other IfcRoot entities are shared unless copy_roots, definitions (materials, units, contexts, the owner history) unless copy_definitions; any other resource is copied. Produces the copy.

@dataclass(frozen=True)
class AuthoringResult:

What a committed IfcModel.author() batch did.

ids holds, per operation, the id of the entity it produced, or None for a removal.

AuthoringResult( ids: Tuple[Optional[int], ...], created: Tuple[int, ...], removed: Tuple[int, ...])
ids: Tuple[Optional[int], ...]
created: Tuple[int, ...]
removed: Tuple[int, ...]
@dataclass(frozen=True)
class RemovalReport:

What IfcModel.remove_product() or IfcModel.purge() did, or, for a dry run (applied false), would do. Every list is in id order.

RemovalReport( removed: Tuple[RemovedEntity, ...], kept: Tuple[KeptEntity, ...], detached: Tuple[int, ...], rebased: Tuple[int, ...], applied: bool)
removed: Tuple[RemovedEntity, ...]
kept: Tuple[KeptEntity, ...]
detached: Tuple[int, ...]
rebased: Tuple[int, ...]
applied: bool
@dataclass(frozen=True)
class RemovedEntity:

An entity IfcModel.remove_product() or IfcModel.purge() removed: its id and upper-case type.

RemovedEntity(id: int, type_name: str)
id: int
type_name: str
@dataclass(frozen=True)
class HistoryChange:

What IfcModel.undo() or IfcModel.redo() restored: entities created (absent before, present after), removed and modified, and whether the file header changed.

HistoryChange( created: Tuple[int, ...], removed: Tuple[int, ...], modified: Tuple[int, ...], header: bool)
created: Tuple[int, ...]
removed: Tuple[int, ...]
modified: Tuple[int, ...]
header: bool
@dataclass(frozen=True)
class HistoryState:

How much history IfcModel.history() reports: the bound on undo entries (limit, 0 while history is off) and the entries IfcModel.undo() (undo) and IfcModel.redo() (redo) can step through.

HistoryState(limit: int, undo: int, redo: int)
limit: int
undo: int
redo: int
@dataclass(frozen=True)
class TableChange:

One value IfcModel.import_table() changes (#474).

row and column are one-based, the header being row 1; key is the row's key and path the column's value path. entity is the row's entity and target_entity the one written, which a path such as type.Name finds elsewhere; target is the attribute name or Set.Property written. before and after are cell text.

TableChange( row: int, column: int, key: str, path: str, entity: int, target_entity: int, target: str, before: str, after: str)
row: int
column: int
key: str
path: str
entity: int
target_entity: int
target: str
before: str
after: str
@dataclass(frozen=True)
class TableImport:

What IfcModel.import_table() planned, and whether it wrote it.

Any refusal means nothing was written; applied is false then, for a dry run, and for a table that changes nothing.

TableImport( applied: bool, changes: Tuple[TableChange, ...], refusals: Tuple[TableRefusal, ...])
applied: bool
changes: Tuple[TableChange, ...]
refusals: Tuple[TableRefusal, ...]
@dataclass(frozen=True)
class TableRefusal:

One refused table, row or cell of IfcModel.import_table().

row and column are one-based and None for the whole table or row. code is malformed-table, invalid-header, duplicate-column, no-key-column, ragged-row, empty-key, unknown-key, duplicate-key, ambiguous-key, or the error code of a refused write (type-mismatch, invalid-value, ...). span is the byte range of a header that does not parse.

TableRefusal( row: Optional[int], column: Optional[int], code: str, message: str, span: Optional[Tuple[int, int]])
row: Optional[int]
column: Optional[int]
code: str
message: str
span: Optional[Tuple[int, int]]
@dataclass(frozen=True)
class KeptEntity:

An entity a removal reached and kept.

reason is shared (users still need it), related-object (a type, container or filling: an object of its own), definition (a material, classification reference, unit, context or owner history, which only a purge removes) or protected (a purge skipped it: an IfcRoot or the owner history, unless asked).

KeptEntity(id: int, type_name: str, reason: str, users: Tuple[int, ...])
id: int
type_name: str
reason: str
users: Tuple[int, ...]
@dataclass(frozen=True)
class CopyReport:

What IfcModel.copy_product() or IfcModel.append() did, or, for a dry run (applied false), would do.

copy is the product's copy (None for an append); copied every original with its copy, in creation order; reused (append) the source entities the target already holds; joined the existing relationships and layers the copies joined; skipped the relationships of an original the copies do not get; regenerated (append) the copies given a new GlobalId.

CopyReport( copy: Optional[int], copied: Tuple[CopiedEntity, ...], reused: Tuple[CopiedEntity, ...], joined: Tuple[int, ...], skipped: Tuple[int, ...], regenerated: Tuple[int, ...], applied: bool)
copy: Optional[int]
copied: Tuple[CopiedEntity, ...]
reused: Tuple[CopiedEntity, ...]
joined: Tuple[int, ...]
skipped: Tuple[int, ...]
regenerated: Tuple[int, ...]
applied: bool
@dataclass(frozen=True)
class CopiedEntity:

An original and its copy (or, in CopyReport.reused, the target entity used for it).

CopiedEntity(original: int, copy: int, type_name: str)
original: int
copy: int
type_name: str
@dataclass(frozen=True)
class LengthUnitReport:

What IfcModel.convert_length_unit() did, or, for a dry run (applied false), would do. from_unit and to name the project length unit before and after (MILLI METRE, foot); the factors multiply lengths, areas and volumes (an area or volume factor is None when that unit did not follow).

LengthUnitReport( from_unit: str, to: str, length_factor: float, area_factor: Optional[float], volume_factor: Optional[float], length_unit: Optional[int], area_unit: Optional[int], volume_unit: Optional[int], converted: Tuple[ConvertedValues, ...], kept: Tuple[KeptValues, ...], entities_changed: int, values_converted: int, created: Tuple[int, ...], removed: Tuple[int, ...], applied: bool)
from_unit: str
to: str
length_factor: float
area_factor: Optional[float]
volume_factor: Optional[float]
length_unit: Optional[int]
area_unit: Optional[int]
volume_unit: Optional[int]
converted: Tuple[ConvertedValues, ...]
kept: Tuple[KeptValues, ...]
entities_changed: int
values_converted: int
created: Tuple[int, ...]
removed: Tuple[int, ...]
applied: bool
@dataclass(frozen=True)
class ConvertedValues:

Values of one attribute of one entity type that IfcModel.convert_length_unit() rescaled.

kind is length, area, volume, inverse-length, inverse-area or map-scale; values counts numbers (a point has three), entities the entities holding them.

ConvertedValues( entity_type: str, attribute: str, kind: str, entities: int, values: int)
entity_type: str
attribute: str
kind: str
entities: int
values: int
@dataclass(frozen=True)
class KeptValues:

Length-like values of one attribute left as they are, with the reason: explicit-unit (the value states its own unit), map-unit (a map coordinate in the CRS's MapUnit), unitless-parameter (a curve or surface parameter that is an angle, a knot or a multiple) or unit-not-followed (an area or volume while the project has no such unit or area_and_volume is off).

KeptValues(entity_type: str, attribute: str, reason: str, values: int)
entity_type: str
attribute: str
reason: str
values: int
HANDLE_BASE = 4611686018427387904
def handle(index: int) -> int:

The handle of the entity operation index of an IfcModel.author() batch produces, usable wherever a later operation of the batch takes an id, attribute values included.

@dataclass(frozen=True)
class ParseOptions:

How a STEP read treats damaged input. The defaults are strict.

on_malformed="skip" drops a record that cannot be parsed and reports it in IfcModel.diagnostics() instead of failing the read. check_references reports duplicate ids and references to undefined ids. accept_real_without_point reads 1E-05 as a real.

ParseOptions( on_malformed: str = 'abort', check_references: bool = False, accept_real_without_point: bool = False)
on_malformed: str = 'abort'
check_references: bool = False
accept_real_without_point: bool = False
@classmethod
def strict(cls) -> ParseOptions:

Any malformed record fails the read.

@classmethod
def lenient(cls) -> ParseOptions:

Skip malformed records and accept reals without a point.

@dataclass(frozen=True)
class ValidationReport:

The result of IfcModel.validate() or IfcModel.validate_express().

conformant means no errors and no evaluation errors; unsupported rules do not count against it. truncated means the finding budget was reached, so the counts are lower bounds. indeterminate counts EXPRESS rules that evaluated to UNKNOWN; it is 0 without EXPRESS rules.

ValidationReport( conformant: bool, truncated: bool, errors: int, evaluation_errors: int, warnings: int, unsupported: int, findings: Tuple[ValidationFinding, ...], indeterminate: int = 0)
conformant: bool
truncated: bool
errors: int
evaluation_errors: int
warnings: int
unsupported: int
findings: Tuple[ValidationFinding, ...]
indeterminate: int = 0
@dataclass(frozen=True)
class ValidationFinding:

One finding. entity is None for the file as a whole.

severity is error, evaluation-error, warning, indeterminate or unsupported; rule is the check's stable id.

ValidationFinding( severity: str, rule: str, entity: Optional[int], attribute_index: Optional[int], attribute_name: Optional[str], path: str, message: str)
severity: str
rule: str
entity: Optional[int]
attribute_index: Optional[int]
attribute_name: Optional[str]
path: str
message: str
@dataclass(frozen=True)
class UnreachableProduct:

A product no viewer will draw.

reason is not-contained-in-spatial-structure, no-representation-in-model-context or representation-without-context; found_views lists the target views the geometry sits in instead, for the second reason.

UnreachableProduct(id: int, reason: str, found_views: Tuple[str, ...], message: str)
id: int
reason: str
found_views: Tuple[str, ...]
message: str
@dataclass(frozen=True)
class PropertySet:

A property set, quantity set or predefined property set.

source is occurrence (stated on the object) or type (held by the type object source_id). An inherited property the occurrence overrides is left out.

PropertySet( id: int, global_id: Optional[str], name: str, type_name: str, source: str, source_id: Optional[int], properties: Tuple[Property, ...])
id: int
global_id: Optional[str]
name: str
type_name: str
source: str
source_id: Optional[int]
properties: Tuple[Property, ...]
@dataclass(frozen=True)
class Property:

One property, quantity or predefined-set attribute.

kind is value, enumerated, list, bounded, table, reference or complex. value keeps the declared type: Typed("IFCLENGTHMEASURE", Real(0.2)). unit is the unit the property states; IfcModel.resolve_unit() resolves it, or the project default when it is None.

Property( id: int, name: str, type_name: str, kind: str, value_type: Optional[str], unit: Optional[int], value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], enumeration: Optional[PropertyEnumeration], bounds: Optional[PropertyBounds], table: Optional[PropertyTable], usage: Optional[str], discrimination: Optional[str], quality: Optional[str], members: Tuple[Property, ...])
id: int
name: str
type_name: str
kind: str
value_type: Optional[str]
unit: Optional[int]
enumeration: Optional[PropertyEnumeration]
bounds: Optional[PropertyBounds]
table: Optional[PropertyTable]
usage: Optional[str]
discrimination: Optional[str]
quality: Optional[str]
members: Tuple[Property, ...]
@dataclass(frozen=True)
class PropertyEnumeration:

An IfcPropertyEnumeration: the values an enumerated property permits.

PropertyEnumeration( id: int, name: str, values: Tuple[Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], ...])
id: int
name: str
values: Tuple[Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], ...]
@dataclass(frozen=True)
class PropertyBounds:

An IfcPropertyBoundedValue's values; Null() when unstated.

PropertyBounds( lower: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], upper: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], set_point: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed])
set_point: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]
@dataclass(frozen=True)
class PropertyTable:

An IfcPropertyTableValue.

PropertyTable( rows: Tuple[PropertyTableRow, ...], expression: Optional[str], defining_unit: Optional[int], defined_unit: Optional[int], interpolation: Optional[str])
rows: Tuple[PropertyTableRow, ...]
expression: Optional[str]
defining_unit: Optional[int]
defined_unit: Optional[int]
interpolation: Optional[str]
@dataclass(frozen=True)
class PropertyTableRow:

One row of a PropertyTable.

PropertyTableRow( defining: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], defined: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed])
defining: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]
defined: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]
@dataclass(frozen=True)
class ResolvedUnit:

A measure's effective unit: si = value * scale + offset.

dimensions are the SI exponents (L, M, T, I, Θ, N, J).

ResolvedUnit( unit: Optional[int], from_project: bool, dimensions: Tuple[int, ...], scale: float, offset: float)
unit: Optional[int]
from_project: bool
dimensions: Tuple[int, ...]
scale: float
offset: float
@dataclass(frozen=True)
class PropertyEdit:

One edit for IfcModel.set_properties().

Writes value to property name of set set on object, or, built with removal(), removes it. value is the read side's Property.value: a Typed IfcValue (or Null()), a List of them for an enumerated or list value, a typed measure for a quantity. set_type ("IfcPropertySet" or "IfcElementQuantity") names the entity of a set the edit creates that neither the type object nor the catalog describes.

PropertyEdit( object: int, set: str, name: str, value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed, NoneType] = None, set_type: Optional[str] = None, remove: bool = False)
object: int
set: str
name: str
value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed, NoneType] = None
set_type: Optional[str] = None
remove: bool = False
@classmethod
def removal( cls, object: int, set: str, name: str) -> PropertyEdit:

An edit removing property name from object's own set.

@dataclass(frozen=True)
class PropertyEditResult:

What a committed IfcModel.set_properties() batch did.

properties holds, per edit, the entity holding the property afterwards, or None when the batch leaves none.

PropertyEditResult( properties: Tuple[Optional[int], ...], created: Tuple[int, ...], removed: Tuple[int, ...])
properties: Tuple[Optional[int], ...]
created: Tuple[int, ...]
removed: Tuple[int, ...]
@dataclass(frozen=True)
class SpatialTree:

The containment tree. release is the release containers were classified against (IFC4_ADD2_TC1), or None for one the tree is not verified for.

SpatialTree( release: Optional[str], roots: Tuple[int, ...], nodes: Tuple[SpatialNode, ...], orphans: Tuple[int, ...], dangling: Tuple[SpatialDanglingReference, ...], anomalies: Tuple[SpatialAnomaly, ...])
release: Optional[str]
roots: Tuple[int, ...]
nodes: Tuple[SpatialNode, ...]
orphans: Tuple[int, ...]
dangling: Tuple[SpatialDanglingReference, ...]
anomalies: Tuple[SpatialAnomaly, ...]
@dataclass(frozen=True)
class SpatialNode:

A spatial container. kind is project, site, building, storey, space or other; elements are contained, referenced only referenced.

SpatialNode( id: int, global_id: Optional[str], name: Optional[str], type_name: str, kind: str, parent: Optional[int], children: Tuple[int, ...], elements: Tuple[int, ...], referenced: Tuple[int, ...])
id: int
global_id: Optional[str]
name: Optional[str]
type_name: str
kind: str
parent: Optional[int]
children: Tuple[int, ...]
elements: Tuple[int, ...]
referenced: Tuple[int, ...]
@dataclass(frozen=True)
class SpatialDanglingReference:

A relationship naming an entity the file lacks.

SpatialDanglingReference(relation: int, target: int)
relation: int
target: int
@dataclass(frozen=True)
class SpatialAnomaly:

A second parent or a non-container structure the tree rejected.

SpatialAnomaly(kind: str, relation: int, subject: int, kept: Optional[int])
kind: str
relation: int
subject: int
kept: Optional[int]
@dataclass(frozen=True)
class Classification:

A classification that applies to an object.

kind is reference, system or notation (IFC2X3); source is occurrence or type (via type_object). parents are the references above a reference, nearest first.

Classification( relationship: int, global_id: Optional[str], source: str, type_object: Optional[int], target: int, kind: str, identification: Optional[str], name: Optional[str], location: Optional[str], notation: Tuple[str, ...], parents: Tuple[int, ...], system: Optional[ClassificationSystem])
relationship: int
global_id: Optional[str]
source: str
type_object: Optional[int]
target: int
kind: str
identification: Optional[str]
name: Optional[str]
location: Optional[str]
notation: Tuple[str, ...]
parents: Tuple[int, ...]
system: Optional[ClassificationSystem]
@dataclass(frozen=True)
class ClassificationSystem:

An IfcClassification.

ClassificationSystem(id: int, name: str, source: Optional[str], edition: Optional[str])
id: int
name: str
source: Optional[str]
edition: Optional[str]
@dataclass(frozen=True)
class MaterialAssignment:

The material association of an object, its own or its type's.

kind is material, list, layer, layer-set, layer-set-usage, profile, profile-set, profile-set-usage, constituent or constituent-set.

MaterialAssignment( relationship: int, global_id: Optional[str], source: str, type_object: Optional[int], target: int, type_name: str, kind: str, set: Optional[int], name: Optional[str], materials: Tuple[MaterialRef, ...], layers: Tuple[MaterialLayer, ...], profiles: Tuple[MaterialProfile, ...], constituents: Tuple[MaterialConstituent, ...], usage: Optional[MaterialUsage])
relationship: int
global_id: Optional[str]
source: str
type_object: Optional[int]
target: int
type_name: str
kind: str
set: Optional[int]
name: Optional[str]
materials: Tuple[MaterialRef, ...]
layers: Tuple[MaterialLayer, ...]
profiles: Tuple[MaterialProfile, ...]
constituents: Tuple[MaterialConstituent, ...]
usage: Optional[MaterialUsage]
@dataclass(frozen=True)
class MaterialRef:

An IfcMaterial.

MaterialRef(id: int, name: str, category: Optional[str])
id: int
name: str
category: Optional[str]
@dataclass(frozen=True)
class MaterialLayer:

An IfcMaterialLayer; thickness in the file's length unit, is_ventilated a Bool, Unknown or Null value.

MaterialLayer( id: int, material: Optional[MaterialRef], thickness: float, is_ventilated: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], name: Optional[str], category: Optional[str], priority: Optional[int])
id: int
material: Optional[MaterialRef]
thickness: float
is_ventilated: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]
name: Optional[str]
category: Optional[str]
priority: Optional[int]
@dataclass(frozen=True)
class MaterialProfile:

An IfcMaterialProfile; profile is its IfcProfileDef.

MaterialProfile( id: int, material: Optional[MaterialRef], profile: int, name: Optional[str], category: Optional[str], priority: Optional[int])
id: int
material: Optional[MaterialRef]
profile: int
name: Optional[str]
category: Optional[str]
priority: Optional[int]
@dataclass(frozen=True)
class MaterialConstituent:

An IfcMaterialConstituent.

MaterialConstituent( id: int, material: MaterialRef, name: Optional[str], category: Optional[str], fraction: Optional[float])
id: int
material: MaterialRef
name: Optional[str]
category: Optional[str]
fraction: Optional[float]
@dataclass(frozen=True)
class MaterialUsage:

How a layer or profile set is placed.

MaterialUsage( layer_set_direction: Optional[str], direction_sense: Optional[str], offset_from_reference_line: Optional[float], reference_extent: Optional[float], cardinal_point: Optional[int], end_set: Optional[int], cardinal_end_point: Optional[int])
layer_set_direction: Optional[str]
direction_sense: Optional[str]
offset_from_reference_line: Optional[float]
reference_extent: Optional[float]
cardinal_point: Optional[int]
end_set: Optional[int]
cardinal_end_point: Optional[int]
@dataclass(frozen=True)
class Systems:

Every system, and what the reader could not place.

Systems( systems: Tuple[System, ...], anomalies: Tuple[SystemAnomaly, ...])
systems: Tuple[System, ...]
anomalies: Tuple[SystemAnomaly, ...]
@dataclass(frozen=True)
class System:

An IfcSystem with its members and the structures it serves.

System( id: int, global_id: Optional[str], type_name: str, name: Optional[str], long_name: Optional[str], predefined_type: Optional[str], members: Tuple[int, ...], serviced_buildings: Tuple[int, ...], serviced_facilities: Tuple[int, ...])
id: int
global_id: Optional[str]
type_name: str
name: Optional[str]
long_name: Optional[str]
predefined_type: Optional[str]
members: Tuple[int, ...]
serviced_buildings: Tuple[int, ...]
serviced_facilities: Tuple[int, ...]
@dataclass(frozen=True)
class SystemAnomaly:

A membership the systems reader could not honour.

SystemAnomaly(kind: str, subject: int, other: Optional[int], message: str)
kind: str
subject: int
other: Optional[int]
message: str
@dataclass(frozen=True)
class Cost:

Every cost schedule and cost item.

Cost( schedules: Tuple[CostSchedule, ...], items: Tuple[CostItem, ...], anomalies: Tuple[CostAnomaly, ...])
schedules: Tuple[CostSchedule, ...]
items: Tuple[CostItem, ...]
anomalies: Tuple[CostAnomaly, ...]
@dataclass(frozen=True)
class CostSchedule:

An IfcCostSchedule; items are the objects assigned to it.

CostSchedule( id: int, global_id: Optional[str], name: Optional[str], identification: Optional[str], status: Optional[str], predefined_type: Optional[str], items: Tuple[int, ...])
id: int
global_id: Optional[str]
name: Optional[str]
identification: Optional[str]
status: Optional[str]
predefined_type: Optional[str]
items: Tuple[int, ...]
@dataclass(frozen=True)
class CostItem:

An IfcCostItem; objects are the objects it prices.

CostItem( id: int, global_id: Optional[str], name: Optional[str], identification: Optional[str], description: Optional[str], predefined_type: Optional[str], parent: Optional[int], children: Tuple[int, ...], values: Tuple[CostValue, ...], quantities: Tuple[int, ...], objects: Tuple[int, ...])
id: int
global_id: Optional[str]
name: Optional[str]
identification: Optional[str]
description: Optional[str]
predefined_type: Optional[str]
parent: Optional[int]
children: Tuple[int, ...]
values: Tuple[CostValue, ...]
quantities: Tuple[int, ...]
objects: Tuple[int, ...]
@dataclass(frozen=True)
class CostValue:

An IfcCostValue; applied_value as authored, typed.

CostValue( id: int, name: Optional[str], description: Optional[str], category: Optional[str], condition: Optional[str], applied_value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], operator: Optional[str], unit_basis: Optional[UnitBasis], components: Tuple[CostValue, ...])
id: int
name: Optional[str]
description: Optional[str]
category: Optional[str]
condition: Optional[str]
applied_value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]
operator: Optional[str]
unit_basis: Optional[UnitBasis]
components: Tuple[CostValue, ...]
@dataclass(frozen=True)
class UnitBasis:

The IfcMeasureWithUnit a rate is stated per.

UnitBasis( id: int, value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], unit: Optional[int])
id: int
unit: Optional[int]
@dataclass(frozen=True)
class CostAnomaly:

A cost item nested under two parents.

CostAnomaly(item: int, kept: int, rejected: int, relation: int)
item: int
kept: int
rejected: int
relation: int
@dataclass(frozen=True)
class MapConversion:

A coordinate operation resolved with the project length unit.

linear maps project metres to map metres as three columns; translation is where the project origin lands, in map metres.

MapConversion( operation: int, kind: str, source: int, source_kind: str, target_crs: ProjectedCrs, eastings: float, northings: float, orthogonal_height: float, x_axis: Tuple[float, ...], scale: float, factors: Optional[Tuple[float, ...]], project_unit: LengthUnit, map_unit: LengthUnit, map_unit_declared: bool, linear: Tuple[Tuple[float, ...], ...], translation: Tuple[float, ...])
operation: int
kind: str
source: int
source_kind: str
target_crs: ProjectedCrs
eastings: float
northings: float
orthogonal_height: float
x_axis: Tuple[float, ...]
scale: float
factors: Optional[Tuple[float, ...]]
project_unit: LengthUnit
map_unit: LengthUnit
map_unit_declared: bool
linear: Tuple[Tuple[float, ...], ...]
translation: Tuple[float, ...]
@dataclass(frozen=True)
class ProjectedCrs:

An IfcProjectedCRS.

ProjectedCrs( id: int, name: Optional[str], description: Optional[str], geodetic_datum: Optional[str], vertical_datum: Optional[str], map_projection: Optional[str], map_zone: Optional[str], well_known_text: Optional[str])
id: int
name: Optional[str]
description: Optional[str]
geodetic_datum: Optional[str]
vertical_datum: Optional[str]
map_projection: Optional[str]
map_zone: Optional[str]
well_known_text: Optional[str]
@dataclass(frozen=True)
class LengthUnit:

A length unit reduced to metres.

LengthUnit(name: str, metres_per_unit: float)
name: str
metres_per_unit: float
@dataclass(frozen=True)
class ProductPlacement:

One product's world placement and selected Body.

representation is None for a product with no solid representation (an axis only), which is not a refusal.

ProductPlacement( id: int, global_id: Optional[str], type_name: str, transform: Optional[Tuple[float, ...]], representation: Optional[SelectedRepresentation], refusal: Optional[GeometryRefusal])
id: int
global_id: Optional[str]
type_name: str
transform: Optional[Tuple[float, ...]]
representation: Optional[SelectedRepresentation]
refusal: Optional[GeometryRefusal]
@dataclass(frozen=True)
class SelectedRepresentation:

The IfcShapeRepresentation selected as a product's Body, and its context (ContextOfItems).

SelectedRepresentation( id: int, identifier: Optional[str], representation_type: Optional[str], context: Optional[int], context_type: Optional[str], context_identifier: Optional[str], target_view: Optional[str])
id: int
identifier: Optional[str]
representation_type: Optional[str]
context: Optional[int]
context_type: Optional[str]
context_identifier: Optional[str]
target_view: Optional[str]
@dataclass(frozen=True)
class GeometryRefusal:

Why one product has no placement, representation, graph or mesh.

code is unsupported, invalid-model, missing-reference or budget-exceeded; entity the entity at fault, if named.

GeometryRefusal(code: str, entity: Optional[int], message: str)
code: str
entity: Optional[int]
message: str
@dataclass(frozen=True)
class ProductGeometry:

One product's Body as Axiolid's neutral geometry graph.

payload is the wire envelope, a str for encoding "json" (json.loads reads it) and bytes for "cbor". The graph is in world coordinates, metres; transform is the product's placement, already applied, never to be applied again. No payload and no refusal: a product with no Body representation.

ProductGeometry( id: int, global_id: Optional[str], type_name: str, transform: Optional[Tuple[float, ...]], encoding: str, payload_size: int, refusal: Optional[GeometryRefusal], payload: Union[str, bytes, NoneType])
id: int
global_id: Optional[str]
type_name: str
transform: Optional[Tuple[float, ...]]
encoding: str
payload_size: int
refusal: Optional[GeometryRefusal]
payload: Union[str, bytes, NoneType]
GEOMETRY_FORMAT = 'axiolid-geometry-graph'
GEOMETRY_FORMAT_VERSION = '1.4'
@dataclass(frozen=True)
class ProductMesh:

One product's Body as triangles.

positions holds x, y, z per vertex (array('f'), metres, relative to transform), indices three vertex indices per triangle (array('I')). Empty arrays and no refusal: a product with no Body representation.

colour is the colour the Body's items agree on (#449), None when nothing colours the product or colour_refusal says why it is not resolved: code ambiguous (two styled items or two colours at one level, a layer or profile set of several materials, a constituent set no shape aspect resolves, or Body items of different colours) or a shared geometry code. A colour never refuses the mesh.

ProductMesh( id: int, global_id: Optional[str], type_name: str, transform: Optional[Tuple[float, ...]], vertex_count: int, triangle_count: int, refusal: Optional[GeometryRefusal], positions: array.array[float], indices: array.array[int], colour: Optional[SurfaceColour] = None, colour_refusal: Optional[GeometryRefusal] = None, closure: str = 'unknown')
id: int
global_id: Optional[str]
type_name: str
transform: Optional[Tuple[float, ...]]
vertex_count: int
triangle_count: int
refusal: Optional[GeometryRefusal]
positions: array.array[float]
indices: array.array[int]
colour: Optional[SurfaceColour] = None
colour_refusal: Optional[GeometryRefusal] = None
closure: str = 'unknown'
@dataclass(frozen=True)
class ProductCurves:

One product's curves as polylines (#458).

positions holds x, y, z per vertex (array('f'), metres, relative to transform), every polyline's vertices in turn; each of polylines names its slice. No polylines and no refusal: a product without the representation, or one with no curves. skipped lists the representation's text literals and annotation fill areas by entity id: not drawn, and not a refusal (#512).

ProductCurves( id: int, global_id: Optional[str], type_name: str, transform: Optional[Tuple[float, ...]], vertex_count: int, polylines: Tuple[ProductPolyline, ...], refusal: Optional[GeometryRefusal], skipped: Tuple[int, ...], positions: array.array[float])
id: int
global_id: Optional[str]
type_name: str
transform: Optional[Tuple[float, ...]]
vertex_count: int
polylines: Tuple[ProductPolyline, ...]
refusal: Optional[GeometryRefusal]
skipped: Tuple[int, ...]
positions: array.array[float]
@dataclass(frozen=True)
class ProductPolyline:

One curve of a ProductCurves, as a slice of its positions: vertices first_vertex to first_vertex + vertex_count, in the curve's direction. closed: the last vertex repeats the first. chord_bound is the certified bound, in metres, on how far the exact curve lies from the polyline (0.0 for a polyline the file authored); chord_requested the budget, one millimetre. curve is the IFC curve, when the lowering names one.

ProductPolyline( curve: Optional[int], first_vertex: int, vertex_count: int, closed: bool, chord_bound: float, chord_requested: float)
curve: Optional[int]
first_vertex: int
vertex_count: int
closed: bool
chord_bound: float
chord_requested: float
@dataclass(frozen=True)
class SurfaceColour:

The surface colour a mesh is painted with (#449).

red, green and blue are in [0, 1]; transparency too, 0 opaque, and None when the file states none (which the standard reads as opaque). source is item, layer or material, in that precedence; source_entity the IfcStyledItem, the layer assignment or the IfcMaterial; surface_style the IfcSurfaceStyle.

SurfaceColour( red: float, green: float, blue: float, transparency: Optional[float], source: str, source_entity: int, surface_style: int)
red: float
green: float
blue: float
transparency: Optional[float]
source: str
source_entity: int
surface_style: int
Value = typing.Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed]
@dataclass(frozen=True)
class Null:

$ -- the attribute is not set.

@dataclass(frozen=True)
class Derived:

* -- derived in a supertype; distinct from $.

@dataclass(frozen=True)
class Bool:

.T. or .F..

Bool(value: bool)
value: bool
@dataclass(frozen=True)
class Unknown:

.U. -- the third logical state.

@dataclass(frozen=True)
class Integer:

An integer literal (64-bit).

Integer(value: int)
value: int
@dataclass(frozen=True)
class Real:

A real literal; must be finite.

Real(value: float)
value: float
@dataclass(frozen=True)
class Text:

A string.

Text(value: str)
value: str
@dataclass(frozen=True)
class Binary:

A binary literal, as its hex digits.

Binary(value: str)
value: str
@dataclass(frozen=True)
class Enum:

An enumeration constant, without dots: Enum("ELEMENT").

Enum(value: str)
value: str
@dataclass(frozen=True)
class Ref:

A reference to entity #id.

Ref(id: int)
id: int
@dataclass(frozen=True)
class List:

An aggregate (list, set, array or bag).

List( items: Tuple[Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], ...])
items: Tuple[Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed], ...]
@dataclass(frozen=True)
class Typed:

A typed wrapper such as IFCLENGTHMEASURE(2.5).

Typed( type: str, value: Union[Null, Derived, Bool, Unknown, Integer, Real, Text, Binary, Enum, Ref, List, Typed])
type: str