@jonathon and @iainsproat, I seem to get a little bit further. With the code down below i got a valid “200” status_code. The issue now is that i now get an empty list where i was expecting data.
header={
"Authorization": f"Bearer {Token}",
"Accept": "application/json",
"Content-Type": "application/json"
}
body = {
'objects': ['"cf02d5566caa6c38c3e2a7d9154168f4"']
}
url_get=f"https://app.speckle.systems/api/getobjects/{IN[0]}"
with requests.post(url=url_get,headers=header,json=body,stream=True) as r:
OUT=r
Hey Jonathan, do you maybe have an idea of how i could decipher if there is a bug in the API? It seems now that the script should return an object but what i get is an empty list. At this moment i have no clue how to check where the problem lies. I’m hoping you can give me some direction of how to figure out whether this is a bug or a mistake in my script?
TBH i wouldnt try to download a stream with the REST API from python, id go straight to using specklepy.
Some basic setup
import os
from dotenv import load_dotenv
load_dotenv()
token = os.getenv("SPECKLE_APP_TOKEN")
server = os.getenv("SPECKLE_APP_URL")
project_id = "6a87e55c77"
Get an authenticated client
from specklepy.api.client import SpeckleClient
client = SpeckleClient(server, use_ssl=True)
client.authenticate_with_token(token)
Use the API to retrieve data using a ServerTransport
from specklepy.transports.memory import MemoryTransport
from specklepy.transports.server import ServerTransport
project = client.stream.get(project_id)
model_id = "58c8effef5"
branches = client.branch.list(project_id)
model = next((b for b in branches if b.id == model_id), None)
latest_version = model.commits.items[0].referencedObject
memory_transport: MemoryTransport = MemoryTransport()
server_transport = ServerTransport(project_id, client)
data = operations.receive(latest_version, server_transport, memory_transport)
A simple flatten function to retrieve a List and not a Graph
from collections.abc import Iterable
from specklepy.objects import Base
def flatten_base(base: Base) -> Iterable[Base]:
"""Flatten a base object into an iterable of bases.
This function recursively traverses the `elements` or `@elements` attribute of the
base object, yielding each nested base object.
Args:
base (Base): The base object to flatten.
Yields:
Base: Each nested base object in the hierarchy.
"""
# Attempt to get the elements attribute, fallback to @elements if necessary
elements = getattr(base, "elements", getattr(base, "@elements", None))
if elements is not None:
for element in elements:
yield from flatten_base(element)
yield base
Thank you very much Jonathan! this is very helpfull. I tried this as well in dynamo for Revit. The problem i have here happens at the statement:
project = client.stream.get(project_id)``
Giving the output:
Failed to execute the GraphQL stream request. Inner exception: Transport is allready connected.
Before we start to tackle this problem, maybe it would be helpfull to explain a bit off what im trying to do. I want to make a custom connector In Revit/Dynamo which will be able to get elements in an sends them back with the same id. The goal is to maintain the element traceability throughout the whole proces, even when it gets modified in different software. The documentation stated:
When working with uploading and downloading objects, the REST API is preferred.
Is the GrapQL the right approach for this usecase or is the REST API the way to go for this usecase? I’m still figuring out the landscape of connection options in Speckle. I have tried the built-in Speckle 2 Connector in Dynamo but with that approach i didn’t seem to get all data neccesairy. I’d like to get your opinion about this. Thanks again in advance! The help i get on this platform is great!
I’ll check with the team internally, but in my experience/view, updating objects with the same ID directly is possible, yet it is considered unSpeckle-like. That is not to say it is illegitimate, but it is not the direction of travel we have for our demonstration of Speckle.
That’s a lot of words to say; I disagree with what you found in our docs
The updating objects with the same ID isn’t something i read in the documents but just a usecase i’m working on at the moment (so no fault there on the Speckle-end ). The reason i’m interested in this idea is because of the following situation:
Lets say an architect models a certain wall in Archicad. After that, the structural engineer imports that wall into Revit and adjust some parameters and maybe also some of the geometry. When importing that same wall back into Speckle, it is no longer recognised as the same wall.
This situation affects the tracebillity of the object througout the design proces. What we are now trying to explore is if we can use Speckle in a way were we can still track the changes of certain objects over multiple transfers between different software. The goal here is that we can later use this data to optimize our designproces.
Maybe updating the object to the same id is not the right way, but thats the approach which came to mind with my (still limited) knowlegde of the Speckle ecosystem. Do you know if there are allready other functionalities available which we can use to track the changes of objects over multiple transfers through different software?
Ah, the ID problem. It is much debated. A universal UID for objects externalised to the database and the authoring application—now that’s Strange Matter territory.
But before diving into solutions, it’s worth asking: Why is tracking an object across tools and versions essential to your current challenges? Is this driven by:
Design Auditing: Accountability or version control needs?
Coordination: Streamlining collaboration between disciplines?
Optimisation: Understanding how changes cascade through the design.
Or is it a more theoretical exploration to future-proof your workflows? If theoretical, it’s worth examining whether it aligns with Speckle’s capabilities, as universal object tracking often introduces practical complexities. Speckle’s versioning and metadata features might already meet your needs more simply.
The Current Landscape of Object Identification in Speckle
By default, Speckle handles object identification in two ways:
applicationId: Assigned by the host application:
Revit might use a GUID tied to its database.
Archicad would have its logic.
Navisworks, with no permanent UID concept, maps applicationId to a hierarchical path index. This is inherently software-specific and breaks when the object moves between platforms or is multi-authored.
speckleId: A hash based on an object’s content (geometry, metadata, etc.), unique to its exact state at the creation time. Any modification—intentional or software-induced—generates a new ID.
Thus, neither applicationId (software-specific and mutable) nor speckleId (content-based and immutable) can reliably track objects across versions or tools.
Why Cross-Software Tracking Is Challenging
Content Dependency: Speckle IDs change with any alteration to geometry or metadata.
Application-Specific Logic: applicationIds are tied to the originating software, lost or altered when objects are transformed.
Multi-Author Workflows: Collaborative edits across tools lead to new applicationIds, further compounding the issue.
No Universal Standards: Traceability remains elusive without a shared global UID system across platforms.
Potential Workarounds
globalId or Custom Properties:
Use a shared ID manually or via middleware to persist object lineage across tools.
Speckle supports custom properties, but not all tools faithfully transmit metadata.
Metadata and Geometric Matching:
Compare secondary properties like dimensions, material, or geometry as a “fingerprint.” However, metadata loss or precision issues can limit reliability.
Middleware for Reconciliation:
Custom tools or scripts to map relationships between IDs (applicationId, globalId) and establish traceability.
Standardised Workflows:
Agree on conventions for object creation, modification, and sharing to maintain consistency.
Speckle Automate:
Develop automation scripts to compare objects, identify lineage, and track changes programmatically.
Speckle’s Role in This
Speckle is designed to share, version, and collaborate on data, but its IDs focus on immutable snapshots rather than evolving object tracking. Cross-software traceability requires leveraging custom workflows, metadata, or middleware. If this challenge is critical, we can explore tailored approaches to your needs.
So our the reasons we want to track an object across tools are:
Optimisation: Understanding how changes cascade through the design.
Coordination: Streamlining collaboration between disciplines?
The workaround we wanted to apply is:
Custom tools or scripts to map relationships between IDs (applicationId, globalId) and establish traceability.
Agree on conventions for object creation, modification, and sharing to maintain consistency.
So in this thread we have discussed the REST-api, the GraphQL-api and the builtin speckle module in dynamo. Also i see that Speckle Automate might be an option. We would like to develop a durable workflow. Which of the the options spoken of above would you recommend to start with?
@jonathon@iainsproat, I still encounter several problems but trying to get the objects with all of their information into dynamo for Revit with SpecklePy. But to know which problem to solve i first am trying to find out which approach would be the right one in regards to the usecase as describes above. Could you help me out please?
since any speckle object (that inherits from specklepy.objects.base:Base) supports dynamically attaching arbitrary arguments, you can start experimenting with attaching your own data conventions to any objects you receive / create locally and then send to the server.
For all object-tree related actions we highly recommend using operations exposed in specklepy ie specklepy.api.operations:send, :serialize.
So if I understand your flow correctly, you are producing data somewhere, which you want to receive and manipulate in dynamo. I think running specklepy in dynamo might running into some dependency conflicts, as noted by Kateryna.
To confirm, that your script does what you need, i recommend running it in a standard python environment outside of the (many times weird) dynamo python environment.
Hi Gergo,
Thanks for your reply. The flow i want to implement is as follows:
get data from speckle in Dynamo
parse data to Revit-object (with speckle-data)
(user modifies elements)
extract elements from Revit into Dynamo
send elements back to Speckle with (mostly) original attributes
The goal is to find a way to be able to trace an element throughout the whole design-cycle. In this flow i made the assumption that it would be possible to map a native element to a speckle element by some kind of id-attribute. Basicly i would like to make a custom connector for Revit which doesn’t port elements back as Revit elements. At the moment i don’t know which of the systems suits this case best (REST-api, GraphQL, Dynamo-connecter, Specklepy etc.). So if i understand correctly i need to pay special attention into setting up the environment in a dynamo python environment and the Base-object is the entity which ties native-objects to speckle-objects (please correct me if i’m wrong). Before i start experimenting with the different communication-systems, could you advise me from your point of view which of the systems (REST-api, GraphQL, Dynamo-connecter, Specklepy etc.) is by design best suited for this usecase (or direct me in other utilities Speckle might have to have more control over the attributes while transporting elements)?
as mentioned above, any time your are trying to do anything with Speckle objects, its highly recommended to do it via one of our SDK-s.
As for your workflow, its been a while since I done hacking on revit data in anger, so I might be wrong, but it sounds like you need to bake a custom parameter to all of your revit objects, that allows you to assign this uniqueId.
Our connectors (with the right settings) fully support parameter extraction and baking on send and receive, but you’d have to wire up this custom parameter logic yourself.