Accessing run-time Robot Framework info in extensions

127 views
Skip to first unread message

Martin Taylor

unread,
Dec 1, 2008, 10:01:04 AM12/1/08
to robotframework-users
I'm working on an extension for Robot Framework that provides support
for the Open Source "AutoIt" Windows automation tool. When certain
methods fail, I'd like to capture a screenshot before raising the
failure exception to Robot Framework. This is basically working, but
my AutoItLibrary extension doesn't know where Robot Framework has been
told to put the output (via command line --outputdir). Is there some
way to get at this run-time information from Robot Framework from
inside an extension library Python module?

Thanks for any tips and suggestions,
Martin

Pekka Klärck

unread,
Dec 1, 2008, 10:42:18 AM12/1/08
to c.marti...@gmail.com, robotframework-users
2008/12/1 Martin Taylor <c.marti...@gmail.com>:

>
> I'm working on an extension for Robot Framework that provides support
> for the Open Source "AutoIt" Windows automation tool.

This sounds interesting. Having a library for AutoIT has been on our
todo-list for ages. We actually implemented a simple library for one
team before Robot Framework was open sourced and have that code
somewhere. Might be a good idea to discuss can we share work somehow.
For example, how have you planned to handle the communication between
AutoIT and Robot? (If the discussion gets very technical, it might be
better to move it to the developers mailing list.)

> When certain
> methods fail, I'd like to capture a screenshot before raising the
> failure exception to Robot Framework. This is basically working, but
> my AutoItLibrary extension doesn't know where Robot Framework has been
> told to put the output (via command line --outputdir). Is there some
> way to get at this run-time information from Robot Framework from
> inside an extension library Python module?

One possibility is using automatic variables [1] in the test data.
Variables are available through Robot's internal modules too, and
below is roughly how SeleniumLibrary gets --outputdir information.

from robot.running import NAMESPACES

def some_keyword():
outdir = NAMESPACES.current.variables['${OUTPUTDIR}']


I can't promise that this API is stable between major releases,
though, but I just submitted an issue [2] about a documented and
stable API. In the meantime the above approach is probably the best,
but it's a good idea to monitor the new issue (e.g. by adding a star
to it) and test the library with betas and release candidates when we
get closer to 2.1 release.

[1] http://robotframework.googlecode.com/svn/trunk/doc/userguide/RobotFrameworkUserGuide.html#automatic-variables
[2] http://code.google.com/p/robotframework/issues/detail?id=167

Cheers,
.peke

Pekka Klärck

unread,
Dec 1, 2008, 3:55:36 PM12/1/08
to Taylor, Martin, robotframework-users
[ Added the users list back to Cc since most of this reply is
generally interesting. ]

2008/12/1 Taylor, Martin <cmta...@ti.com>:
> Hi Pekka,
>
> That's an interesting technique that I might try. Since I posted I also thought of another possibility: Make my extension library take an initialization parameter for "OutputDir" and pass it ${OUTPUTDIR} in the library import line. I haven't tried it yet. Do you think that would work?
>

That's exactly how the Screenshot library [1] sets the directory where
to save its outputs. It has system tempdir as a default, but it could
actually use ${OUTPUTDIR} as a default too similarly as
SeleniumLibrary does it. You may also want to take a look how
Screenshot library logs the image so that it is actually visible in
the log (see the log_screenshot method). See Logging information
section [2] from the User Guide for more details.

[1] http://code.google.com/p/robotframework/wiki/ScreenshotLibrary
[2] http://robotframework.googlecode.com/svn/trunk/doc/userguide/RobotFrameworkUserGuide.html#logging-information


> If you don't mind me asking another question, I've been having a lot of trouble understanding how to use lists in Robot Framework.

Sure, lists can be a bit tricky.

> Here's two examples of the kind of problem I'm having:
>
> 1. I have a keyword that returns ["PASS", [<list of stuff>]]. In the RF test I have
>
> ${RC} | @{PIDList} = | MyKeyword |
>
> The log shows:
> 10:35:02.890 INFO ${RC} = PASS
> 10:35:02.890 INFO @{PIDList} = [ ['0C100018280B10C4627F8D51F3E'] ]
>
> So for some reason its wrapped my returned list in another list.

