For example, suppose you want to know exactly where a TextureOp is located in the construction history (aka the operator stack).
A TextureOp object is nested under a cluster, not under the primitive, so you can’t use Primitive.ConstructionHistory.

Try it, and you’ll see that the TextureOp does not show up.
from siutils import sisel # Selection
from siutils import log # LogMessage
for x in sisel(0).ActivePrimitive.ConstructionHistory:
if x.BelongsTo( "MarkerOperators" ):
sMarker = x.type
log( "%s -> %s" %(sMarker,x.name) )
Instead, you’ll have to use DataRepository.GetConnectionStackInfo, which returns an XML description of the operator stack. The XML looks something like this (note that I had to use <_object> to stop wordpress from removing the <object> tag in my XML):
<?xml version="1.0"?>
<connections>
<connection>
<datacopy>0x000000001D7B7330</datacopy>
<hidden>false</hidden>
<_object>sphere.polymsh.modelingmarker</_object>
<objectid>533</objectid>
<region>2</region>
<type>out</type>
</connection>
<connection>
<datacopy>0x000000001F4C9F40</datacopy>
<hidden>false</hidden>
<_object>sphere.polymsh.cls.sample.clslist.Texture_Coordinates_AUTO.localprops.ClsProp.Texture_Projection.TextureOp</_object>
<objectid>571</objectid>
<region>2</region>
<type>out</type>
</connection>
<connection>
<datacopy>0x000000001C215310</datacopy>
<hidden>false</hidden>
<_object>sphere.polymsh.bulgeop</_object>
<objectid>532</objectid>
<region>2</region>
<type>in</type>
</connection>
</connections>
Here’s a Python snippet that uses ElementTree to parse the connectionstack XML and then log the TextureOp tooltip that says where the op reads from the stack:
from siutils import si # Application
from siutils import sidict # Dictionary
from siutils import sisel # Selection
from siutils import siuitk # XSIUIToolkit
from siutils import siut # XSIUtils
from siutils import log # LogMessage
from siutils import disp # win32com.client.Dispatch
from siutils import C # win32com.client.constants
from xml.etree import ElementTree as ET
prim = sisel(0).ActivePrimitive if si.ClassName(sisel(0)) == 'X3DObject' else sisel(0)
stackInfo = siut.DataRepository.GetConnectionStackInfo( prim )
#log( stackInfo )
connections = ET.XML(stackInfo)
currentMarker =''
#
# Read XML into a list of tuples that looks like this:
# ('sphere.polymsh.secondaryshapemarker', 'sphere.polymsh.secondaryshapemarker')
# ('sphere.polymsh.postsimulationmarker', 'sphere.polymsh.postsimulationmarker')
# ('sphere.polymsh.simulationmarker', 'sphere.polymsh.simulationmarker')
# ('sphere.polymsh.ICETree', 'sphere.polymsh.simulationmarker')
# ('sphere.polymsh.animationmarker', 'sphere.polymsh.animationmarker')
# ('sphere.polymsh.shapemarker', 'sphere.polymsh.shapemarker')
# ('sphere.polymsh.modelingmarker', 'sphere.polymsh.modelingmarker')
# ('sphere.polymsh.cls.sample.clslist.Texture_Coordinates_AUTO.localprops.ClsProp.Texture_Projection.TextureOp', 'sphere.polymsh.modelingmarker')
# ('sphere.polymsh.geom', 'sphere.polymsh.modelingmarker')
#
currentMarker = '%s.%s' %(prim.FullName, 'above-secondaryshapemarker')
ops = []
for connection in connections:
o = connection.find('object').text
bHidden = connection.find('hidden').text == 'true'
if o == currentMarker or bHidden:
continue
if o.endswith('marker'):
currentMarker = o
ops.append( (o, currentMarker ) )
#
# Go through list of tuples and find
# where TextureOp reads
#
for i in range( len(ops) ):
oOp = sidict.GetObject( ops[i][0] )
if oOp.type == 'TextureOp':
print oOp.Name
if i == len(ops):
sRead = "(reading from bottom of primitive stack)"
else:
sRead = '(reading just above %s)' %(sidict.GetObject( ops[i+1][0] ).Name)
print '%s %s' %(oOp.Name,sRead)
# TextureOp (reading just above Bulge Op)