def resolve_arguments(self, args_and_kwargs, variables=None):
        """More Pythonic argument handling for interactive
        :class:`robottools.testrobot.keyword.Keyword` calls.

        Original ``resolve_arguments`` methods from ``robot.running.handlers``
        expect as first argument a single list of Keyword arguments
        coming from an RFW script::

           ['arg0', 'arg1', ..., 'name=value', ...]

        So there is no chance to pass unstringified named argument values.
        Only unstringified positional arguments are possible.

        This wrapper method takes a normal Python `args_and_kwargs` pair
        instead as first argument::

           (arg0, arg1, ...), {name: value, ...}

        It resolves the named arguments stringified via the original method
        but returns the original Python values::

           [arg0, arg1, ...], [(name, value), ...]

        Only strings are untouched.
        So RFW ``'...${variable}...'`` substitution still works.
        """
        posargs, kwargs = args_and_kwargs
        rfwargs = list(posargs)
        # prepare 'key=value' strings for original RFW method
        for name, value in dictitems(kwargs):
            if not isstring(value):
                value = repr(value)
            rfwargs.append(u'%s=%s' % (name, value))
        posargs, rfwkwargs = self._resolve_arguments(rfwargs, variables)
        # and replace values with original non-string objects after resolving
        kwargslist = []
        if isdict(rfwkwargs):
            # ==> RFW < 3.0
            rfwkwargs = dictitems(rfwkwargs)
        for name, rfwvalue in rfwkwargs:
            value = kwargs[name]
            if isstring(value):
                value = rfwvalue
            kwargslist.append((name, value))
        if hasattr(self, 'run'):
            # ==> RFW < 3.0
            return posargs, dict(kwargslist)
        # RFW >= 3.0
        return posargs, kwargslist
Esempio n. 2
0
    def __new__(mcs, clsname=None, bases=None, clsattrs=None, **kwargs):
        metaattrs = {'__module__': clsattrs.get('__module__')}
        for name, obj in list(dictitems(clsattrs)):
            if ismetamethod(obj):
                metaattrs[name] = clsattrs.pop(name).func
            elif ismetaclassmethod(obj):
                metaattrs[name] = classmethod(clsattrs.pop(name).func)

        metabases = tuple(type(b) for b in bases if issubclass(b, object))
        # is this `mcs` already under the bases' metaclasses?
        if not any(issubclass(mb, mcs) for mb in metabases):
            # no? ==> change that
            metabases = (mcs, ) + metabases
        # is there a user-defined inner `meta` options class?
        meta = clsattrs.pop('meta', None)
        if meta:
            # then prepend it as additional metaclass base
            metabases = (meta, ) + metabases
        # and now create the new metaclass for the new modeled class
        mcs = type(clsname + '.meta', metabases, metaattrs)

        # create basic modeled-class-specific exception class
        mcs.Exception = type('%s.Exception' % clsname, (Exception, ), {})

        # delegate actual class creation to modeled.base.metabase
        cls = base.__new__(mcs, clsname, bases, clsattrs)
        if meta:
            # re-add user-defined inner meta options class
            # for later use in derived __new__ or __init__ methods
            clsattrs['meta'] = meta
        return cls
Esempio n. 3
0
    def __new__(mcs, clsname=None, bases=None, clsattrs=None, **kwargs):
        metaattrs = {'__module__': clsattrs.get('__module__')}
        for name, obj in list(dictitems(clsattrs)):
            if ismetamethod(obj):
                metaattrs[name] = clsattrs.pop(name).func
            elif ismetaclassmethod(obj):
                metaattrs[name] = classmethod(clsattrs.pop(name).func)

        metabases = tuple(type(b) for b in bases if issubclass(b, object))
        # is this `mcs` already under the bases' metaclasses?
        if not any(issubclass(mb, mcs) for mb in metabases):
            # no? ==> change that
            metabases = (mcs, ) + metabases
        # is there a user-defined inner `meta` options class?
        meta = clsattrs.pop('meta', None)
        if meta:
            # then prepend it as additional metaclass base
            metabases = (meta, ) + metabases
        # and now create the new metaclass for the new modeled class
        mcs = type(clsname + '.meta', metabases, metaattrs)

        # create basic modeled-class-specific exception class
        mcs.Exception = type('%s.Exception' % clsname, (Exception, ), {})

        # delegate actual class creation to modeled.base.metabase
        cls = base.__new__(mcs, clsname, bases, clsattrs)
        if meta:
            # re-add user-defined inner meta options class
            # for later use in derived __new__ or __init__ methods
            clsattrs['meta'] = meta
        return cls
 def method(self, *args, **kwargs):
     try:
         variables = BuiltIn()._variables
     except RobotNotRunningError:
         pass
     else:
         for key, value in list(dictitems(kwargs)):
             if is_scalar_var(key):
                 kwargs[variables[key]] = kwargs.pop(key)
     return func(self, *args, **kwargs)
 def method(self, *args, **kwargs):
     try:
         variables = BuiltIn()._variables
     except RobotNotRunningError:
         pass
     else:
         for key, value in list(dictitems(kwargs)):
             if is_scalar_var(key):
                 kwargs[variables[key]] = kwargs.pop(key)
     return func(self, *args, **kwargs)
