A. Kootstra
A. Kootstra

Reputation: 6961

Robot Framework Variable Class File with triple Nested Dictionary is not dot notation accessible

Using the Robot Framework Documentation on Variable Files as a guide I implemented a Variable File Class with the get_variables. The basic example works as described.

When I implement a triple nested Dictionary (${A.B.C}) I can access the first two using ${A} and ${A.B} notation. However, when I want to access the third node ${A.B.C} the result is that I get an error

Resolving variable '${A.B.C}' failed: AttributeError: 'OrderedDict' object
has no attribute 'C'

In the below three examples I have an RF generated nested dictionary that I can access all nodes through the dot notation. The second example is a plain Python dictionary that is given back by the Variable Class. In the last example the Variable class returned is of the type OrderedDict.

Although the ${A['B']['C']['key']} works, it is more difficult to read in the code. When I load a similar yaml structure it supports the dot notation fully but this is not an option as the yaml file is static, and I require flexibility of Python for some of the key values.

So, I'm looking for some support on how to return a data structure that allows Robot Framework to interpret the full nested structure with the dot notation.

Variable Class File

from collections import OrderedDict

class OrderDict(object):
    def get_variables(self):
        C = OrderedDict([(u'key', u'value')])
        B = OrderedDict([(u'C', C)])
        A = OrderedDict([(u'B', B)])
        D = {
                u'E':
                    {
                    u'F':
                        {
                            u'key':  u'value'
                        }
                    }
            }
        return OrderedDict([(u'DICT__A', A), (u'DICT__D', D)])

Robot Framework Script

*** Test Cases ***
Dictionary RF
    ${Z}    Create Dictionary    key=value
    ${Y}    Create Dictionary    Z=${Z}
    ${X}    Create Dictionary    Y=${Y}
    Log To Console    ${EMPTY}
    Log To Console    ${X}
    Log To Console    ${X['Y']['Z']['key']}
    Log To Console    ${X.Y}
    Log To Console    ${X.Y.Z}
    Log To Console    ${X.Y.Z.key}

Plain Dictionary Variable Class
    Log To Console    ${EMPTY}
    Log To Console    ${D}
    Log To Console    ${D['E']['F']['key']}
    Log To Console    ${D.E}
    Log To Console    ${D.E.F}
    Log To Console    ${D.E.F.key}

Ordered Dictionary Variable Class
    Log To Console    ${EMPTY}
    Log To Console    ${A}
    Log To Console    ${A['B']['C']['key']}
    Log To Console    ${A.B}
    Log To Console    ${A.B.C}
    Log To Console    ${A.B.C.key}

Robot Framework Console Log

Suite Executor: Robot Framework 3.0.2 (Python 2.7.9 on win32)

Dictionary RF                                                         
{u'Y': {u'Z': {u'key': u'value'}}}
value
{u'Z': {u'key': u'value'}}
{u'key': u'value'}
value
| PASS |
------------------------------------------------------------------------------
Plain Dictionary Variable Class                                       
{u'E': {u'F': {u'key': u'value'}}}
value
{u'F': {u'key': u'value'}}
| FAIL |
Resolving variable '${D.E.F}' failed: AttributeError: 'dict' object has no attribute 'F'
------------------------------------------------------------------------------
Ordered Dictionary Variable Class                                     
{u'B': OrderedDict([(u'C', OrderedDict([(u'key', u'value')]))])}
value
OrderedDict([(u'C', OrderedDict([(u'key', u'value')]))])
| FAIL |
Resolving variable '${A.B.C}' failed: AttributeError: 'OrderedDict' object has no 
attribute 'C'

Upvotes: 1

Views: 3757

Answers (1)

A. Kootstra
A. Kootstra

Reputation: 6961

In the Robot Framework Slack channel Pekka Klarck pointed out that Robot Framework internally uses the robot.utils.DotDic class. Having get_variables() return a DotDic structure resolved my issue and I can now use the dot notation. Below is the code for the Variable Class DotDic (stored as DotDic.py).

from robot.utils import DotDict

class DotDic(object):
    def get_variables(self):
        G = {
                u'H':
                    {
                    u'I':
                        {
                            u'key':  u'value'
                        }
                    }
            }
        return {u'G': self.dict_to_dotdict(G)}

    def dict_to_dotdict(self, dct):
        dd = DotDict({})
        for key, val in dct.items():
            if isinstance(val, dict):
                dd[key] = self.dict_to_dotdict(val)
            else:
                dd[key] = val
        return dd

Upvotes: 1

Related Questions