Receiving bundle versions
Versions created with the new Speckle object model are bundle-only: instead of an object
graph they carry a bundle reference (bundle.<projectId>.<modelId>.<versionId>) in
Version.referencedObject, and their data lives in parquet artifacts served by the
/api/v2 rail. Receiving one needs the bundle extra:
pip install "specklepy[bundle]"
operations.receive3
from specklepy.api import operations
from specklepy.api.credentials import get_default_account
account = get_default_account()
with operations.receive3(account, project_id, model_id, version_id) as model:
for obj in model.objects_with("Constraints.Base Offset"):
print(obj.application_id, obj["Constraints.Base Offset"], obj.level.name)
wall = model.object_by_application_id("wall-1")
for geometry in wall.geometries: # placements already composed
mesh = geometry.decode_mesh()
material = geometry.effective_material
The returned Model owns the downloaded files until it is
closed (leave the with block, or call close()); parsed data stays usable afterwards.
Geometry is parsed from disk on first access — pass include_geometry=False to skip
downloading it entirely.
Properties are read straight from the bundle's columnar storage: obj.properties is a
read-only mapping of dotted paths ("Constraints.Base Offset"), obj["path"] resolves
instance → type → root scalar, and model.objects_with(path) scans one column across the
whole model.
Legacy operations.receive
operations.receive(obj_id, remote_transport, ...) detects a bundle reference and returns
the same data projected onto the classic Collection / DataObject tree
(Model.to_base()): objects keyed by applicationId, nested properties,
renderMaterialProxies and instanceDefinitionProxies on the root, version = 4. It needs
an authenticated ServerTransport for the reference's project.
API
Read façade over a received bundle (port of .NET Speckle.Sdk.Bundles.Model).
Model
Model(
project_id: str,
model_id: str,
version_id: str,
directory: str,
files: Sequence[str],
bundle: ArtefactBundle,
geometry_downloaded: bool = True,
)
A received version. Owns its download directory until :meth:close; parsed
data stays usable afterwards, geometry is parsed from disk on first access.
Source code in src/specklepy/bundle/model.py
| def __init__(
self,
project_id: str,
model_id: str,
version_id: str,
directory: str,
files: Sequence[str],
bundle: ArtefactBundle,
geometry_downloaded: bool = True,
) -> None:
self.project_id = project_id
self.model_id = model_id
self.version_id = version_id
self.directory = directory
self.files = list(files)
self.bundle = bundle
self._geometry_downloaded = geometry_downloaded
self._closed = False
if bundle.relations.unknown_rels:
log.warning(
"bundle %s/%s/%s uses relation ids this SDK does not know: %s",
project_id,
model_id,
version_id,
sorted(bundle.relations.unknown_rels),
)
|
project_id
instance-attribute
model_id
instance-attribute
version_id
instance-attribute
directory
instance-attribute
bundle
instance-attribute
default_scene_view
cached
property
default_scene_view: list[SceneViewTier]
camera_views
property
camera_views: list[CameraView]
property_set_definitions
property
unknown_relations
property
property_paths
cached
property
materials
cached
property
definitions
cached
property
collections
cached
property
is_geometry_loaded
property
geometries
cached
property
close
Source code in src/specklepy/bundle/model.py
| def close(self) -> None:
if self._closed:
return
self._closed = True
shutil.rmtree(self.directory, ignore_errors=True)
|
objects_with
Source code in src/specklepy/bundle/model.py
| def objects_with(self, path: str) -> list[ModelObject]:
keys = self.bundle.property_table.keys_with(PROPERTIES_PREFIX + path)
return [o for k in keys if (o := self.object(k)) is not None]
|
object
Source code in src/specklepy/bundle/model.py
| def object(self, k: int) -> ModelObject | None:
return self._objects_by_k.get(k)
|
object_by_application_id
object_by_application_id(
application_id: str,
) -> ModelObject | None
Source code in src/specklepy/bundle/model.py
| def object_by_application_id(self, application_id: str) -> ModelObject | None:
return self._objects_by_app_id.get(application_id)
|
node
Source code in src/specklepy/bundle/model.py
| def node(self, k: int | None) -> ModelNode | None:
return None if k is None else self.nodes.get(k)
|
to_base
Source code in src/specklepy/bundle/model.py
| def to_base(self) -> Collection:
from specklepy.bundle.base_projection import to_base
return to_base(self)
|
ModelObject
Source code in src/specklepy/bundle/model.py
| def __init__(self, model: Model, k: int, application_id: str) -> None:
self._model = model
self.k = k
self.application_id = application_id
|
application_id
instance-attribute
application_id = application_id
root_properties
property
root_properties: PropertyView
type_properties
property
type_properties: PropertyView
geometries
cached
property
assembly_members
property
system
property
First system membership; see :attr:systems for all of them.
collection_path
cached
property
scene_view_segments
property
scene_view_segments: list[SceneViewSegment]
container_material
property
get_double
Source code in src/specklepy/bundle/model.py
| def get_double(self, path: str) -> float | None:
return self._typed("get_double", path)
|
get_string
get_string(path: str) -> str | None
Source code in src/specklepy/bundle/model.py
| def get_string(self, path: str) -> str | None:
return self._typed("get_string", path)
|
get_bool
Source code in src/specklepy/bundle/model.py
| def get_bool(self, path: str) -> bool | None:
return self._typed("get_bool", path)
|
ModelGeometry
ModelGeometry(
model: Model,
owner: ModelObject,
k: int,
geometry: Geometry,
role: GeometryRole,
ord: int,
transform: Transform | None = None,
instance_k: int | None = None,
)
Source code in src/specklepy/bundle/model.py
| def __init__(
self,
model: Model,
owner: ModelObject,
k: int,
geometry: Geometry,
role: GeometryRole,
ord: int,
transform: Transform | None = None,
instance_k: int | None = None,
) -> None:
self._model = model
self.owner = owner
self.k = k
self.content = geometry.content
self.type = geometry.type
self.is_sgeo = geometry.is_sgeo
self.role = role
self.ord = ord
self.transform = None if transform is None else list(transform)
self._instance_k = instance_k
|
content
instance-attribute
is_sgeo
instance-attribute
transform = None if transform is None else list(transform)
effective_material
property
decode
Source code in src/specklepy/bundle/model.py
| def decode(self) -> Base:
return sgeo.decode(self.content)
|
decode_mesh
decode_mesh() -> DecodedMesh
Source code in src/specklepy/bundle/model.py
| def decode_mesh(self) -> sgeo.DecodedMesh:
return sgeo.decode_mesh(self.content)
|
ModelNode
ModelNode(model: Model, k: int, node: Node)
Source code in src/specklepy/bundle/model.py
| def __init__(self, model: Model, k: int, node: Node) -> None:
self._model = model
self._node = node
self.k = k
|
ModelContainer
ModelContainer(model: Model, k: int, node: Node)
Source code in src/specklepy/bundle/model.py
| def __init__(self, model: Model, k: int, node: Node) -> None:
self._model = model
self._node = node
self.k = k
|
ModelLevel
ModelLevel(model: Model, k: int, node: Node)
Source code in src/specklepy/bundle/model.py
| def __init__(self, model: Model, k: int, node: Node) -> None:
self._model = model
self._node = node
self.k = k
|
ModelMaterial
ModelMaterial(model: Model, k: int, node: Node)
Source code in src/specklepy/bundle/model.py
| def __init__(self, model: Model, k: int, node: Node) -> None:
self._model = model
self._node = node
self.k = k
|
ModelColor
ModelColor(model: Model, k: int, node: Node)
Source code in src/specklepy/bundle/model.py
| def __init__(self, model: Model, k: int, node: Node) -> None:
self._model = model
self._node = node
self.k = k
|
ModelDefinition
ModelDefinition(model: Model, k: int, node: Node)
Source code in src/specklepy/bundle/model.py
| def __init__(self, model: Model, k: int, node: Node) -> None:
self._model = model
self._node = node
self.k = k
|
ModelInstance
ModelInstance(model: Model, k: int, node: Node)
Source code in src/specklepy/bundle/model.py
| def __init__(self, model: Model, k: int, node: Node) -> None:
self._model = model
self._node = node
self.k = k
|