How to handle a named parameter and #keyword in robotframework - robotframework

I use the Robot framework with Python and Linux.
I don't know how to use the optional named parameter b and c in the decorator. Can somebody explain?
See example below:
#keyword('Starting a "${a}" b "${b}"?? c "${c}"??')
def Start(self, a, b='', c=''):
foo

The way I understand your question, you're trying to create a keyword with embedded arguments, which would have default args - and this is not allowed, doc link, the last paragraph in Basic Syntax.
What you could do is to leave up for the caller to pass on "the default" values; e.g.:
#keyword('Starting a "${a}" b "${b}" c "${c}"')
def Start(self, a, b, c):
# just work with a, b, c, they *always* have _some_ value when called from RF
foo
# later on, used in Robotframework code:
Starting a "" b "" c ""
When called like this ^, the variables a, b and c will be passed to the python function as empty strings - RF defaults arguments to string type, meaning this code inside the function will work in this case:
assert a == '' # will pass when called with no value for a
assert type(b) == str # this will always work, regardless did b (or a, or c) have a value set in the call, or not

Related

Refer to struct fields without dot notation (in Julia)

In Julia I've defined a type and I need to write some functions that work with the fields of that type. Some of the functions contain complicated formulas and it gets messy to use the field access dot notation all over the place. So I end up putting the field values into local variables to improve readability. It works fine, but is there some clever way to avoid having to type out all the a=foo.a lines or to have Julia parse a as foo.a etc?
struct Foo
a::Real
b::Real
c::Real
end
# this gets hard to read
function bar(foo::Foo)
foo.a + foo.b + foo.c + foo.a*foo.b - foo.b*foo.c
end
# this is better
function bar(foo::Foo)
a = foo.a
b = foo.b
c = foo.c
a + b + c + a*b - b*c
end
# this would be great
function bar(foo::Foo)
something clever
a + b + c + a*b - b*c
end
Because Julia generally encourages the use of generalized interfaces to interact with fields rather than accessing the fields directly, a fairly natural way of accomplishing this would be unpacking via iteration. In Julia, objects can be "unpacked" into multiple variables by iteration:
julia> x, y = [1, 2, 3]
3-element Array{Int64,1}:
1
2
3
julia> x
1
julia> y
2
We can implement such an iteration protocol for a custom object, like Foo. In v0.7, this would look like:
Base.iterate(foo::Foo, state = 1) = state > 3 ? nothing : (getfield(foo, state), state + 1)
Note that 3 is hardcoded (based on the number of fields in Foo) and could be replaced with fieldcount(Foo). Now, you can simply "unpack" an instance of Foo as follows:
julia> a, b, c = Foo("one", 2.0, 3)
Foo("one", 2.0, 3)
julia> a
"one"
julia> b
2.0
julia> c
3
This could be the "something clever" at the beginning of your function. Additionally, as of v0.7, you can unpack the fields in the function argument itself:
function bar((a, b, c)::Foo)
a + b + c + a*b - b*c
end
Although this does require that you mention the field names again, it comes with two potential advantages:
In the case that your struct is refactored and the fields are renamed, all code accessing the fields will remain intact (as long as the field order doesn't change or the iterate implementation is changed to reflect the new object internals).
Longer field names can be abbreviated. (i.e. rather than using the full apples field name, you can opt to use a.)
If it's important that the field names not be repeated, you could define a macro to generate the required variables (a = foo.a; b = foo.b; c = foo.c); however, this would likely be more confusing for the readers of your code and lack the advantages listed above.
As of Julia 1.6, the macros in this package look relevant: https://github.com/mauro3/UnPack.jl.
The syntax would look like:
function bar(foo::Foo)
# something clever!
#unpack a, b, c = f
a + b + c + a*b - b*c
end
In Julia 1.7, it looks like this feature will be added with the syntax
function bar(foo::Foo)
# something clever!
(; a, b, c) = f
a + b + c + a*b - b*c
end
Here is the merged pull request: https://github.com/JuliaLang/julia/pull/39285

Understanding how to pass macro arguments to a program in Stata

I am currently writing a short program to print the global macro variables of the current Stata session.
I cannot understand the outcome of the following piece of code:
macro drop _all
global glob0: all globals
cap program drop print_globals
program define print_globals
args start_globs
di "$glob0"
di "`start_globs'"
end
print_globals $glob0
The outcome of this is:
S_level S_ADO S_StataMP S_StataSE S_FLAVOR S_OS S_OSDTL S_MACH
S_level
Why am I not passing to start globs the entire information contained in glob0?
Your args statement assigns only the first argument supplied to the program to a local macro; if there are other arguments they are ignored.
The essence of the matter is whether double quotes are used to bind what is supplied into one argument.
Whether you supply an argument as a global or a local is immaterial: globals and locals mentioned on the command line are evaluated before the program even runs and are not seen as such; only their contents are passed to the program.
Define this simpler program and run through the possibilities:
program showfirstarg
args first
di "`first'"
end
global G "A B C D E"
local L "A B C D E"
showfirstarg $G
showfirstarg "$G"
showfirstarg `L'
showfirstarg "`L'"
Results in turn:
. showfirstarg $G
A
. showfirstarg "$G"
A B C D E
. showfirstarg `L'
A
. showfirstarg "`L'"
A B C D E
In order to print the content of the program argument as intended, one must use compound quotes:
print_globals `" ${glob0} "'
and not print_globals ${glob0}.
To see this, consider the following example:
local A "a b c d e"
global B "a b c d e"
cap program drop print_prog
program define print_prog
args loc_input
di "print global: $B"
di "print local: `loc_input'"
end
print_prog `A'
print_prog `" `A' "' // prints both A and B as initially intended
The confusion here is given by the fact that B is printed as intended without having to use compound quotes, whereas the same does not apply for the local macro A when it's passed as argument to the program.
In fact, as highligted in the comments below, in the latter case only the first element is passed as program argument (a in the example).
By using compound quotes we supply a b c d e as a single argument and the final result is the one wanted.

Groovy map creation, use value assigned to previous key

Is there a way to use the values assigned to the previous key in map, for eg:
def x = [
a: someList.sum(),
b: anotherList.sum(),
c: someList.sum() / anotherList.sum()
]
I want the value of 'c' to be a/b, so is there a shortcut so that I don't have to recompute the sums while computing 'c'
In order to use previously-added key/values to compute new key/values, you must be able to control the order in which the keys/values are added. I know that's obvious, but what may not be obvious is that Groovy Map declarations do not take order into account. For example, if you write this...
def x = [
a: 8,
b: 2,
c: a / b
]
..., when evaluating the expression for the value of key c, Groovy will attempt to access a variable or property named a, which will fail because the variable/property does not exist. However, you can take advantage of that property lookup and do this:
def x = [:].with {
a = 8
b = 2
c = a / b
delegate
}
You start by creating an empty Map. Then, use with(Closure) to execute putAt() and get() against the Map. The example above is the equivalent to...
def x = [:].with {
putAt('a', 8)
putAt('b', 2)
putAt('c', get('a') / get('b'))
delegate
}
Finally, return the Map itself so that it's assigned to x.

Pass function arguments into Julia non-interactively

I have a Julia function in a file. Let's say it is the below. Now I want to pass arguments into this function. I tried doing
julia filename.jl randmatstat(5)
but this gives an error that '(' token is unexpected. Not sure what the solution would be. I am also a little torn on if there is a main function / how to write a full solution using Julia. For example what is the starting / entry point of a Julia Program?
function randmatstat(t)
n = 5
v = zeros(t)
w = zeros(t)
for i = 1:t
a = randn(n,n)
b = randn(n,n)
c = randn(n,n)
d = randn(n,n)
P = [a b c d]
Q = [a b; c d]
v[i] = trace((P.'*P)^4)
w[i] = trace((Q.'*Q)^4)
end
std(v)/mean(v), std(w)/mean(w)
end
Julia doesn't have an "entry point" as such.
When you call julia myscript.jl from the terminal, you're essentially asking julia to execute the script and exit. As such, it needs to be a script. If all you have in your script is a function definition, then it won't do much unless you later call that function from your script.
As for arguments, if you call julia myscript.jl 1 2 3 4, all the remaining arguments (i.e. in this case, 1, 2, 3 and 4) become an array of strings with the special name ARGS. You can use this special variable to access the input arguments.
e.g. if you have a julia script which simply says:
# in julia mytest.jl
show(ARGS)
Then calling this from the linux terminal will give this result:
<bashprompt> $ julia mytest.jl 1 two "three and four"
UTF8String["1","two","three and four"]
EDIT: So, from what I understand from your program, you probably want to do something like this (note: in julia, the function needs to be defined before it's called).
# in file myscript.jl
function randmatstat(t)
n = 5
v = zeros(t)
w = zeros(t)
for i = 1:t
a = randn(n,n)
b = randn(n,n)
c = randn(n,n)
d = randn(n,n)
P = [a b c d]
Q = [a b; c d]
v[i] = trace((P.'*P)^4)
w[i] = trace((Q.'*Q)^4)
end
std(v)/mean(v), std(w)/mean(w)
end
t = parse(Int64, ARGS[1])
(a,b) = randmatstat(t)
print("a is $a, and b is $b\n")
And then call this from your linux terminal like so:
julia myscript.jl 5
You can try running like so:
julia -L filename.jl -E 'randmatstat(5)'
Add the following to your Julia file:
### original file
function randmatstat...
...
end
### new stuff
if length(ARGS)>0
ret = eval(parse(join(ARGS," ")))
end
println(ret)
Now, you can run:
julia filename.jl "randmatstat(5)"
As attempted originally. Note the additional quotes added to make sure the parenthesis don't mess up the command.
Explanation: The ARGS variable is defined by Julia to hold the parameters to the command running the file. Since Julia is an interpreter, we can join these parameters to a string, parse it as Julia code, run it and print the result (the code corresponds to this description).

Check if an argument is a dictionary or not in Tcl

I want have a proc which does something if its' argument is a Tcl 8.5 and above dictionary or not.
I could not find anything straightforward from Tcl dict command.
The code which I could get working is:
proc dict? {dicty} {
expr { [catch { dict info $dicty } ] ? 0 : 1 }
}
Is there anything w/o using catch, something built in?Thanks.
You can test if a value is a dictionary by seeing if it is a list and if it has an even number of elements; all even length lists may be used as dictionaries (though many are naturally not canonical dictionaries because of things like duplicate keys).
proc is-dict {value} {
return [expr {[string is list $value] && ([llength $value]&1) == 0}]
}
You can peek at the actual type in Tcl 8.6 with tcl::unsupported::representation but that's not advised because things like literals are converted to dictionaries on the fly. The following is legal, shows what you can do, and shows the limitations (
% set value {b c d e}
b c d e
% tcl::unsupported::representation $value
value is a pure string with a refcount of 4, object pointer at 0x1010072e0, string representation "b c d e"
% dict size $value
2
% tcl::unsupported::representation $value
value is a dict with a refcount of 4, object pointer at 0x1010072e0, internal representation 0x10180fd10:0x0, string representation "b c d e"
% dict set value f g;tcl::unsupported::representation $value
value is a dict with a refcount of 2, object pointer at 0x1008f00c0, internal representation 0x10101eb10:0x0, no string representation
% string length $value
11
% tcl::unsupported::representation $value
value is a string with a refcount of 2, object pointer at 0x1008f00c0, internal representation 0x100901890:0x0, string representation "b c d e f g"
% dict size $value;tcl::unsupported::representation $value
value is a dict with a refcount of 2, object pointer at 0x1008f00c0, internal representation 0x1008c7510:0x0, string representation "b c d e f g"
As you can see, types are a bit slippery in Tcl (by design) so you're strongly advised to not rely on them at all.
Your approach is flawed because Tcl has dynamic type system where the actual type of a value is able to morph dynamically and depends on the commands applied to it—observe:
$ tclsh
% info pa
8.5.11
% dict info {a b}
1 entries in table, 4 buckets
number of buckets with 0 entries: 3
number of buckets with 1 entries: 1
number of buckets with 2 entries: 0
number of buckets with 3 entries: 0
number of buckets with 4 entries: 0
number of buckets with 5 entries: 0
number of buckets with 6 entries: 0
number of buckets with 7 entries: 0
number of buckets with 8 entries: 0
number of buckets with 9 entries: 0
number of buckets with 10 or more entries: 0
average search distance for entry: 1.0
% llength {a b}
2
% string len {a b}
3
%
As you can see, the same value {a b} is a dictionary, a list and a string: in each case, the value acquires its "real" type in the very moment a Tcl command expecting a value of certain type converts the "default" type of the value, which is string, to the one the command operates on.
You should understand by now that trying to make a call dict? {a b} has little sence as the value {a b} is a perfect dict as well as a perfect list as well as a perfect string, and it could be, say, a perfect tuple if there are custom commands in the current interpreter working on tuples (lists of fixed length).
Hence the real approach you should take is to just blindly use dict command on those values passed to your commands you expect to contain dictionaries. If a user will manage to pass to your command something which is not interpretable as a dictionary, the dict command will fail, and that's a good thing to do as such an error is not really recoverable (it's a programming error).
Any attempt to count on a value's specific type is going again the grain of the very idea of the Tcl's implicit/dynamic typing. It's even true for the Tcl C API.
If you really meant to ask how to be sure the current Tcl version supports dict command, and not about the type of a particular value, test the Tcl's version somewhere at startup and save this as a flag, like this:
set hasDicts [expr {[package vcompare [info tclversion] 8.5] >= 0}]
But note that your code relying on the hasDicts value is now in some gray zone because if the user is not supplying you values you process with the dict command then what command you use to process them?
Please also note that the dict command can be added to a Tcl 8.4 interpreter in the form of the loadable module (see this).

Resources