def test_dictitems(dict_):
    """Test the dictitems() function,
       which returns an iterator of a dictionary's (key, value) pairs
       and also works with simpledict() class instances.
    """
    items = dictitems(dict_)
    # dictitems() should not return lists, only iterators
    assert not isinstance(items, list)
    # compare with reference sequence from dict method
    for (key, value), (refkey, refvalue) in zip(items, dict_.items()):
        assert key is refkey and refvalue is refvalue
    # and check that iterator is exhausted
    with pytest.raises(StopIteration):
        next(items)
def test_dictitems(dict_):
    """Test the dictitems() function,
       which returns an iterator of a dictionary's (key, value) pairs
       and also works with simpledict() class instances.
    """
    items = dictitems(dict_)
    # dictitems() should not return lists, only iterators
    assert not isinstance(items, list)
    # compare with reference sequence from dict method
    for (key, value), (refkey, refvalue) in zip(items, dict_.items()):
        assert key is refkey and refvalue is refvalue
    # and check that iterator is exhausted
    with pytest.raises(StopIteration):
        next(items)
        def open_session(self, *args, **kwargs):
            """Open an unnamed {singular}.

            This keyword automatically closes
            any other currently active unnamed {singular}.
            """
            previous = cls.session
            active = func(self, *args, **kwargs)
            cls.add_session(active)
            if previous is not None and close_func:
                # explicitly close previously active session if unnamed
                for name, session in dictitems(cls.sessions):
                    if session is previous:
                        break
                else:
                    close_func(self, previous)
    def close_session(cls, name=None):
        """Helper method for closing the currently active session.
        """
        if name:
            try:
                session = cls.sessions.pop(name)
            except KeyError:
                raise cls.SessionError('Session not found: %s' % repr(name))
            if session is cls.session:
                cls.session = None
            return session

        if cls.session is None:
            raise cls.SessionError('No active session.')
        for name, session in list(dictitems(cls.sessions)):
            if session is cls.session:
                del cls.sessions[name]
        session = cls.session
        cls.session = None
        return session
Esempio n. 10
0
 def switch_session(self, name):
     previous = cls.session
     active = cls.switch_session(name)
     if previous is not None and close_func:
         # explicitly close previously active session if unnamed
         for name, session in dictitems(cls.sessions):
             if session is previous:
                 break
         else:
             try:
                 close_func(self, previous)
             except Exception as exc:
                 raise cls.SessionError(
                     "Couldn't close unnamed session "
                     "on switching to %s (%s: %s)"
                     % (repr(name), qualname(type(exc)), exc))
     if switch_func:
         try:
             switch_func(self, active)
         except Exception as exc:
             raise cls.SessionError(
                 "Couldn't switch session to %s (%s: %s)"
                 % (repr(name), qualname(type(exc)), exc))
     cls.session = active
