Source code for python_sikuli_client.misc

"""
Extra classes that implementent miscellaneous needed functionailty
"""
from functools import wraps
from python_sikuli_client.sikuli_class import ClientSikuliClass

__author__ = 'Alistair Broomhead'
from python_sikuli_client.pattern import Pattern
from python_sikuli_client.match import Match


[docs]class RemoteLib(object): """ Re-exposes a classes keywords wrapped by robotremotelibrary.py """ def __init__(self, remote): self.__lib = remote def __getattr__(self, name): if name in self.__lib.get_keyword_names(): def _(*args): return self.__lib.run_keyword(name, args) _.__name__ = name self.__dict__[name] = _ return _ raise AttributeError()
[docs]class SikuliUnreflected(object): """ Custom keyword handlers rather than those reflected over RPC """ def __init__(self, remote): """ :type remote: SikuliServer """ self.remote = remote
[docs] def find(self, PS): """ :param PS: :class:`~python_sikuli_client.pattern.Pattern` or str :rtype: :class:`~python_sikuli_client.match.Match` Find a particular GUI element, which is seen as the given image or just plain text. The given file name of an image specifies the element's appearance. It searches within the region and returns the best match, which shows a similarity greater than the minimum similarity given by the pattern. If no similarity was set for the pattern by :meth:`python_sikuli_client.pattern.Pattern.similar` before, a default minimum similarity of 0.7 is set automatically. If autoWaitTimeout is set to a non-zero value, find() just acts as a wait(). **Side Effect** *lastMatch*: the best match can be accessed using :meth:`~python_sikuli_client.region.Region.getLastMatch` afterwards. """ if isinstance(PS, Pattern): assert isinstance(PS, Pattern) ps = "self._get_jython_object(%r)" % PS.remote_id else: ps = repr(PS) #noinspection PyUnresolvedReferences match_id = self._eval("self._new_jython_object(self.find(%s))" % ps) # noinspection PyArgumentList return Match(remote=self.remote, id_=match_id)
[docs]def dropNones(num_required, keys, *args, **kwargs): """ Was finding this repoetitive. :param num_required: how many args are required in total :param keys: dict of keys and (bool) is_required (None ignores this) :param args: :param kwargs: some of these will not """ if keys is None: kw = {k: v for k, v in kwargs.items() if v is not None} else: kw = {k: v for k, v in kwargs.items() if (v is not None) or (k in keys and keys[k])} while len(kw) + len(args) > num_required and args[-1] is None: args = args[:-1] return args, kw
[docs]def constructor(cls): """ :param cls: class to use decorated function as constructor for Uses func as a potential constructor for cls: func should return the string which when evaluated by jython gives the object we want. .. code-block:: python @constructor(cls) def func(*args, **kwargs): ... """ def _wrapper(func): @wraps(func) def _func(*args, **kwargs): return cls.remote._eval("self._new_jython_object(%s)" % func(*args, **kwargs)) cls._constructors = cls._constructors + (_func,) return _func return _wrapper
[docs]def return_from_remote(rtype): """ Decorator factory returning a run_on_remote decorator which marshals and unmarshals the return type as ``rtype`` where ``rtype`` must be either a subclass of :class:`ClientSikuliClass`, or the string name of a class in :mod:`~python_sikuli_client.classes` :param rtype: return type .. code-block:: python @return_from_remote(rtype) def func(*args, **kwargs): ... """ def _new_decorator(func): func = run_on_remote(func) rt = [] # noinspection PyUnusedLocal @func.func def _inner_func(self, *args, **kwargs): location_id = self.remote._eval( "self._new_jython_object(" " self._get_jython_object(%r).%s(%s))" % ( self._id, func.__name__, ', '.join([s_repr(x) for x in args]))) if not rt: from python_sikuli_client.classes import SIKULI_CLASSES cls = (rtype if isinstance(rtype, ClientSikuliClass) else SIKULI_CLASSES[rtype]) rt.append(cls) else: cls = rt[0] obj = cls(remote=self.remote, server_id=str(location_id)) #obj.remote._del_obj(location_id) return obj return func return _new_decorator
[docs]def DEFERRED(func): """ Decorator for unimplemented interfaces :type func: function """ func.__doc__ = """ .. todo:: Implement %r (later) """ % func.__name__ return func
[docs]def TODO(func): """ Decorator for unimplemented interfaces :type func: function """ func.__doc__ = """ .. todo:: Implement %r (soon) """ % func.__name__ return func
[docs]def run_on_remote(func): """ :param func: function to decorate Runs the decorated function but discards the result, so you can use it for sanity-checking but should not use it for actual processing, as this will be done on the server side. The decorated function can have a number of properties that modify the way it is run, each of which should be a function itself: ``func.arg(*args, **kwargs)``: The output of this will be used as args for the inner wrapper ``func.post(result)``: This takes the output of the inner wrapper, and its ouput is returned by the outer wrapper ``func.func(*args, **kwargs)``: Replaces the default inner function - should handle all interaction with the server .. code-block:: python @run_on_remote def func(*args, **kwargs): ... """ gjo = "self._get_jython_object" func._augment = { 'inner': lambda self, *args: (self.remote._eval("%s(%r).%s(%s)" % (gjo, self._id, func.__name__, ', '.join([s_repr(x)for x in args])))) } @wraps(func) def _outer(self, *args, **kwargs): if not self._on_server: raise NameError('%r has been garbage collected on the server side' % self) func(self, *args, **kwargs) if "arg" in func._augment: arg_kw = func._augment["arg"](self, *args, **kwargs) if len(arg_kw) == 2 and (isinstance(arg_kw[0], tuple) and isinstance(arg_kw[1], dict)): args, kwargs = arg_kw else: args, kwargs = arg_kw, {} result = func._augment['inner'](self, *args, **kwargs) if "post" in func._augment: return func._augment["post"](self, result) else: return result def _arg(arg_func): func._augment['arg'] = arg_func return func def _post(post_func): func._augment['post'] = post_func return func def _func(func_func): func._augment['inner'] = func_func return func func.arg = _arg func.post = _post func.func = _func func.run = _outer return func
[docs]def s_repr(obj): """ :param obj: object """ return (repr(obj) if not isinstance(obj, ClientSikuliClass) else obj._str_get)