robotframework / robotframework.github.com

Robot Framework ecosystem from page
http://robotframework.org
77 stars 80 forks source link

Feature Request: Add Recursive Conversion Functionality to Convert to Dictionary #322

Open GLMeece opened 4 months ago

GLMeece commented 4 months ago

Issue

When passing a Robot Framework dictionary to a Python function, one must convert the RF dictionary to a Python (non-ordered, non-DotDict) dictionary. When one passes in a dictionary with nested dictionaries, this conversion process only affects the root of the dictionary. That is to say, any sub-dictionary will remain in its Robot Framework object form and is not converted to to a "pure" Python dictionary.

Example

*** Settings ***
Documentation    Demonstration of nested dictionary behavior with the Convert To Dictionary keyword
Library      path/to/python_function.py   # Note: NOT provided - reader is left to their imagination

*** Variables ***
&{MAIN_DICT}    Sub_Dict_One=${EMPTY}    Sub_Dict_Two=${EMPTY}    Sub_Dict_Three=${EMPTY}

*** Test Cases ***

# Test cases that would call one of the keywords below

*** Keywords ***
Convert Dictionaries - Base Only
    [Documentation]    Only converts the base dictionary to 'regular' Pythonic dictionary
    &{Sub_One}    Create Dictionary    sub_key_one_a=one-one    sub_key_one_b=one-two
    &{Sub_Two}    Create Dictionary    sub_key_two_a=two-one    sub_key_two_b=two-two
    &{Sub_Three}  Create Dictionary    sub_key_three_a=three-one    sub_key_three_b=three-two
    Set To Dictionary    ${MAIN_DICT}    Sub_Dict_One=${Sub_One}    
    ...    Sub_Dict_Two=${Sub_Two}    Sub_Dict_Three=${Sub_Three}
    ${Converted_Main}    Convert To Dictionary    ${MAIN_DICT}  # Only the 'root' of the dictionary is converted

Convert Dictionaries - All
    [Documentation]    Converts both the sub-dictionaries as well as 
    ...    the base dictionary to a 'regular' Pythonic dictionary
    &{Sub_One}    Create Dictionary    sub_key_one_a=one-one    sub_key_one_b=one-two
    ${Converted_Sub_One}    Convert To Dictionary    ${Sub_One}
    &{Sub_Two}    Create Dictionary    sub_key_two_a=two-one    sub_key_two_b=two-two
    ${Converted_Sub_Two}    Convert To Dictionary    ${Sub_Two}
    &{Sub_Three}  Create Dictionary    sub_key_three_a=three-one    sub_key_three_b=three-two
    ${Converted_Sub_Three}    Convert To Dictionary    ${Sub_Three}
    Set To Dictionary    ${MAIN_DICT}    Sub_Dict_One=${Converted_Sub_One}    
    ...    Sub_Dict_Two=${Converted_Sub_Two}    Sub_Dict_Three=${Converted_Sub_Three}
    ${Converted_Main}    Convert To Dictionary    ${MAIN_DICT}  # All nodes of the dictionary are converted

Convert Dictionaries - Idealized
    [Documentation]    Written as if both the sub-dictionaries as well as 
    ...    the base dictionary were automatically converted to a 'regular' Pythonic dictionary
    &{Sub_One}    Create Dictionary    sub_key_one_a=one-one    sub_key_one_b=one-two
    &{Sub_Two}    Create Dictionary    sub_key_two_a=two-one    sub_key_two_b=two-two
    &{Sub_Three}  Create Dictionary    sub_key_three_a=three-one    sub_key_three_b=three-two
    Set To Dictionary    ${MAIN_DICT}    Sub_Dict_One=${Sub_One}    
    ...    Sub_Dict_Two=${Sub_Two}    Sub_Dict_Three=${Sub_Three}
    ${Converted_Main}    Convert To Dictionary    ${MAIN_DICT}    recursive_conversion=${True}

I will generate some Python that will elucidate the metadata that comes along with unconverted dictionaries at a later date.

Possible Update

Note: The following code is untested. I do not have the bandwidth at the moment to fork and create tests, but I was thinking something along the lines of the following as an update of Collections.py:

def convert_to_dictionary(self, item, recursive_conversion=False):
    """Converts the given ``item`` to a Python ``dict`` type.

     Mainly useful for converting other mappings to normal dictionaries.
    This includes converting Robot Framework's own ``DotDict`` instances
    that it uses if variables are created using the ``&{var}`` syntax.

    If ``recursive_conversion`` is set to ``True``, recursively converts 
    any nested DotDict dictionaries

    Use `Create Dictionary` from the BuiltIn library for constructing new
    dictionaries.
    """
    if recursive_conversion:
        for key, value in item.items():
            if isinstance(value, dict):  # or, would that be `DotDict`?
                key[value] = dict(value)
        return dict(item)
    return dict(item)