Esempio n. 11
0
    def __init__(cls, clsname, bases, clsattrs):
        """Generate the actual session management keywords
           for :class:`Handler` derived classes.

        - Includes the session management helper methods of :class:`Handler`
          and user-defined session opener methods
          (whose names start with 'open').
        - Looks for optional custom session switch/close hook methods
          named 'switch'/'close'
        - All Keyword names include the handler-specific
          `meta.identifier_name`.
        """
        try:
            meta = cls.meta
        except AttributeError:
            return

        open_funcs = []
        switch_func = close_func = None
        for name, func in dictitems(clsattrs):
            if name.startswith('open'):
                open_funcs.append(func)
            elif name == 'switch':
                switch_func = func
            elif name == 'close':
                close_func = func
        for func in open_funcs:
            cls.add_opener(func, close_func=close_func)

        def switch_session(self, name):
            previous = cls.session
            active = cls.switch_session(name)
            if previous is not None and close_func:
                # explicitly close previously active session if unnamed
                for name, session in dictitems(cls.sessions):
                    if session is previous:
                        break
                else:
                    try:
                        close_func(self, previous)
                    except Exception as exc:
                        raise cls.SessionError(
                            "Couldn't close unnamed session "
                            "on switching to %s (%s: %s)"
                            % (repr(name), qualname(type(exc)), exc))
            if switch_func:
                try:
                    switch_func(self, active)
                except Exception as exc:
                    raise cls.SessionError(
                        "Couldn't switch session to %s (%s: %s)"
                        % (repr(name), qualname(type(exc)), exc))
            cls.session = active

        keywordname = 'switch_' + meta.identifier_name
        cls.keywords[keywordname] = switch_session

        def close_session(self, name=None):
            session = cls.close_session(name)
            if close_func:
                close_func(self, session)

        keywordname = 'close_' + meta.identifier_name
        cls.keywords[keywordname] = close_session
 def __call__(self, *args, **kwargs):
     """Call the Keyword's actual function with the given arguments.
     """
     func = self.func
     # the exception to finally reraise (if any)
     error = None
     # look for explicit <session>= and <context>= switching options
     # in kwargs and store the currently active
     # session aliases and context names
     # for switching back after the Keyword call:
     current_sessions = {}
     for _, hcls in self.libinstance.session_handlers:
         if not hcls.meta.auto_explicit:
             continue
         identifier = hcls.meta.identifier_name
         plural_identifier = hcls.meta.plural_identifier_name
         try:
             sname = kwargs.pop(identifier)
         except KeyError:
             continue
         previous = getattr(self.libinstance, identifier)
         switch = getattr(self.libinstance, 'switch_' + identifier)
         try:
             switch(sname)
         except hcls.SessionError:
             error = sys.exc_info()
             # don't switch any more sessions
             break
         # store previous session for switching back later
         current_sessions[identifier, plural_identifier] = previous
     # only perform explicit context switching
     # if explicit session switching didn't raise any error
     current_contexts = {}
     if error is None:
         for hcls in self.context_handlers:
             if not getattr(hcls, 'auto_explicit', False):
                 continue
             identifier = hcls.__name__.lower()
             try:
                 ctxname = kwargs.pop(identifier)
             except KeyError:
                 continue
             previous = getattr(self.libinstance, identifier)
             switch = getattr(self.libinstance, 'switch_' + identifier)
             try:
                 switch(ctxname)
             except hcls.ContextError:
                 error = sys.exc_info()
                 # don't switch any more contexts
                 break
             # store previous context for switching back later
             current_contexts[identifier] = previous
     # only call the acutal keyword func
     # if explicit session and context switching didn't raise any error
     if error is None:
         # Look for arg type specs:
         if func.argtypes:
             casted = []
             for arg, argtype in zip(args, func.argtypes):
                 if not isinstance(arg, argtype):
                     arg = argtype(arg)
                 casted.append(arg)
             args = tuple(casted) + args[len(func.argtypes):]
         # Look for context specific implementation of the Keyword function
         for context, context_func in dictitems(func.contexts):
             if context in self.libinstance.contexts:
                 func = context_func
         # Does the keyword support **kwargs?
         if self.func.argspec.keywords or not kwargs:
             try:
                 result = func(self.libinstance, *args, **kwargs)
             except Exception:
                 error = sys.exc_info()
         else:
             # resolve **kwargs to positional args...
             posargs = []
             # (argspec.args start index includes self)
             for name in self.func.argspec.args[1 + len(args):]:
                 if name in kwargs:
                     posargs.append(kwargs.pop(name))
             # and turn the rest into *varargs in 'key=value' style
             varargs = [
                 '%s=%s' % (key, kwargs.pop(key)) for key in list(kwargs)
                 if key not in self.func.argspec.args
             ]
             try:
                 result = func(
                     self.libinstance,
                     *chain(args, posargs, varargs),
                     # if **kwargs left ==> TypeError from Python
                     **kwargs)
             except:
                 error = sys.exc_info()
     # finally try to switch back contexts and sessions (in reverse order)
     # before either returning result or reraising any error catched above
     for identifier, ctxname in dictitems(current_contexts):
         switch = getattr(self.libinstance, 'switch_' + identifier)
         # don't catch anything here. just step out on error
         switch(ctxname)
     for (identifier,
          plural_identifier), session in dictitems(current_sessions):
         for sname, sinstance in dictitems(
                 getattr(self.libinstance, plural_identifier)):
             if sinstance is session:
                 switch = getattr(self.libinstance, 'switch_' + identifier)
                 # don't catch anything here. just step out on error
                 switch(sname)
     # was an error catched on initial session or context switching
     # or on calling the actual keyword func?
     if error is not None:
         reraise(*error)
     # great! everything went fine :)
     return result
 def __call__(self, *args, **kwargs):
     """Call the Keyword's actual function with the given arguments.
     """
     func = self.func
     # the exception to finally reraise (if any)
     error = None
     # look for explicit <session>= and <context>= switching options
     # in kwargs and store the currently active
     # session aliases and context names
     # for switching back after the Keyword call:
     current_sessions = {}
     for _, hcls in self.libinstance.session_handlers:
         if not hcls.meta.auto_explicit:
             continue
         identifier = hcls.meta.identifier_name
         plural_identifier = hcls.meta.plural_identifier_name
         try:
             sname = kwargs.pop(identifier)
         except KeyError:
             continue
         previous = getattr(self.libinstance, identifier)
         switch = getattr(self.libinstance, 'switch_' + identifier)
         try:
             switch(sname)
         except hcls.SessionError:
             error = sys.exc_info()
             # don't switch any more sessions
             break
         # store previous session for switching back later
         current_sessions[identifier, plural_identifier] = previous
     # only perform explicit context switching
     # if explicit session switching didn't raise any error
     current_contexts = {}
     if error is None:
         for hcls in self.context_handlers:
             if not getattr(hcls, 'auto_explicit', False):
                 continue
             identifier = hcls.__name__.lower()
             try:
                 ctxname = kwargs.pop(identifier)
             except KeyError:
                 continue
             previous = getattr(self.libinstance, identifier)
             switch = getattr(self.libinstance, 'switch_' + identifier)
             try:
                 switch(ctxname)
             except hcls.ContextError:
                 error = sys.exc_info()
                 # don't switch any more contexts
                 break
             # store previous context for switching back later
             current_contexts[identifier] = previous
     # only call the acutal keyword func
     # if explicit session and context switching didn't raise any error
     if error is None:
         # Look for arg type specs:
         if func.argtypes:
             casted = []
             for arg, argtype in zip(args, func.argtypes):
                 if not isinstance(arg, argtype):
                     arg = argtype(arg)
                 casted.append(arg)
             args = tuple(casted) + args[len(func.argtypes):]
         # Look for context specific implementation of the Keyword function
         for context, context_func in dictitems(func.contexts):
             if context in self.libinstance.contexts:
                 func = context_func
         # Does the keyword support **kwargs?
         if self.func.argspec.keywords or not kwargs:
             try:
                 result = func(self.libinstance, *args, **kwargs)
             except Exception:
                 error = sys.exc_info()
         else:
             # resolve **kwargs to positional args...
             posargs = []
             # (argspec.args start index includes self)
             for name in self.func.argspec.args[1 + len(args):]:
                 if name in kwargs:
                     posargs.append(kwargs.pop(name))
             # and turn the rest into *varargs in 'key=value' style
             varargs = ['%s=%s' % (key, kwargs.pop(key))
                        for key in list(kwargs)
                        if key not in self.func.argspec.args]
             try:
                 result = func(self.libinstance,
                               *chain(args, posargs, varargs),
                               # if **kwargs left ==> TypeError from Python
                               **kwargs)
             except:
                 error = sys.exc_info()
     # finally try to switch back contexts and sessions (in reverse order)
     # before either returning result or reraising any error catched above
     for identifier, ctxname in dictitems(current_contexts):
         switch = getattr(self.libinstance, 'switch_' + identifier)
         # don't catch anything here. just step out on error
         switch(ctxname)
     for (identifier, plural_identifier), session in dictitems(
             current_sessions
     ):
         for sname, sinstance in dictitems(getattr(
                 self.libinstance, plural_identifier
         )):
             if sinstance is session:
                 switch = getattr(self.libinstance, 'switch_' + identifier)
                 # don't catch anything here. just step out on error
                 switch(sname)
     # was an error catched on initial session or context switching
     # or on calling the actual keyword func?
     if error is not None:
         reraise(*error)
     # great! everything went fine :)
     return result