libdoc error when using BuiltIn().get_library_instance() in constructor

1,691 views
Skip to first unread message

vbs

unread,
Mar 15, 2016, 12:10:06 PM3/15/16
to robotframework-users
Hi Guys,

I just discovered the amazing libdoc to generate keyword documentation for my test libraries. Sadly it turned out that libdoc throws an error when a library is using BuiltIn().get_library_instance in its constructor. Here a simplified test library to reproduce the problem:

from robot.libraries.BuiltIn import BuiltIn

class ScDocTestLibrary():
    def __init__(self):
        sc = BuiltIn().get_library_instance("ScConnector")
        self.inputDirectory = sc.getInputDir()

Gives me:
X:\robot-framework-test\testlibs\doc>python -m robot.libdoc ..\ScDocTestLibrary.py scdotest.html
Initializing test library 'ScDocTestLibrary' with no arguments failed: RobotNotRunningError: Cannot access execution context
Traceback (most recent call last):
  File "X:\robot-framework-test\testlibs\ScDocTestLibrary.py", line 11, in __init__
    sc = BuiltIn().get_library_instance("ScConnector")
  File "C:\Python27\lib\site-packages\robot\libraries\BuiltIn.py", line 2964, in get_library_instance
    return self._namespace.get_library_instance(name)
  File "C:\Python27\lib\site-packages\robot\libraries\BuiltIn.py", line 75, in _namespace
    return self._get_context().namespace
  File "C:\Python27\lib\site-packages\robot\libraries\BuiltIn.py", line 70, in _get_context
    raise RobotNotRunningError('Cannot access execution context')

Try --help for usage information.

X:\robot-framework-test\testlibs\doc>

I guess libdoc actually is trying to instantiate this class and fails cause "ScConnectorLibrary" is not loaded.

Is there anything I can do about it?

Thanks alot!
Robin

Bryan Oakley

unread,
Mar 15, 2016, 12:29:06 PM3/15/16
to Robin Lorke, robotframework-users
I avoid this by using properties for things that depend on a runtime context. For example:

    from robot.libraries.BuiltIn import BuiltIn

    class ScDocTestLibrary():
        @property
        def inputDirectory(self):

            sc = BuiltIn().get_library_instance("ScConnector")
            return sc.getInputDir()

With the above, the code doesn't actually call get_library_instance until the first time something needs self.inputDirectory.

--
You received this message because you are subscribed to the Google Groups "robotframework-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to robotframework-u...@googlegroups.com.
To post to this group, send email to robotframe...@googlegroups.com.
Visit this group at https://groups.google.com/group/robotframework-users.
For more options, visit https://groups.google.com/d/optout.

vbs

unread,
Mar 16, 2016, 4:20:17 AM3/16/16
to robotframework-users, robin...@gmail.com
Thanks for quick answer! I can think I can use that pattern for most my libraries. I'm afraid there will be some places where I cannot apply it that way since the constructors are a bit more complex. I am a bit undecided if I want to change the structure of those libraries "just" to make libdoc work though (for example by introducing another "init" function or something that has to be invoked manually to properly initialize the library object).

Another question (a bit offtopic): I noticed that libraries having constructor arguments do generally not work with libdoc. libdoc tries to instantiate the classes without constructor arguments and fails if arguments are existing. Is there also some workaround for it?

Thanks again & Cheers
Robin

Tatu Aalto

unread,
Mar 16, 2016, 9:42:52 AM3/16/16
to Robin Lorke, robotframework-users

Ugh

I usually try to have a meaningful default value. If meaningful value cannot be guaranteed, I tend to use Python None and raise an meaningful exception when keyword is used. The other option is give the arguments from command line[1], the examples are at the end of the chapter 5.1.

[1] http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#general-usage

--

Tatu Aalto

unread,
Mar 17, 2016, 11:44:57 AM3/17/16
to robotframework-users, robin...@gmail.com
Ugh

I have also always tough that code in below solves the problems with libdoc. But I did stumble on on problems when using hybrid library[1] and having that property. My libdoc command looks like this: python -m robot.libdoc --pythonpath . tmp.MyClassName list

If my code looks like this and is in tmp.py file:
from robot.libraries.BuiltIn import BuiltIn
from robot.api.deco import keyword


class MyClassName(object):

    def get_keyword_names(self):
        return [name for name in dir(self) if hasattr(getattr(self, name), 'robot_name')]

    @keyword
    def keyword_here(self):
        print self.get_lib

    @property
    def get_lib(self):
        return BuiltIn().get_library_instance('Selenium2Library')

Libdoc will fail on the following error: Calling dynamic method 'get_keyword_names' failed: RobotNotRunningError: Cannot access execution context

Now if my code looks like this:
from robot.libraries.BuiltIn import BuiltIn


class MyClassName(object):

    def get_keyword_names(self):
        return ['keyword_here']

    def keyword_here(self):
        print self.get_lib

    @property
    def get_lib(self):
        return BuiltIn().get_library_instance('Selenium2Library')

Libdoc works nicely. Is this a by intention or a bug somewhere?

-Tatu
To unsubscribe from this group and stop receiving emails from it, send an email to robotframework-users+unsub...@googlegroups.com.

Pekka Klärck

unread,
Mar 18, 2016, 9:26:30 AM3/18/16
to Tatu Aalto, robotframework-users, Robin Lorke
2016-03-17 17:44 GMT+02:00 Tatu Aalto <aalto...@gmail.com>:
>
> I have also always tough that code in below solves the problems with libdoc.
> But I did stumble on on problems when using hybrid library[1] and having
> that property. My libdoc command looks like this: python -m robot.libdoc
> --pythonpath . tmp.MyClassName list
>
> If my code looks like this and is in tmp.py file:
> from robot.libraries.BuiltIn import BuiltIn
> from robot.api.deco import keyword
>
>
> class MyClassName(object):
>
> def get_keyword_names(self):
> return [name for name in dir(self) if hasattr(getattr(self, name),
> 'robot_name')]
>
> @keyword
> def keyword_here(self):
> print self.get_lib
>
> @property
> def get_lib(self):
> return BuiltIn().get_library_instance('Selenium2Library')
>
> Libdoc will fail on the following error: Calling dynamic method
> 'get_keyword_names' failed: RobotNotRunningError: Cannot access execution
> context

The reason for the error is twofold:

- Robot needs to call your get_keyword_names method to know what
keywords the library implements.
- Your get_keyword_names indirectly executes get_lib property.

I don't think there's anything that could be changed on Robot side to
fix this issue. Possible solutions in your library include
blacklisting propertys and accessing attributes via class, not
instance, to avoid propertys being called.

Cheers,
.peke
--
Agile Tester/Developer/Consultant :: http://eliga.fi
Lead Developer of Robot Framework :: http://robotframework.org
Reply all
Reply to author
Forward
0 new messages