The repository or configuration that created this release differ from a previous release. View details.
ifc-spf
Read and write IFC files with the standard library. Instances, property sets, quantities, units, the spatial chain — and edits written back out — no geometry kernel, no compiled dependency, no schema download.
from ifcspf import Model, Index
model = Model.open("building.ifc")
index = Index(model)
for door in model.of_type("IfcDoor"): # subtypes included
print(model.attr(door, "Name"), # attributes by name, not position
index.flat(door), # {"Pset_DoorCommon.FireExit": True, …}
index.spatial(door)["storey"]) # where it is
Extracted from two tools that had each written it once already — a quantity takeoff and a building-code checker — because the interesting part of both was never the parser.
What it does
| layer | what you get |
|---|---|
spf |
ISO 10303-21 tokeniser and parser: strings and their \X2\ escapes, references, enumerations, typed values, complex instances, comments, gzip, the header |
schema |
attributes addressed by name (attr(door, "OverallWidth")), subtype expansion (IfcWall finds IfcWallStandardCase), IFC4 / IFC2X3 differences — all as data tables |
units |
the project unit assignment resolved to SI factors, including conversion-based units (feet, inches), plus output conversion to mm, ft2, cy, … |
psets |
property sets, quantity sets and the spatial chain, converted to SI, with type-object inheritance and per-property unit overrides |
write |
instances back to ISO 10303-21: semantic round trip, byte-idempotent output, \X2\ string encoding, IFC GlobalId compression |
The three things it gets right that hand-rolled readers usually don't
Type-level property sets are inherited. A door's fire rating often lives on
its IfcDoorType, not the occurrence. Index collects type sets first and lets
instance sets override them — the inheritance IFC intends — and marks which is
which (Value.from_type).
Per-property units override the project unit. IfcPropertySingleValue and
every IfcQuantity* may carry their own Unit. A file with millimetre lengths
and one property in metres is not exotic; it is a Tuesday.
Every measure comes out in SI, and says what it was. Value carries the
converted number, the raw number, the measure type (IFCLENGTHMEASURE) and the
kind (length), so a consumer converts once, deliberately, at its own edge.
value = index.get(door, "Pset_PlancheckDoor", "ClearWidth")
value.value # 0.88 — metres, whatever the file used
value.raw # 880.0 — as written
value.measure # 'IFCLENGTHMEASURE'
value.kind # 'length'
value.from_type # False
Install
pip install ifc-spf
Python 3.11+. No dependencies.
API
Model.open(path) / Model.from_text(text) # .ifc and .ifc.gz
model.of_type("IfcWall", subtypes=True) -> [Entity]
model.attr(entity, "Name") / model.ref_attr(entity, "RelatingStructure")
model.get(ref) / model.resolve_all(refs) / model.referencing(entity, of_type=None)
model.schema # 'IFC4' | 'IFC2X3' | …
model.scale # UnitScale(length=0.001, area=1.0, …)
model.type_counts()
index = Index(model, inherit_type=True)
index.values(entity) # {set name: {property name: Value}}
index.flat(entity) # {"Pset.Name": value}
index.get(entity, "Pset_DoorCommon", "FireExit") # one Value, case-insensitive
index.find(entity, "FireExit") # by name, any set
index.spatial(entity) # {"space": …, "storey": …, "building": …, "site": …}
index.storey_elevation(entity) # metres
from ifcspf import loads, load, unwrap, convert, expand_types
convert(0.88, "mm") # 880.0 — SI base out to a declared unit
# editing — by name, refusing to guess
model.set_attr(wall, "Name", "Tường trục A") # unknown names raise KeyError
new = model.add("IfcWall", GlobalId=new_guid(), Name="W-09")
model.remove(entity) # raises DanglingReferenceError if referenced
model.remove(entity, force=True) # …strips the references too
model.save("edited.ifc") # or model.dumps() for the text
The written file is semantically identical to what was parsed (same instances,
same values) and writing is byte-idempotent, but layout is not preserved:
comments and whitespace go, numbers are respelt canonically (1.0E3 → 1000.0),
non-ASCII strings come out as \X2\ runs. Diff an edited file against a
previous write, not against the original export.
What it deliberately does not do
- No geometry. No swept solids, no BRep, no placement maths, no clash detection. Property-level tooling — takeoffs, code checks, audits, exports — does not need it, and pretending otherwise is how a reader becomes a kernel.
- No schema validation. It reads what the file states about itself, and it
writes what the instances say — an edit that violates the EXPRESS schema will
be written faithfully, not corrected. The one guard is referential:
remove()will not silently orphan references. - No layout preservation on write. Output is canonical, not a patch of the original text (see above).
If you need geometry or validation, use ifcopenshell — it is excellent, and this package is not trying to replace it. This is for the large class of jobs where pulling in a compiled IFC toolkit is the heaviest thing in the project.
Used by
- qto — quantity takeoff with pluggable cost classification
- plancheck — building code as machine-readable rules
MIT licensed.
Metadata
Release files for ifc-spf 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Change of provenance
The repository or configuration that created these release files differ from that of a previous release.
We recommend inspecting the repository and configuration before proceeding. View details.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| ifc_spf-0.2.0.tar.gz | 35.6 kB | With provenance | Details for ifc_spf-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| ifc_spf-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for ifc_spf-0.2.0-py3-none-any.whl |
Total release size: 61.9 kB
Release files / ifc_spf-0.2.0.tar.gz
Change of provenance
This file belongs to a release with changed provenance: the repository or configuration that created the release files differ from that of a previous release.
We recommend inspecting the repository and configuration before proceeding. View details.
| Download URL | ifc_spf-0.2.0.tar.gz |
|---|---|
| Size | 35.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
960e5654a7cefdaaa97ae30b0302483278c1be43b12f528f75cb0ca704f73ce3
|
|
BLAKE2b-256 checksum How to use checksums |
26af78b73c85ea711899a8b91e66d734f4523ae45aa8b77cc8d895714128bfe4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.
Transparency logRelease files / ifc_spf-0.2.0-py3-none-any.whl
Change of provenance
This file belongs to a release with changed provenance: the repository or configuration that created the release files differ from that of a previous release.
We recommend inspecting the repository and configuration before proceeding. View details.
| Download URL | ifc_spf-0.2.0-py3-none-any.whl |
|---|---|
| Size | 26.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dd0542bd41d6ebc3c8174093f9917bf60d5367d59f8f582522ad246040bfaa12
|
|
BLAKE2b-256 checksum How to use checksums |
5ce5066b81c02556c02d66e4fd0089893e6b7707016b04007fd060ff44aaf61a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.
Transparency logSecurity for ifc-spf 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Change of provenance
The repository and configuration that created this release differ from a previous release.
While this could reflect a routine change by the project maintainers, it may also indicate that the release files have been compromised.
Repository
- Removed 0.1.0 github.com/sophie-nguyenthuthuy/ifc-spf
- Added 0.2.0 github.com/aec-platform/ifc-spf
Attestation for ifc_spf-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 10, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.