Skip to main content

Overview

The operations module provides the core functions for working with Speckle data: sending objects to transports, receiving them back, and serializing/deserializing for custom workflows.
from specklepy.api import operations
from specklepy.objects.geometry import Point
from specklepy.transports.server import ServerTransport

# Send an object
point = Point(x=1, y=2, z=3)
transport = ServerTransport(stream_id="abc", client=client)
object_id = operations.send(point, [transport])

# Receive it back
received = operations.receive(object_id, remote_transport=transport)

Principal Operations

send()

Send a Base object to one or more transports.
operations.send(
    base: Base,
    transports: Optional[List[AbstractTransport]] = None,
    use_default_cache: bool = True
) -> str
Parameters:
base
Base
required
The object to send
transports
List[AbstractTransport]
default:"None"
Where to send the object. Defaults to local cache only.
use_default_cache
bool
default:"True"
Whether to also save to the local SQLite cache
Returns:
object_id
str
The object ID (hash) of the sent object
Examples:
  • Send to Server
  • Send Complex Object
  • Send to Multiple Transports
  • Local Cache Only
from specklepy.api import operations
from specklepy.api.client import SpeckleClient
from specklepy.transports.server import ServerTransport
from specklepy.objects.geometry import Point

# Setup
client = SpeckleClient(host="https://app.speckle.systems")
client.authenticate_with_token(token)

# Create transport
transport = ServerTransport(stream_id="project_id", client=client)

# Send object
point = Point(x=10, y=20, z=5)
object_id = operations.send(point, [transport])

print(f"Sent object: {object_id}")
When you send an object, all nested Base objects are automatically sent too. You don’t need to send them separately.

receive()

Receive a Base object from a transport.
operations.receive(
    obj_id: str,
    remote_transport: Optional[AbstractTransport] = None,
    local_transport: Optional[AbstractTransport] = None
) -> Base
Parameters:
obj_id
str
required
The ID of the object to receive
remote_transport
AbstractTransport
default:"None"
The transport to receive from (e.g., ServerTransport)
local_transport
AbstractTransport
default:"None"
The local cache to check first. Defaults to SQLiteTransport
Returns:
object
Base
The received object, fully recomposed with all children
Examples:
  • Receive from Server
  • Receive with Local Cache
  • Receive from Cache Only
from specklepy.api import operations
from specklepy.api.client import SpeckleClient
from specklepy.transports.server import ServerTransport

# Setup
client = SpeckleClient(host="https://app.speckle.systems")
client.authenticate_with_token(token)

# Get the object ID from a version
version = client.version.get(project_id, version_id)
object_id = version.referencedObject

# Create transport and receive
transport = ServerTransport(stream_id=project_id, client=client)
obj = operations.receive(object_id, remote_transport=transport)

print(f"Received: {obj.speckle_type}")
receive() automatically reconstructs the entire object tree. All referenced child objects are fetched and recomposed.

Serialization

Note: The serialize() and deserialize() functions below are included for completeness, but most developers won’t need them directly. The send() and receive() operations handle serialization and deserialization implicitly. Use these functions only when you need custom workflows like saving objects to files or working with JSON representations directly.

serialize()

Serialize a Base object to a JSON string.
operations.serialize(
    base: Base,
    write_transports: Optional[List[AbstractTransport]] = None
) -> str
Parameters:
base
Base
required
The object to serialize
write_transports
List[AbstractTransport]
default:"None"
Transports to write detached objects to. If None, objects are serialized inline without detachment
Returns:
json_string
str
JSON string representation of the object
Examples:
  • Simple Serialization
  • Serialize with Detachment
  • Save to File
from specklepy.api import operations
from specklepy.objects.geometry import Point

point = Point(x=10, y=20, z=5)
point.units = "m"

json_str = operations.serialize(point)
print(json_str)
# {"x": 10, "y": 20, "z": 5, "units": "m", "speckle_type": "Objects.Geometry.Point", ...}
Without write transports, large nested objects are serialized inline, which can result in huge JSON strings. Use write transports for large objects.

deserialize()

Deserialize a JSON string back into a Base object.
operations.deserialize(
    obj_string: str,
    read_transport: Optional[AbstractTransport] = None
) -> Base
Parameters:
obj_string
str
required
JSON string to deserialize
read_transport
AbstractTransport
default:"None"
Transport to read detached/referenced objects from. Defaults to SQLiteTransport
Returns:
object
Base
The deserialized object
Examples:
  • Simple Deserialization
  • Deserialize with References
  • Load from File
from specklepy.api import operations

json_str = '{"x": 10, "y": 20, "z": 5, "speckle_type": "Objects.Geometry.Point"}'
point = operations.deserialize(json_str)

print(f"Point: ({point.x}, {point.y}, {point.z})")
# Point: (10, 20, 5)
If the JSON contains references (like "@displayValue": "hash123..."), you must provide a read_transport that contains those referenced objects.

Detachment and Chunking

Large objects are automatically optimized during send:
from specklepy.api import operations
from specklepy.objects.geometry import Mesh
from specklepy.transports.server import ServerTransport

# Create a large mesh
mesh = Mesh(
    vertices=[...],  # 1 million vertices
    faces=[...],     # 500k faces
)

# Mesh vertices and faces are automatically chunked
transport = ServerTransport(stream_id="project_id", client=client)
object_id = operations.send(mesh, [transport])

# The mesh and its chunks are all stored separately for efficiency
Objects like Mesh have predefined chunking and detachment rules. See the Mesh documentation for details.

Best Practices

Always let the local cache work for you:
# Good - uses local cache by default
object_id = operations.send(obj, [remote_transport])

# Also good - explicit local cache
received = operations.receive(
    object_id,
    remote_transport=remote_transport,
    local_transport=SQLiteTransport()  # Explicit
)

# Bad - disabling cache hurts performance
object_id = operations.send(
    obj,
    [remote_transport],
    use_default_cache=False  # Don't do this
)
Network operations can fail:
from specklepy.api import operations
from specklepy.transports.server import ServerTransport

transport = ServerTransport(stream_id="project_id", client=client)

try:
    obj = operations.receive(object_id, remote_transport=transport)
    print(f"Success: {obj.speckle_type}")
except Exception as e:
    print(f"Receive failed: {e}")
    # Handle error (retry, log, notify user, etc.)
Be careful with deserialization:
# Only deserialize JSON from trusted sources
def safe_deserialize(json_str: str):
    try:
        # Validate it's actually Speckle data
        obj = operations.deserialize(json_str)
        if not hasattr(obj, 'speckle_type'):
            raise ValueError("Not a valid Speckle object")
        return obj
    except Exception as e:
        print(f"Deserialization failed: {e}")
        return None
Choose the right transport for your use case:
from specklepy.transports.server import ServerTransport
from specklepy.transports.memory import MemoryTransport
from specklepy.transports.sqlite import SQLiteTransport

# For sending to Speckle
server = ServerTransport(stream_id="id", client=client)
operations.send(obj, [server])

# For temporary storage
memory = MemoryTransport()
operations.send(obj, [memory])

# For local persistence
sqlite = SQLiteTransport()
operations.send(obj, [sqlite])

Summary

The operations module provides four essential functions:
  • send() - Send objects to transports with automatic chunking/detachment
  • receive() - Receive and recompose objects from transports
  • serialize() - Convert objects to JSON strings
  • deserialize() - Convert JSON strings back to objects
These operations are the foundation of all Speckle data workflows!

Next Steps