This ought to work if you would return just a flat list instead of a
nested list. For example ['rc', 'pid1', 'pid2', pid3']. If you need to
return more complicated values you may also consider returning an
object and using its attributes with "extended variable syntax". [3]

[3] http://robotframework.googlecode.com/svn/trunk/doc/userguide/RobotFrameworkUserGuide.html#extended-variable-syntax


> If I try this instead:
>
> ${RC} | ${PIDList} = | MyKeyword |
>
> Then the log shows:
>
> 10:39:21.286 INFO ${RC} = PASS
> 10:39:21.302 INFO ${PIDList} = [ 0C100018280B10C4627F8D51F3E ]
>
> But RF doesn't know that ${PIDList} is a list, so when I try this:
>
> FOR ${PID} IN [ ${PIDList} ]
>
> I get:
>
> VAR: ${PID} = ['0C100018280B10C4627F8D51F3E']

Now ${PIDList} contains a list but it is still a scalar variable [4].
You needed to convert it to a list variable first using BuiltIn 'Set
Variable' keyword, but it's probably better to change the returned
list into a flat list instead.

[4] http://robotframework.googlecode.com/svn/trunk/doc/userguide/RobotFrameworkUserGuide.html#variable-types


> So I have to do the same workaround and fake it with:
>
> KEYWORD: ${DevPID} = BuiltIn.Evaluate ${PID}[0]

You could use the first item of the list anywhere in the test data
like ${PID[0]}. This again uses the extended variable syntax [3].

> Please advise me of any better approach to dealing with the return and use of nested lists like this.

As I already wrote, the simplest solution is returning a nested list,
and in more complex situation it's often better to return custom
objects.


> 2. I'm trying to set a list variable in a Python variables file.
>
> MYLIST = ["SingleItem"]
>
> When I try to use this in RF like this:
>
> Variables
> @{FullList} | @{CommonList} | ${MYLIST}
>
> I get
> ["FullListItem1", "FullListItem2", ["SingleItem"]]
>
> And if I try this:
>
> @{FullList} | @{CommonList} | @{MYLIST}
>
> Then RF says it doesn't know about @{MYLIST}.
>
> Again any advice on how to deal with creating and working with lists to/from scalars would be much appreciated.

You a scalar variable with a list as its value. You need to prefix the
name with 'LIST__' to make it a list variable. [5]

[5] http://robotframework.googlecode.com/svn/trunk/doc/userguide/RobotFrameworkUserGuide.html#creating-variables-directly


> Thanks very much,
>
> Martin

No problem!

.peke

Pekka Klärck

unread,
Dec 12, 2008, 3:27:11 AM12/12/08
to c.marti...@gmail.com, robotframework-users
2008/12/1 Pekka Klärck <pe...@iki.fi>:
> 2008/12/1 Martin Taylor <c.marti...@gmail.com>:

>>
>> When certain
>> methods fail, I'd like to capture a screenshot before raising the
>> failure exception to Robot Framework. This is basically working, but
>> my AutoItLibrary extension doesn't know where Robot Framework has been
>> told to put the output (via command line --outputdir). Is there some
>> way to get at this run-time information from Robot Framework from
>> inside an extension library Python module?
>
> One possibility is using automatic variables [1] in the test data.
> Variables are available through Robot's internal modules too, and
> below is roughly how SeleniumLibrary gets --outputdir information.
>
> from robot.running import NAMESPACES
>
> def some_keyword():
> outdir = NAMESPACES.current.variables['${OUTPUTDIR}']
>
>
> I can't promise that this API is stable between major releases,
> though, but I just submitted an issue [2] about a documented and
> stable API. In the meantime the above approach is probably the best,
> but it's a good idea to monitor the new issue (e.g. by adding a star
> to it) and test the library with betas and release candidates when we
> get closer to 2.1 release.
>
> [1] http://robotframework.googlecode.com/svn/trunk/doc/userguide/RobotFrameworkUserGuide.html#automatic-variables
> [2] http://code.google.com/p/robotframework/issues/detail?id=167

There's actually a better and more stable way to get this done.
There's already a built-in keywords 'Replace Variables' which replaces
variables in the given text with their values, and the method
implementing it can be used by other libraries as illustrated below.

from robot.libraries.BuiltIn import BuiltIn

def some_keyword():
outdir = BuiltIn().replace_variables('${OUTPUTDIR}')


A small limitation is that replace_variables currently always returns
the value as a string, but I already fixed that so and in the next
version the value can be anything. In the above example that doesn't
really matter since ${OUTPUTDIR} is always a string.

I updated this information to the issue 167 [2] already. It might be
that this keyword is enough as an API to variables, and since most
interesting settings are available as variables we may not need a
separate API for that.

Cheers,
.peke

Reply all
Reply to author
Forward
0 new messages