RAIMAD

DictList

A Dictlist is a RAIMAD-special container type that acts like both a Python dict, list and object all at the same time:

import raimad as rai

mydictlist = rai.DictList()

# works like a list
mydictlist.append('foo')
mydictlist.append('bar')
mydictlist.extend(['ayy', 'lmao'])

print(f"{len(mydictlist)=}")
print(f"{mydictlist[0]=}")
print(f"{mydictlist[2]=}")
len(mydictlist)=4
mydictlist[0]='foo'
mydictlist[2]='ayy'
# But also like a dict
mydictlist['free'] = 'luigi'
mydictlist['marco'] = 'polo'

print(f"{len(mydictlist)=}")
print(f"{mydictlist[4]=}")
print(f"{mydictlist['free']=}")
print(f"{mydictlist[5] is mydictlist['marco']=}")

for i, item in enumerate(mydictlist.items()):
    print(f"Item {i} = {item}")
len(mydictlist)=6
mydictlist[4]='luigi'
mydictlist['free']='luigi'
mydictlist[5] is mydictlist['marco']=True
Item 0 = (0, 'foo')
Item 1 = (1, 'bar')
Item 2 = (2, 'ayy')
Item 3 = (3, 'lmao')
Item 4 = ('free', 'luigi')
Item 5 = ('marco', 'polo')
# And also like an object

mydictlist.someattr = 'somevalue'
print(f"{mydictlist.someattr=}")
print(f"{mydictlist.free=}")
print(f"{mydictlist.marco=}")
mydictlist.someattr='somevalue'
mydictlist.free='luigi'
mydictlist.marco='polo'

The reason that it's good to know about dictlist is that it shares a common ancestry with the .subcompos and .marks attributes of compos. The exact inheritance diagram looks like this:

D ProxyableDictList <class 'raimad.compo.ProxyableDictList'> SubcompoContainer <class 'raimad.compo.SubcompoContainer'> ProxyableDictList->SubcompoContainer DictList <class 'raimad.dictlist.DictList'> DictList->ProxyableDictList FilteredDictList <class 'raimad.dictlist.FilteredDictList'> FilteredDictList->DictList MarksContainer <class 'raimad.compo.MarksContainer'> FilteredDictList->MarksContainer
snowman = rai.Snowman()
print(type(snowman.subcompos))
print(type(snowman.marks))
<class 'raimad.compo.SubcompoContainer'>
<class 'raimad.compo.MarksContainer'>

What this means in practice is that there are essentially two ways to assign a subcompo: with a name, or without a name. Using subcompos.append and subcompos.extend will assign only an index to the subcompo, while using self.subcompos.foo = bar or self.subcompos['foo'] = bar will make it accessible with both an index and a name. The second approach makes it easier for users of your component to do Subcompo Introspection.

Layers/Marks/Options annotations

#TODO no page on annotations yet!

Even though you assign the Layers, Marks, and Options annotations as nested classes when you create a component, when the class gets actually created, they also become dictlists:

print(type(rai.Snowman.Layers))
print(type(rai.Snowman.Options))
print(type(rai.Snowman.Marks))

print(rai.Snowman.Layers[0])
print(rai.Snowman.Layers[0].name)
print(rai.Snowman.Layers['pebble'].name)
print(rai.Snowman.Layers['pebble'].desc)
<class 'raimad.dictlist.DictList'>
<class 'raimad.dictlist.DictList'>
<class 'raimad.dictlist.DictList'>
<raimad.layer.Layer object at 0x7f10d38da3f0>
pebble
pebble
Non-malleable polycrystalline silicon layer

Anyway, hopefully this page clears up some non-trivial lines you might find in example code, such as calling self.subcompos.extend, or addressing self.marks with both [index_notation] and .attribute_notation.