Test a python function in Robot Framework - python-2.7

I am a new user and I didn't find a solution for a doubt about the execution of my script, wrote in python, in Robot Framework.
The script works when I execute it on python compiler but when I execute the test case on Robot Framework, this error is showed:
===========================================================================
TestProvaPower
===========================================================================
TestPowerAngelo | FAIL |
No keyword with name 'power' found.
---------------------------------------------------------------------------
TestProvaPower | FAIL |
1 critical test, 0 passed, 1 failed
1 test total, 0 passed, 1 failed
===========================================================================
Output: c:\users\user\appdata\local\temp\RIDEjtznzw.d\output.xml
I think that this error is shown because it is necessary to pass the arguments and parameters.
Please, how can I pass these values in Robot Framework?
The test suite is:
** Settings **
Library ../../../../../Users/User/workspace/TestAngelo18.09/TestProva22.py
** Test Cases **
TestPowerAngelo
power base exponent
push ${base} ${exponent}
While my Python script is:
base = input("Insert base")
exponent =input("Insert exponent")
def power(base,exponent):
result=base**exponent
print "%d to the power of %d is %d" %(base,exponent,result)
power (base,exponent)

As part of your module definition, you are getting input from the user. When a module is being imported, you cannot use the standard input stream so an EOFError occurs. Below is a modified version of your library that is still testable via direct execution.
def power(base, exponent):
result = base**exponent
return result
if __name__ == '__main__':
base = input("Insert base")
exponent = input("Insert exponent")
result = power(base,exponent)
print "%d to the power of %d is %d" %(base, exponent, result)

Instead of using complex path in the Library import try setting python path with pybot e.g.
pybot --pythonpath /path/to/libs/where/py/file/is
And in the test suite file import it using just the name e.g. without the .py suffix.
Library TestProva22

RF treats arguments as strings by default. For literals, you can surround them with ${} or variables use Convert To Integer first. Something like this should work:
${result} = power ${2} ${4}
Should Be Equal As Integers ${result} 16

Related

Handling map function in python2 & python3

Recently i came across a question & confused with a possible solution,
code part is
// code part in result reader
result = map(int, input())
// consumer call
result_consumer(result)
its not about how do they work, the problem is when you are running in python2 it will raise an exception, on result fetching part, so result reader can handle the exception, but incase of python3 a map object is returned, so only consumer will be able to handle exception.
is there any solution keeping map function & handle the exception in python2 & python3
python3
>>> d = map(int, input())
1,2,3,a
>>> d
<map object at 0x7f70b11ee518>
>>>
python2
>>> d = map(int, input())
1,2,3,'a'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'a'
>>>
the behavior of map is not the only difference between python2 and python3, input is also difference, you need to keep in mind the basic differences between the two to make code compatible for both
python 3 vs python 2
map = itertools.imap
zip = itertools.izip
filter = itertools.ifilter
range = xrange
input = raw_input
so to make code for both, you can use alternatives like list comprehension that work the same for both, and for those that don't have easy alternatives, you can make new functions and/or use conditional renames, like for example
my_input = input
try:
raw_input
except NameError: #we are in python 3
my_input = lambda msj=None: eval(input(msj))
(or with your favorite way to check which version of python is in execution)
# code part in result reader
result = [ int(x) for x in my_input() ]
# consumer call
result_consumer(result)
that way your code do the same regardless of which version of python you run it.
But as jsbueno mentioned, eval and python2's input are dangerous so use the more secure raw_input or python3's input
try:
input = raw_input
except NameError: #we are in python 3
pass
(or with your favorite way to check which version of python is in execution)
then if your plan is to provide your input as 1,2,3 add an appropriate split
# code part in result reader
result = [ int(x) for x in input().split(",") ]
# consumer call
result_consumer(result)
If you always need the exception to occur at the same place you can always force the map object to yield its results by wrapping it in a list call:
result = list(map(int, input()))
If an error occurs in Python 2 it will be during the call to map while, in Python 3, the error is going to surface during the list call.
The slight downside is that in the case of Python 2 you'll create a new list. To avoid this you could alternatively branch based on sys.version and use the list only in Python 3 but that might be too tedious for you.
I usually use my own version of map in this situations to escape any possible problem may occur and it's
def my_map(func,some_list):
done = []
for item in some_list:
done.append( func(item) )
return done
and my own version of input too
def getinput(text):
import sys
ver = sys.version[0]
if ver=="3":
return input(text)
else:
return raw_input(text)
if you are working on a big project add them to a python file and import them any time you need like what I do.

