I have a keyword in robot framework; it takes an argument, performs some process on it and returns it after all:
My Keyword Name
[Arguments] ${arg}
# Some process on ${arg}
[Return] ${arg}
So it would be the usage:
${x} = My Keyword Name ${x}
Which implies that I gave the old value of ${x} to the keyword and it returned me the new value of it.
I want to make a call by reference on My Keyword Name, so I don't need to use an assignment for setting new value for ${x}. I have read the BuiltIn and UserGuide,
but there was no line about this subject. Can anyone help me on this?
If ${x} is a mutable type such as a list or dictionary, you can pass the object itself. If it represents a scalar value such as a string or int, you can't do what you want. Your only choice is to return the new value and re-assign it to the original variable.
It will work if you initialize the variable as
My Keyword Name
[Arguments] ${arg}
${arg} = Set Variable 56
[Return] ${arg}
Test
Log To Console \n\nin Test
${x} = Set Variable 0
${x} = My Keyword Name ${x}
Log To Console ${x}
Or
Can you explore whether you can make use of Set Global Variable or Set Test Variable?
I'd spent some time before i got the solution!
* Variables
${someVar} initial value
* Test Cases
[Check reference]
Set this \${someVar} new value
Should Be Equal ${someVar} new value
* Keywords
Set this
[Arguments] ${varName} ${value}
Set Test Variable ${varName} ${value}
The point is in the magic "\" char :)
It actually comes down to mutable/immutable variables in python, and how they are passed to functions.
Details here in this answer, but in RF context it boils down to - you can change lists and dictionaries, and not strings and numbers (int, float). Example:
A testcase
Log To Console \n
${var}= Create List member1
Log To Console ${var}
Mutate The List ${var}
Log To Console ${var}
*** Keywords ***
Mutate The List
[Arguments] ${lst}
Append To List ${lst} new one
The output when ran would be:
==============================================================================
A testcase
['member1']
['member1', 'new one']
| PASS |
, e.g. the variable defined in the case got changed by a keyword. The same can be done with dictionaries.
If you reassign the variable in the function though, it will not change; e.g. with a keyword like this:
Mutate The Dict
[Arguments] ${lst}
${lst}= Create List fsf
Append To List ${lst} bogus
, the original variable ${var} will not be changed.
Why so? In short, in python variables are just identifiers ("names") to memory addresses; when you assign ${lst} to a new list, the variable now points to a new address in the memory, and further interactions don't change the original one.
Welp I just ran into the same issue, as I was using a Run Keyword If statement in a For Loop. Knowing that if I used a keyword that returns a value, robot framework freaks out.
So I just thought of this as a potential solution. It'll use my example. It does have redundancy, but thats because you just have to in this case.
***Keywords***
| Increment | [Arguments] | ${var} |
| | ${var} | Evaluate | ${var} + 1 |
| | Set Test Variable | ${var} | ${var} |
Usage:
| Increment | ${idx} |
| Set Test Variable | ${idx} | ${var}
Now I'm not saying this is the best solution, but if you run into the scenario that you have to return a value to a variable with a keyword, and you're inside a "Run Keyword If", this should allow you to circumvent the issue. I don't really like it that much, but it gets the job done.
Related
I can see two ways to define a global variable from a function in q.
Using ::
q){gv::10}[]
q)gv /- 10
Using set
q){`gv set 20}[]
q)gv /- 20
There is a catch with set i.e. if a global variable already has a symbol assigned to it, then the value which is assigned to global variable within the function is assigned to the symbol which is assigned to global variable.
q)gv:`t
q){gv set 20}[]
`t
q)gv
`t
q)t
20
Can someone please explain me which is the better way (set or ::) to define a global variable within a function and why is it better?
There is no "better" really - but set has the advantage of assigning to a variable name which is itself a variable (as you showed in your example).
I'm confused about your confusion in the last example though......if you wanted 20 to be assigned to a global called gv then you should put a backtick in front of gv, aka `gv set 20; and conversely if you wanted 20 to be assigned to the symbol/name that gv contains then don't use the backtick, aka gv set 20;
Final point to note is that you can also create globals in non-root directories/namespaces using a single colon assignment
q){.this.that:1;}[]
q)
q).this
| ::
that| 1
I am currently trying to create dynamic variable names based on the valuelabels of the passed Argument. Currently, I have something like this:
COMPUTE counter = 0.
APPLY DICTIONARY FROM *
/SOURCE VARIABLES = V601
/TARGET VARIABLES = counter.
DEFINE !macro1 (!POS !CMDEND).
STRING name (A20).
!DO !#i = 1 !TO 62
COMPUTE counter = #i
!IF (!POS !EQ !i)
!THEN
COMPUTE name = VALUELABEL(!POS)
COMPUTE !CONCAT('wasnot', name) = 1.
!ELSE
COMPUTE name = VALUELABEL(!counter).
COMPUTE !CONCAT('wasnot', name) = 0.
!IFEND
!DOEND
CROSSTABS v15 by !CONCAT('wasnot', name) /cells = column.
!ENDDEFINE.
The idea is, that for every unique value of V601 a flag variable will be created (e.g. "wasnotvaluelabel1"). This variable will either have value = 1 or 0 respectively. However, it seems that concat cannot be used the way I intended. I get these errors:
Error # 6843 in column 7. Text: !POS
The end of a macro expression occurred when an operand was expected.
Execution of this command stops.
Error # 6846 in column 7. Text: !POS
A macro expression includes an undefined macro variable or a macro operator
which is not valid within an expression.
Error # 6836 in column 12. Text: !EQ
In a macro expression, an operator was not preceded by an operand.
Error # 6846 in column 2. Text: !THEN
A macro expression includes an undefined macro variable or a macro operator
which is not valid within an expression.
Error # 6846 in column 28. Text: !POS
A macro expression includes an undefined macro variable or a macro operator
which is not valid within an expression.
Questions I have right now:
Is it even possible to generate dynamic names? I have tried
different attempts over the last hours but the SPSS macro "language"
seems very restricted.
Is there perhaps some other way to achieve this Task? It seems rather unconvenient.
Please note, working with the Python AddIn is sadly not an Option. I'm grateful for any received advice.
There is an extension command, SPSSINC CREATE DUMMIES, that will create all these dummy variables automatically. It's on the Transform menu. And it is implemented in Python.
Using Python you can easily read case data and do lots more.
Thanks for all the Help. In the end I did it with generating new syntax using Outfile.
Problem
I want to perform parametric variable evaluation. The to-be-evaluated variable name is constructed with a string concatenation - from a namespace part and a name part being defined in a variable. Example: env:$var, where the value of $var is, for instance "OS". However, while using the expression
${env:OS}
gives the expected value Windows_NT, the construct
$var="OS"
${env:$var}
is a null-valued expression.
Motivation
I'm not really intereseted in the value of environment variables (but this was the simplest example, I could find). What I really want, is to refer to the content of a file via the ${c:<filename>} construct. I want to perform several, conditional in-file string substitutions and, I'd like to use a construct similar to this:
<identify files in a foreach>
${c:<filename>} -replace 'this', 'that' > ${c:<new filename>}
To achieve this, I need <filename> to be a value of an iterator variable.
Question
If the value of $var is OS, what shall be at ..., if I expect the value of the following expression to be Windows_NT?
${env:...var...}
Use Get-ChildItem on the env: PSDrive and expand the Value of the result:
(ls env:$var).Value
Edit: As #PetSerAl suggested in the comments using Get-Content is a more elegant approach:
(cat env:$var)
I have a Keyword created in external python file which takes only one argument. When called in Ride, I get the error message (displayed below):
Keyword 'CustomUtilityLibrary.CUSTOM Get List Count' expected 1 argument, got 6.
This is the keyword definition
def CUSTOM_Get_List_Count(self, s1):
"""Returns the total number of elements in a list
"""
return len(s1)
This is likely due to an error in your test case. If robot is saying the function was called with six arguments, then it was called with six arguments.
It appears that your function takes a list as an argument. My guess is that you are calling it like this:
| | ${count}= | Get List Count | #{the_list}
The correct syntax for the last line in that example should use $ rather than #:
| | ${count}= | Get List Count | ${the_list}
The reason being, when you use #{some variable}, it expands the variable so that each element of the list is an argument. What you want instead is to pass the whole list as a single argument, and the syntax for that is to reference the list variable with $.
The robot framework user's guide has this to say about list variables:
When you use a list variable in test data, then the elements of the
list are inserted as new cells in the test data. Thus, if the list
variable contains two elements, the cell containing the list variable
is turned into two cells with the content of the list variable.
...
It is possible to use list variables as scalar variables containing
lists simply by replacing # with $
Can any one explain this format?
${name:-$devi}
Example:
"${1+"$#"}" will check for that first variable to be set , if not it will use that
command line argument.
What is the difference between :- and + between those variables?
${var:-val}
is the same as ${var} if var is set and non-null, otherwise it expands to val. This is used to specify a default value for a variable.
${var+val}
expands to nothing if var is unset, otherwise it expands to val. This is used to supply an alternate value for a variable.
"${1+"$#"}"
is a workaround for a bug in old shell versions. If you just wrote "$#", it would expand to "" when no arguments were supplied, instead of expanding to nothing; the script would then act as if a single, empty argument had been supplied. This syntax first checks whether $1 is set -- if there's no first argument, then there are obviously no arguments at all. If $1 is unset, it expands to nothing, otherwise it's safe to use "$#".
Most modern shell versions don't have this bug, so you can just write "$#" without the special check. I'm not sure if there are any other common use cases for the + construct in shell variable expansion.