Search code examples
pythondeserializationyamlpyyaml

Python, yaml nested objects


I am trying to create a yaml format that allow me to create an object inside another object. In this sample i am trying to create a State Machine object and at the same time populate it with some states and connections between them.

yaml.load("""
!statemachine {
     states: [
       !state { name: p1 },
       !state { name: p2 },
       !state { name: p3 },],
     connections:
      [!connection { 'pim' : [p1,p2]}]}
""")

!statemachine have a constructor that generates an object of type MyStateMachine

!state have a constructor that generates an object of type MyState

!connection have a constructor that should use object generated with name p1 and add a connection to it

I have 2 problems here:

1 - The constructor for state is called after the statemachine is created and the states are not present inside it

2 - Retrieve the object p1 and invoke the method add_connection over it.

Thanks in advance


Solution

  • lets try the true pyyaml syntax for objects

    myyaml.py:

    import yaml,sys
    
    class StateMachine(object):
        pass
    
    class State(object):
        pass
    
    class Connection(object):
        pass
    
    if __name__ == '__main__':
        o = yaml.load("""
        !!python/object:myyaml.StateMachine {
             states: [
               !!python/object:myyaml.State { name: p1 },
               !!python/object:myyaml.State { name: p2 },
               !!python/object:myyaml.State { name: p3 },],
             connections:
              [       !!python/object:myyaml.Connection { 'pim' : [p1,p2]}]}
        """)
        print o.states[0].name
        print o.states[1].name
        print o.connections[0].pim
        sys.exit(0)
    

    Gets:

    p1
    p2
    ['p1', 'p2']
    

    And never try the yaml.load() in module's root block, always use if __name__ == '__main__' or call it within a function that you ensure it will be called once.

    please note that yaml statement:

    !!python/object:myyaml.State { name: p1 },
    

    At this point yaml tries to import the myyaml.py again, in another context, and the all codes in the module's root will be executed, if you put yaml.load or anything like this in module's root, you may meet an infinite loop, or an unexpected result .