Python on Raspberry Pi: results are only integers

I am using the following python code on the Raspberry Pi to collect an audio signal and output the volume. I can't understand why my output is only integer.
#!/usr/bin/env python
import alsaaudio as aa
import audioop
# Set up audio
data_in = aa.PCM(aa.PCM_CAPTURE, aa.PCM_NONBLOCK, 'hw:1')
data_in.setchannels(2)
data_in.setrate(44100)
data_in.setformat(aa.PCM_FORMAT_S16_LE)
data_in.setperiodsize(256)
while True:
# Read data from device
l,data = data_in.read()
if l:
# catch frame error
try:
max_vol=audioop.max(data,2)
scaled_vol = max_vol/4680
if scaled_vol==0:
print "vol 0"
else:
print scaled_vol
except audioop.error, e:
if e.message !="not a whole number of frames":
raise e
Also, I don't understand the syntax in this line:
l,data = data_in.read()
It's likely that it's reading in a byte. This line l,data = data_in.read() reads in a tuple (composed of l and data). Run the type() builtin function on those variables and see what you've got to work with.
Otherwise, look into the documentation for PCM Terminology and Concepts located within the documentation for the pyalsaaudio package, located here.

Pass integer input argument for Popen.communicate()

I am pretty new to python and I am stuck with something now. I am using python 2.7.
I am trying to automate a command in shell for which I wrote a python script. I have to input an integer value to the shell for which I am using Popen.communicate(input='2'). Though input is passed, it is passed as a string and the subprocess needs it as a numeric value. When I try to pass it as a numberic value like Popen.communicate(input=2) it throws the following error :
TypeError: 'int' object has no attribute '__getitem__'
So is there any way to send the input as a numeric value ??
Here is the code I use :
import sys
from subprocess import Popen, PIPE, STDOUT
cmd = ["sudo", "./sbt", "project java-examples", "run"]
proc = Popen(cmd, bufsize=4096, shell=False, stdout=PIPE, stdin=PIPE, stderr=STDOUT)
string = proc.communicate(input='2')
print string[0]
proc.stdin.close()
Edit :
Sorry that I didn't mentioned this at the first place.
My java application has multiple main classes hence the compiler ask which class to be executed, and I need to enter the same number every time,which is why I am trying to automate it. When I am passing a string value it throws numberformatexception.
Finally I found the solution for this.
Well the solution to this was pretty simple
when I changed
string = proc.communicate(input='2')
to
string = proc.communicate(input='2\n')
it worked fine.
The ./sbt process you are calling needs to be able to read a string and convert it into a integer. It is not possible to send native Python types to a child process with only Popen.
Another potential solution would be to serialize the data into JSON, YAML, XML, python pickle format, etc - choose your standard. However as you are passing a single integer this would seem very much overkill.
Pipes are byte streams in Unix. There is no numeric input -- there is only "string" input (there are no numbers or anything else -- there are only bytes).
If your child java process expects a number as its ascii representation then .communicate(input='2') is correct already if the subprocess reads from stdin (System.in). If the java process reads from the console directly (System.console().readLine()) then stdin=PIPE won't work (you might need to provide a pty in this case e.g., using pexpect).
For example, to read an integer from stdin and print it back in Java:
import java.util.Scanner;
public class ReadInteger
{
public static void main(String args[])
{
Scanner in = new Scanner(System.in);
int i = in.nextInt();
System.out.println("got " + i);
}
}
To pass an integer from Python process to the Java process via a pipe:
#!/usr/bin/env python2
from subprocess import Popen, PIPE
p = Popen(['java', '-ea', 'ReadInteger'], stdin=PIPE, stdout=PIPE)
output = p.communicate(input='2')[0]
print 'from java {' + output.strip() + '}'
It works (the output is from java {got 2}).
It stops working if the child process reads from the console instead:
public class ReadIntegerConsole
{
public static void main(String args[])
{
int i = Integer.parseInt(System.console().readLine());
System.out.println("got " + i);
}
}
The same python script leads to NullPointerException (and the output is from java {}) because System.console() is null here (stdin is redirected). It works if we provide a pseudo-tty:
#!/usr/bin/env python2
import pexpect # $ pip install pexpect
child = pexpect.spawn('java -ea ReadIntegerConsole')
child.setecho(False)
child.sendline('2')
child.expect(pexpect.EOF)
child.close()
print "from java {" + child.before.strip() + "}"
It works (the output is from java {got 2}).

