robotframework
robotframework copied to clipboard
Variable type conversion
RF 3.1 added automatic argument conversion with library keywords using function annotations (#2890), default values (#2932), and some other means. That has worked very well, and it would be nice if something like that would work also with variables defined in test data. We probably could re-use the underlying argument conversion logic which ought to make it relatively easy to implement this. We also got a similar request related to variables passed from the command line #2946.
Automatically converting numbers like 42 and 3.14 to actual integers/floats would be handy, even when we already support them as variables like ${42} and ${3.14}. Being able to use datatime objects, bytes, and other types supported by the argument conversion that don't have direct variable alternatives would naturally be even more useful (but also less commonly needed). I would expect this to be most useful with lists and dictionaries and especially with nested list and dicts that cannot easily be constructed in Robot's data.
My proposed syntax for this functionality is supporting "type postfix" like :int in variable names like this:
*** Variables ***
${COUNT:int} 42
${GOOD IDEA:bool} Yes # Converted to Boolean True
${ANIMALS:list} ['cat', 'dog', 'horse'] # Python syntax
${NESTED:dict} {'a': 1, 'b': [{'x': 2}, {'x': 3}]} # Great with JSON
This syntax is derived from Python's function annotation syntax and also the same syntax that was decided to be used with command line variables in #2946. Created variable names would naturally omit the type suffix and look like ${COUNT} and ${GOOD IDEA}.
In addition to being available in the variable section, the new syntax should also be available also when creating variable otherwise, including in keyword arguments:
*** Keywords ***
Example
[Arguments] ${count:int}
${nested:dict} = Set Variable {'a': ${count}, 'b': [{'x': 2}, {'x': 3}]}
Set Test Variable ${DATE:datetime} 2019-08-23 12:03:42
There are some design decision still to be made like should ${X:dict} create a DotDict instance that allows ${X.key} syntax and how to handle possible backwards incompatibility issues. For most parts the design looks pretty good, though, and I think this would be a valuable addition to Robot Framework. If there's enough interest, we can consider adding this already to RF 3.2 scope. To show your interest, vote with :+1: or :-1: and/or add comments.
This change is backwards compatible because it's possible that someone has used variables that contain : in their name like ${FOO:BAR}. If we always consider the part after the colon to be the type, then such usage won't work anymore. One possibility is checking is that part a recognized type, but there's still a risk that someone has a variable like ${MY:LIST}. It would naturally be safest to deprecate using colons in variable names first, but that would mean that the actual conversion support needed to wait until RF 3.3. In my opinion the risk for this change causing problems is small enough and benefits of the new syntax are big enough to do the change already in RF 3.2.
If this enhancement is implemented, it makes issue #2699 pretty useless. The more I think about it, the more I like this one compared to that one. Mainly because this has so many other benefits than just supporting lists/dicts with embedded arguments.
The main questions is, when could this be implemented. RF 3.2 starts to be so much overdue that this issue cannot fit it unless someone else is interested to look at implementing it. RF 3.3. is possible, but also there are so many other high priority features that external help would be highly appreciated.
We have PR #3385 implementing this so I'll add this tentatively to RF 3.2 scope. That release is so much overdue that I cannot make promises will this issue make into it, though.
Unfortunately this is too much work for the already overdue RF 3.2.
I think expected type is only needed when variable is receiving a value. This is special case.
I propose that the type should be outside of the body. So we extend current syntax instead of making a rather backwards incompatible change
Like this ${mynumber}:int 3 and not ${mynumber:int} 3
And ignore type info on embedded keyword var syntax or escape it.
I'd prefer the ${name: type} syntax over ${name}: type for these reasons:
- Looks better to my eye.
- Easier to implement as the logic to find variables doesn't change.
- Allows using types with embedded arguments. This is pretty important.
- Works well also when assigning variable based on kw return value.
As I already commented above, I don't consider backwards compatibility problems that big. Probably best to allow still using colons in names like ${foo:bar} but perhaps that should be deprecated. Alternatively we could require the separator to be : i.e. a colon followed by a space.
This conversion is also a bit different from static typing although the syntax points to that.
Would this converter be a property of the variable or an external thing? How should each of these behave?
*** Variables ***
${myvar: int} 3
*** Keywords ***
Doing something
${myvar} = Calling Library Keyword
Doing something differently
${myvar: str} = Calling Batman
Doing the usual
${myvar: int} = Calling Mom
It would just be a converter. Creating a variable like ${x:int} would mean converting the value to an integer but ${x} could later be assigned to other type.
After discussing Custom Converters with Pekka, We came to the conclusion that in fact ${mynumber}:int 3 would be better.
*** Keywords ***
Kywrd
[Arguments] ${name}: str ${password}: str = 123456 ${remember}: bool = ${True}
Log ${name}:${password} - ${remember}
The advantages:
- Better readability, because the variable names do not change
- Easier to integrate into IDEs regarding refactoring and finding variables.
Maybe ${var: type} could be a fallback/alternative implementation,
like Dictionaries ${dict.key} or ${dict}[key] to support embedded arguments.
Imho Embedded arguments are not as important, because Default values do also not work for them...
Yeah, ${var}: type syntax has its benefits. Need to look at all pros and cons when we actually start to implement this. Due to the work needed to get all new syntax features done (RETURN, TRY/EXCEPT, WHILE, ...) it seems that this issue needs to be descoped from RF 5.0.
I'm slightly worried can we get this done in RF 7 timeline. This would be a nice enhancement so I keep it in the scope at least for now.
The typing syntax needs to be kept in mind when deciding about #4674. Assuming it's implement, the decision between ${name: type} and ${name}: type isn't that important because both would become $name: type if you omit curly braces.
This issue wasn't considered important enough, considering the required effort, for RF 7.