robotframework icon indicating copy to clipboard operation
robotframework copied to clipboard

Each `*** Variable ***` evaluation is done only once

Open stdedos opened this issue 4 years ago • 9 comments

*** Settings ***
Documentation   Variables evaluation
Suite Setup     Log             slowMo=${SLOWMO_VAL}

*** Variables ***
${SLOWMO_VAL}   0.0625
${SLOWMO_VAL}   0

*** Test Cases ***
A
    Sleep   0

image

vs

*** Settings ***
Documentation   Variables evaluation
Suite Setup     Log             slowMo=${SLOWMO_VAL}

*** Variables ***
${SLOWMO_VAL}   0
${SLOWMO_VAL}   0.0625

*** Test Cases ***
A
    Sleep   0

image

Use case: I don't know (or don't remember) if there is a shorthand ala bash for "if variable is empty then replace with ..." functionality (i.e. ${SLOWMO:-0}) in Robot Framework.

None of the:

  • ${SLOWMO}
  • $SLOWMO
  • ${{ $SLOWMO or 0 }}

seem to work if I remove/comment out all the *** Variables *** (feel free to expand the list)

stdedos avatar May 19 '21 20:05 stdedos

Do I get it right that you get slowMo=0.0625 regardless the order of how you declare ${SLOWMO_VAL}? I tested this locally and your latter example gave me slowMo=0.

With "if variable is empty" do you mean variable having an empty string or possibly None as value or the variable not being defined at all?

Do you have a more concrete example about what you actually are trying to do?

pekkaklarck avatar May 24 '21 08:05 pekkaklarck

Do I get it right that you get slowMo=0.0625 regardless the order of how you declare ${SLOWMO_VAL}? I tested this locally and your latter example gave me slowMo=0.

Hmm - seems the screenshots are a bit off from what I am reporting 😅. I'll run them again. Indeed that's the case - the first declaration takes precedence (i.e. second is slowMo=0).

With "if variable is empty" do you mean variable having an empty string or possibly None as value or the variable not being defined at all?

Yes

Do you have a more concrete example about what you actually are trying to do?

I am trying to have a quick-and-dirty way of configuring slowMo https://marketsquare.github.io/robotframework-browser/Browser.html#New%20Browser.

  • My initial thought was to replicate the bash behavior of ${slowmo:-default}; it failed (the list above)
  • Then, I thought I will define the variable twice - latter declaration takes precedence; it failed too. (the code examples)
  • I know of https://robotframework.org/robotframework/latest/libraries/BuiltIn.html#Get%20Variable%20Value; but that would mean I need to extract a one-liner Suite Setup to a separate keyword and spend about 3-4 lines. It is of course okay to tell me "that's the way it's happening right now"; I was wondering if there are other people that think this would be good/wanted.

stdedos avatar May 24 '21 09:05 stdedos

I think the reason that first variable declaration "wins" is that it makes handling variables in resource files easier. Variables in the test case are parsed first, and thus variables in possible resource files cannot overwrite them. This whole design is actually pretty bad, we should have separate variable namespaces for resource files instead of having all variables in one store. I hope we get all that rewritten sometime in the future and then this could change. Anyway, I don't see much point in declaring same variable multiple times in one place and thus don't think it really matters which one of them is actually used.

pekkaklarck avatar May 25 '21 08:05 pekkaklarck

I don't see much point in declaring same variable multiple times in one place and thus don't think it really matters which one of them is actually used.

I don't see the point either, but this

*** Settings ***
Documentation   Variables evaluation
Suite Setup     Log             slowMo=${SLOWMO_VAL}

*** Variables ***
# ${SLOWMO_VAL}   0.0625

*** Test Cases ***
A
    Sleep   0

will result in an error 😕

stdedos avatar May 25 '21 08:05 stdedos

Being able to give a default value for a variable would be handy and such support was actually added to environment variables in RF 3.2 (#3382) using syntax %{NAME=default}. This syntax is safe because environment variable names cannot contain =, but Robot's normal variable names can contain it and always considering = a default value separator in this context would thus be backwards incompatible. I guess this kind of algorithm would work, though:

  1. Always first try finding a variable with the "full" name. For example, with ${x=y} use x=y.
  2. If there's no match and the name contains =, try finding with the "name part". For example, with ${x=y} use x.
  3. If there's no match, return the default value. For example, with ${x=y} return y.

pekkaklarck avatar May 25 '21 08:05 pekkaklarck

The current way to handle this situation is creating the variable so that it has the default value set. For example,

*** Variables ***
${SLOWMO_VAL}    0

Then that value can be overridden fro the CLI using --variable. The value can also be altered in the data, for example, like

*** Variables ***
#${SLOWMO_VAL}    0
${SLOWMO_VAL}    0.0625

Although this works fine, being able to specify the default value where the variable is used would be more convenient.

pekkaklarck avatar May 25 '21 08:05 pekkaklarck

If you @stdedos think being able to specify default values using ${NAME=default} syntax would be a good idea, please submit a separate issue about that. We could get it added already in RF 4.1 (at least if you are interested to help with a PR) or latest in RF 5.0.

pekkaklarck avatar May 25 '21 08:05 pekkaklarck

  1. Always first try finding a variable with the "full" name. For example, with ${x=y} use x=y.

I'd never use = anyway in a variable myself (unless somehow I have typed it inadvertently). If you/others don't object with the idea, LGTM.

stdedos avatar May 25 '21 08:05 stdedos

I doubt = is too commonly used in variable names, but we still cannot make it a special character without deprecating it or otherwise handling it gracefully. If we select the deprecation way, then we could earliest deprecate it in RF 4.1 and take the new syntax into use in RF 5.0. The algorithm I proposed above ought to work well so that this functionality could be introduced already in RF 4.1. Then we could consider deprecating using = for other purposes to make the syntax simpler.

pekkaklarck avatar May 25 '21 10:05 pekkaklarck