Use Python command line argument as function names and function values

Related to this question Command line arguments in python.
With the SYS module, how can I use a command line argument as a function name and function value, within my code - without importing some other module?
I'd like a solution that uses sys only. Also, please no variable-length params answers. Those are confusing. Assume that just the function name and one function variable are specified at the command line.
import sys
def reversal(aaa): return aaa[::-1]
a = sys.argv[1]
b = sys.argv[2]
print a(b)
At the command line
cpu_location$ python blah.py reversal 'abcdefg'
Traceback (most recent call last):
File "blah.py", line 8, in <module>
print a(b)
TypeError: 'str' object is not callable
I want to know how to make sys.argv[1] be considered a function name, thereby calling the function I have defined.
The other posts I see on this are a mash up of:
- dealing with C/C++ and adding some other module
- not using sys at all
- using the argv items as values for functions, and names of other files, instead of names of functions
Better than the eval solution would be:
a = globals()[sys.argv[1]]
a(b)
globals() returns a dictionary mapping global variables names to those global variables. So globals()['reversal'] evaluates to the reversal function.
It's safer than the eval function. With your approach you could do something like:
python blah.py 'lambda x: x+"hi"' foobar
Which would print foobarhi, which is unexpected because that's not a function name.
2 hours later, I find the answer. I think it's worth it to post it here in a very simple fashion.
Basiclaly there is no "function" data type in Python, but someone did mention a function eval, which is built-in. Execute python commands passed as strings in command line using python -c (No -c is needed for my own example)
The solution, is to change
a = sys.argv[1]
to
a = eval(sys.argv[1])
This will make the passed in word, reversal, be evaluated. It will evaluate to a function. Then the a(b) call will be a perfect call of a function on a string, like how it's defined. Output will be like:
cpu_location$ python blah.py reversal unquoted
detouqnu
cpu_location$ python blah.py reversal 'withquotes'
setouqhtiw
use google module: fire
pip install fire
Here's a simple example:
import fire
class Calculator(object):
"""A simple calculator class."""
def double(self, number):
return 2 * number
if __name__ == '__main__':
fire.Fire(Calculator)
Then, from the command line, you can run:
python calculator.py double 10 # 20
python calculator.py double --number=15 # 30

Evaluating code after parsing it

I'm trying to create a tool written in Python that executes R scripts (from files), injecting values into variables before executing them and reading output variables after that.
The rinterface documentation mentions the parse function, but there is no indication about how to execute the result. The C interface contains an eval function but it doesn't seem available in Python.
Here's a very basic example of what I want to do :
import rpy2.rinterface as ri
ri.initr()
with open('script.r', 'r') as myFile:
script = myFile.read()
expr = ri.parse(script)
# prepare
ri.globalenv['input'] = ri.IntSexpVector((1, 2, 3, 4))
# execute
#??????????????????
# what to do here ?
#??????????????????
# fetch results
# The script is supposed to store results into a global var named 'output'
result = ri.globalenv['output']
Thanks
There are several ways.
One is:
from rpy2.robjects.packages import importr
base = importr('base')
base.eval(expr)