Python Script to read Property Set Definition Value of COGO Points

I can muddle my way through a Dynamo script when needed, but I’ve never attempted a Python Script node, so I turned to AI to write a Python script node to do the one piece of my graph that I couldn’t string together with OOTB nodes. As you may have surmised, the script keeps erroring and my lack of knowledge does not allow me to troubleshoot it properly, or as the saying goes “garbage in, garbage out”, what AI gave me was complete trash to begin with.

My intent with the dynamo graph is to grab all the COGO points in a drawing file and then read the Property Set Definition values for all those COGO points. I would then push those COGO points with a particular value for the particular Property Set Definition field and then put them into a Civil 3D point group. From what I could tell there are no OOTB nodes for COGO points that will read the Property Set Definitions assigned to them, so that led me to attempting to create a Python Script Node that would look for the Property Set Definitions of the COGO points I passed to it. From there I assumed with OOTB nodes I could group and filter as needed to whittle the list of points down to the points with a particular value in their Property Set Definition and then create a new point group. I am including the code I got from the AI google search. Is there anything there that can be troubleshooted to get it to work? Thank you for reading.

import clr

# Import standard Civil 3D/AutoCAD .NET assemblies

clr.AddReference('AcDbMgd')
clr.AddReference('AeccDbMgd')

# Import AEC Property Data assemblies for Property Sets

clr.AddReference('AecPropDataMgd')

import Autodesk.AutoCAD.DatabaseServices as acadDB
import Autodesk.Aec.PropertyData.DatabaseServices as aecPD
import Autodesk.AutoCAD.ApplicationServices as acadApp

# Inputs: Expects a list of Dynamo COGO Point objects

cogo_points = IN\[0\] if isinstance(IN\[0\], list) else \[IN\[0\]\]
output_data = [ ]

# Get the current drawing document and database

adoc = acadApp.Application.DocumentManager.MdiActiveDocument

# Safety check for empty inputs

if cogo_points and cogo_points\[0\] is not None:
with adoc.LockDocument():
with adoc.Database.TransactionManager.StartTransaction() as trans:


        for cp in cogo_points:
            point_info = {"CogoPoint": cp, "PropertySets": {}}
            
            # Extract the native AutoCAD Object ID from the Dynamo wrapper
            try:
                obj_id = cp.InternalObjectId
            except AttributeError:
                # Fallback for older Dynamo versions
                obj_id = cp.InternalElement.ObjectId
            
            # Get the collection of Property Sets attached to this Object ID
            p_set_ids = aecPD.PropertyDataServices.GetPropertySets(obj_id)
            
            for p_set_id in p_set_ids:
                # Open each Property Set object
                p_set = trans.GetObject(p_set_id, acadDB.OpenMode.ForRead)
                
                # Retrieve the Definition name of this Property Set
                # via its corresponding PropertySetDefinition object
                p_set_def = trans.GetObject(p_set.PropertySetDefinitionId, acadDB.OpenMode.ForRead)
                p_set_name = p_set_def.Name
                
                properties_dict = {}
                
                # Iterate through all properties defined in this set
                for prop in p_set.PropertyValues:
                    prop_id = prop.PropertyId
                    # Get the key/name of the property from the definition metadata
                    prop_def = p_set_def.Definitions[prop_id]
                    prop_name = prop_def.Name
                    
                    # Fetch the actual assigned value
                    prop_value = prop.Value
                    properties_dict[prop_name] = prop_value
                
                # Group data under the Property Set Definition Name
                point_info["PropertySets"][p_set_name] = properties_dict
            
            output_data.append(point_info)
            
        trans.Commit()


# Output to Dynamo

OUT = output_data

HI,

a solution that retrieves a DBObject using the ObjectId GetPropertySets need an entity

aecPD.PropertyDataServices.GetPropertySets(DBObject)

code PythonNet3

import sys
import clr

# Add Assemblies for AutoCAD and Civil3D
clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')

# Import references from AutoCAD
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.EditorInput import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *

# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *

# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN

adoc = Application.DocumentManager.MdiActiveDocument
editor = adoc.Editor

import Autodesk.AutoCAD.DatabaseServices as acadDB
import Autodesk.Aec.PropertyData.DatabaseServices as aecPD
import Autodesk.AutoCAD.ApplicationServices as acadApp

class CManager:
    """
    a custom context manager for Disposable Object
    """
    def __init__(self, obj):
        self.obj = obj
        
    def __enter__(self):
        return self.obj
        
    def __exit__(self, exc_type, exc_value, exc_tb):
        self.obj.Dispose()
        if exc_type:
            error = f"{exc_value} at line {exc_tb.tb_lineno}"
            raise ValueError( error)
        return self

cogo_points = IN[0] if isinstance(IN[0], list) else [IN[0]]
output_data = [ ]

# Get the current drawing document and database

adoc = acadApp.Application.DocumentManager.MdiActiveDocument

# Safety check for empty inputs

if cogo_points and cogo_points[0] is not None:
    with adoc.LockDocument():
        with CManager(adoc.Database) as db:
            with CManager(db.TransactionManager.StartTransaction()) as trans:
                for cp in cogo_points:
                    point_info = {"CogoPoint": cp, "PropertySets": {}}
                    
                    # Extract the native AutoCAD Object ID from the Dynamo wrapper
                    try:
                        obj_id = cp.InternalObjectId
                    except AttributeError:
                        # Fallback for older Dynamo versions
                        obj_id = cp.InternalElement.ObjectId
                    #
                    # get object from Id
                    DBObject = trans.GetObject(obj_id, OpenMode.ForRead)
                    # Get the collection of Property Sets attached to this Object 
                    p_set_ids = aecPD.PropertyDataServices.GetPropertySets(DBObject)
                    
                    for p_set_id in p_set_ids:
                        # Open each Property Set object
                        p_set = trans.GetObject(p_set_id, acadDB.OpenMode.ForRead)
                        
                        # Retrieve the Definition name of this Property Set
                        # via its corresponding PropertySetDefinition object
                        p_set_def = trans.GetObject(p_set.PropertySetDefinitionId, acadDB.OpenMode.ForRead)
                        p_set_name = p_set_def.Name
                        
                        properties_dict = {}
                        
                        # Iterate through all properties defined in this set
                        for prop in p_set.PropertyValues:
                            prop_id = prop.PropertyId
                            # Get the key/name of the property from the definition metadata
                            prop_def = p_set_def.Definitions[prop_id]
                            prop_name = prop_def.Name
                            
                            # Fetch the actual assigned value
                            prop_value = prop.Value
                            properties_dict[prop_name] = prop_value
                        
                        # Group data under the Property Set Definition Name
                        point_info["PropertySets"][p_set_name] = properties_dict
                    
                    output_data.append(point_info)
                    
                trans.Commit()

OUT = output_data