How to get the geometry info from commit by python?

Hi!

I used grasshopper to send 3 geometries (rooms) to speckle, and I want to receive them in python. I am newbie in receiving data in python, and I can now receive base object in python. Then how can I further extract info from base e.g. vertice, face and form the geometries back?

Hey @newshunhk! :smiley_spockle:

There are many approaches here (sorry, no simple answer).

In general, a nice way of seeing attributes associated to objects is to use the get_member_names() method. Combine that, with the selection info in the viewer (which you’re already doing), you can access the attributes you want with some simple dot notation and using the parameter names you see in the viewer.

An example below, seeing “what I have” in my commit using get_member_names():

Accessing elements and chaining some attributes together (with the help of the viewer) to access the vertices of a mesh:

This works nicely in a well protected and defined environment. But when working with larger commits, it’s probably nice to use the getattr() to handle attributes not existing. Consider the little example below with two different approaches:

Hope this helps! Let me know if you have any other questions!

I’d be curious to find out more about your workflow - what and how are you wanting to form the geometries back?

Cheers!
Björn

2 Likes

Hi @bjoern thanks for your reply!
But I dont know why I cannot get the “displayValue” in python, despite I can see that from web broswer.

image

Interesting. The get_member_names() return is not what I was expecting when comparing to the viewer. This could, however, be nested within the @Data detached property. Have you had a look in there?

# Explore what is within the detached property
received_base["@Data"]

# If this is directly an object
received_base["@Data"].get_member_names()

Also, does received_base.id from the Python script equal the id shown on the viewer (i.e. 344853b366…)

seems can get something now, but overall a bit complicated :grinning:

1 Like

Hey @newshunhk,

Awesome that it’s working! :cool_spockle:

I seemed to have overread the part about the received commit coming from Grasshopper - my apologies! The extrapolating of information through a series of clunky number of “@{0;0;2;0}” tree indices is a bit awkward - AGREED!

With that, we can refine the code a bit, thankfully @jonathon has got your back with a neat flatten_base function. Modified a little to focus on searching for those indices coming from GH prepended with a “@” symbol:

"""Helper module for a simple speckle object tree flattening."""

from collections.abc import Iterable
from typing import Any

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 any attribute that starts with '@' in the
    base object, yielding each nested base object found within those attributes.

    Args:
        base (Base): The base object to flatten.

    Yields:
        Base: Each nested base object in the hierarchy.
    """
    def _get_elements_from_attr(obj: Any) -> list[Base]:
        """Helper function to get Base objects from an attribute value."""
        if isinstance(obj, (list, tuple)):
            return [item for item in obj if isinstance(item, Base)]
        elif isinstance(obj, Base):
            return [obj]
        return []

    # Get all attributes that start with '@'
    at_attributes = [attr for attr in dir(base) if attr.startswith('@')]
    
    # Process each @ attribute
    for attr in at_attributes:
        elements = getattr(base, attr, None)
        if elements is not None:
            # Get all Base objects from this attribute
            base_elements = _get_elements_from_attr(elements)
            # Recursively process each Base object
            for element in base_elements:
                yield from flatten_base(element)
    
    yield base

As you can see in the below screenshot, my beam objects are stored in ["@Data"]["@{0}]. In this approach, I just call flatten_base on the received_base and I can negate the need for awkward indexing.

Give it a go on your script! Note, this is now specific for GH and searching for a prepended “@” character. Take care when using the function on data from other sources. Other host apps we search for elements attribute as opposed to the “@”.

1 Like

Hi thanks for your reply :slight_smile:
but somehow I got this erro message :frowning:

I think there is just a little variable naming conflict going on there. See two approaches below, the first one uses the variable name flattened_base and the second flatten_base. This should highlight the conflict in naming being the same as the function.

Try assign the result of the method in line 12 to something other than flatten_base which is in your snip the same as the method name.

thank you so much :slight_smile:
yes I used same name by mistaken :laughing:

2 Likes