Created
November 16, 2016 00:47
-
-
Save aule/aaf9aed8e405de72da1f3867d0b1f770 to your computer and use it in GitHub Desktop.
Object Oriented Robot Wrapper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Tools for allowing Robot Framework to interact with Python objects.""" | |
import inspect | |
class RobotWrapper(object): | |
"""Exposes all methods of a wrapped Robot library as functions. | |
Usually, instance methods are bound to a class instance, so that the first | |
parameter (`self`) is automatically passed in. This wrapper is a hack that | |
"unbinds" instance methods, making them normal functions: | |
>>> class Spam(object): | |
... def __init__(self, ham, eggs): | |
... pass | |
... @classmethod | |
... def create_spam(cls, ham, eggs): # normal keyword | |
... return cls(ham, eggs) | |
... def foo(self, bar): # method which will be unbound | |
... print(bar) | |
... | |
>>> instance = Spam('ham', 'eggs') | |
>>> instance.foo('baz') | |
baz | |
>>> foo = instance.foo.__func__ # manually unbind | |
>>> foo(instance, 'baz') | |
baz | |
Why is this interesting? Usually, if a Robot library is a class, then it is | |
initialised when it is imported into a Robot test suite, i.e. at the start. | |
This way, when imported into Robot, these unbound functions become keywords | |
that take an instance as a parameter. Now objects can easily and | |
dynamically be used inside a Robot test suite, provided there is e.g. a | |
static/class factory method or the object is returned by another keyword: | |
*** Keywords *** | |
Do Foo | |
${instance} = Create Spam ${ham} ${eggs} | |
Foo ${instance} ${bar} | |
In the above example the instance came from a class method which was | |
imported as an ordinary keyword. | |
--- | |
To wrap a library, create a wrapper which inherits from this class and set | |
the `wrapped_class` attribute to the library, then import that wrapper in | |
the test suite instead of the library. Additional keywords (e.g. factory | |
methods) can be added to the wrapping class as methods. | |
""" | |
wrapped_class = NotImplemented | |
def __init__(self): | |
"""Unbind and add all functions from wrapped class to the instance.""" | |
# Only callable members need converting into Robot keywords. All static | |
# members can be accessed with ${instance.someproperty} syntax | |
members = inspect.getmembers(self.wrapped_class, predicate=callable) | |
for name, member in members: | |
# skip private methods | |
if name.startswith('_'): | |
continue | |
# do we have an instance method? | |
# if it's a class method, the bound instance is already set | |
# if it's an instance method, the bound instance is None | |
if inspect.ismethod(member) and member.__self__ is None: | |
# hack around robot stripping `self` off instance methods by | |
# using the "raw" function instead of one bound to the instance | |
member = member.__func__ | |
# Set the imported functions as attributes so Robot can grab them | |
setattr(self, name, member) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment