Consider the following code:
In Utils.py:
@keyword
def get_compound_dictionary():
"""
https://docs.python.org/3/library/copy.html
An example compound dictionary
"""
return {'key1': 'value1', 'deep_dict': {'key2': 'value2'}}
In collection-library-tests.robot
*** Settings ***
Documentation A test suite utilizing all collection library keywords
Library Collections
Library Utils.py
# To run:
# robot --pythonpath Resources --noncritical failure-expected -d Results/ Tests/collection-
library-tests.robot
*** Test Cases ***
Use "Copy Dictionary" : Shallow Copy
${compound_python_dictionary} = get compound dictionary
&{shallow_copy} = Copy Dictionary ${compound_python_dictionary} deepcopy=False
# if we modify the contained objects (i.e. deep_dict) through the shallow_copy,
# the original compound_python_dictionary will see the changes in the contained objects
Set To Dictionary ${shallow_copy}[deep_dict] key2=modified
Log ${shallow_copy}
Log ${compound_python_dictionary}
Should Be Equal ${compound_python_dictionary}[deep_dict][key2] modified # fails, why?
The goal is stated in the test case as:
if we modify the contained objects (i.e. deep_dict) through the shallow_copy, the original compound_python_dictionary will see the changes in the contained objects
Expected Result
Should Be Equal ${compound_python_dictionary}[deep_dict][key2] modified # passes
Note that I am using Robot FW version: Robot Framework 3.1.2 (Python 3.7.4 on linux)
Acc.to the documentation about Copy Dictionary:
The deepcopy argument controls should the returned dictionary be a shallow or deep copy. By default returns a shallow copy, but that can be changed by giving deepcopy a true value (see Boolean arguments). This > is a new option in Robot Framework 3.1.2. Earlier versions always returned shallow copies.
Acc.to the documentation about Boolean Arguments:
Some keywords accept arguments that are handled as Boolean values true or false. If such an argument is given as a string, it is considered false if it is an empty string or equal to FALSE, NONE, NO, OFF or 0, case-insensitively. Other strings are considered true regardless their value.
Note also that i tried also deepcopy=${False}
, which yielded the same observed result.
The problem is not with the RF keyword (it very seldom is, they have extensive UT), but with the way you call it, namely this argument:
deepcopy=False
You may be thinking you are passing a boolean value, but in fact you are passing the string "False"
.
Inside the keyword's implementation there is this branching:
if deepcopy:
return copy.deepcopy(dictionary)
, and as a non-empty string evaluates to True
, you are in fact getting a deep copy.
This is the way to pass a real False
:
deepcopy=${False}
I updated the ticket based on the instructions of your comment. Long story short, deepcopy=${False} wont work either. Can run this code on your machine? Thanks Todor.
"Some keywords accept arguments that are handled as Boolean ... " - this one does not, check its implementation. github.com/robotframework/robotframework/blob/master/src/robot/… I cannot run your code anytime soon, but will be deeply surprised if it misbehaves with proper boolean false.
I admit that the code link you provided indeed says differently than what the documentation for the keyword say. So, one issue is a conflict between code and its documentation. Another issue is that given the code you provided, deepcopy=${False} is not working (i deleted all the test logs and re-run the test case twice). What is the reason??
Off topic, but I don't see how the documentation of the keyword differs from its implementation; it describes precisely what the keyword does.
The documentation of the keyword says that deepcopy=False or deepcopy=${False} will be considered as falsy values, therefore shallow copying will take place. Note that i updated this ticket with the keywords documentation.