Federating Speckle Models

Merge 2 - Smash them together

The next version of merging is extreme difference from simple overlays. We will extract all the component objects from each commit. This is a bit more involved as we need to load the things from the server and reconstruct a commit.

image

  1. Take the content of the 3 commits and commit that to speckle.
  2. View that commit in the embedded viewer

Firstly, we’ll get the commit objects

commit_objects = [
    client.commit.get(stream_id, commit_id) for commit_id in commit_ids
]

If the 3 URLs given are all commits, then the first name object has a property called referencedObject which is the id of the wrapper object for the commit data.

referenced_objects = [r.referencedObject for r in commit_objects]

We then’ Receive’ each reference object to assemble a large array of all the committed things.

from specklepy.api import operations

commit_data = [
    operations.receive(obj_id=ref_obj, remote_transport=wrap.get_transport())
    for ref_obj, wrap in zip(referenced_objects, wrappers)
]

For this example, I will create a commit that retains the structure of the three separate. If you were trying to apply any filters or run diffing operations, this is the stage where you could merge the three only to include the latest objects etc. The subject of a future post on this topic

I happen to know there is no overlap, so I’ll proceed.

from specklepy.objects import Base

granular_commit_object = Base(speckle_type="Federation.Granular")
granular_commit_object["@Components"] = commit_data

… and hash them

hash3 = operations.send(base=granular_commit_object , transports=[transport])

Suppose we follow the reasoning from other discussions around Versions, Federations, Assemblies, Exchanges etc. We should store this new commit on a dedicated branch.

def try_get_branch_or_create(client, stream_id, branch_name):
    try:
        client.branch.get(
            stream_id=stream_id, name=branch_name
        ) or client.branch.create(stream_id=stream_id, name=branch_name)
        return client.branch.get(
            stream_id=stream_id, name=branch_name)
    except GraphQLException:
        return client.branch.create(stream_id=stream_id, name=branch_name)

branch = try_get_branch_or_create(client, stream_id, "federated")

And then we create a new commit that contains the resolved objects

commit_id3 = client.commit.create(
    branch_name=branch.name,
    stream_id=stream_id,
    object_id=hash3,
    message="federated commit",
)

Then as with part 1, we generate an embedded viewer URL to demonstrate the federation:

embed_url3 = (f"https://speckle.xyz/embed?stream={stream_id}"
              f"&commit={commit_id3}"
              f"&transparent={transparency}"
              f"&autoload={autoload}"
              f"&hidecontrols={hide_controls}"
              f"&hidesidebar={hide_sidebar}"
              f"&hideselectioninfo={hide_selection_info}")

from IPython.display import IFrame

IFrame(embed_url3, width=400, height=300)

As mentioned, this version could be a jumping-off point for clever logic employed over what objects to include and which not to.

More importantly for Data Management, this complete merge allows for merges across Project Streams!!


6 Likes