Best Python code snippet using robotframework
BuiltIn.py
Source:BuiltIn.py  
...39if JYTHON:40    from java.lang import String, Number41# TODO: Clean-up registering run keyword variants in RF 3.1.42# https://github.com/robotframework/robotframework/issues/219043def run_keyword_variant(resolve):44    def decorator(method):45        RUN_KW_REGISTER.register_run_keyword('BuiltIn', method.__name__,46                                             resolve, deprecation_warning=False)47        return method48    return decorator49class _BuiltInBase(object):50    @property51    def _context(self):52        return self._get_context()53    def _get_context(self, top=False):54        ctx = EXECUTION_CONTEXTS.current if not top else EXECUTION_CONTEXTS.top55        if ctx is None:56            raise RobotNotRunningError('Cannot access execution context')57        return ctx58    @property59    def _namespace(self):60        return self._get_context().namespace61    @property62    def _variables(self):63        return self._namespace.variables64    def _matches(self, string, pattern):65        # Must use this instead of fnmatch when string may contain newlines.66        matcher = Matcher(pattern, caseless=False, spaceless=False)67        return matcher.match(string)68    def _is_true(self, condition):69        if is_string(condition):70            condition = self.evaluate(condition, modules='os,sys')71        return bool(condition)72    def _log_types(self, *args):73        self._log_types_at_level('DEBUG', *args)74    def _log_types_at_level(self, level, *args):75        msg = ["Argument types are:"] + [self._get_type(a) for a in args]76        self.log('\n'.join(msg), level)77    def _get_type(self, arg):78        # In IronPython type(u'x') is str. We want to report unicode anyway.79        if is_unicode(arg):80            return "<type 'unicode'>"81        return str(type(arg))82class _Converter(_BuiltInBase):83    def convert_to_integer(self, item, base=None):84        """Converts the given item to an integer number.85        If the given item is a string, it is by default expected to be an86        integer in base 10. There are two ways to convert from other bases:87        - Give base explicitly to the keyword as ``base`` argument.88        - Prefix the given string with the base so that ``0b`` means binary89          (base 2), ``0o`` means octal (base 8), and ``0x`` means hex (base 16).90          The prefix is considered only when ``base`` argument is not given and91          may itself be prefixed with a plus or minus sign.92        The syntax is case-insensitive and possible spaces are ignored.93        Examples:94        | ${result} = | Convert To Integer | 100    |    | # Result is 100   |95        | ${result} = | Convert To Integer | FF AA  | 16 | # Result is 65450 |96        | ${result} = | Convert To Integer | 100    | 8  | # Result is 64    |97        | ${result} = | Convert To Integer | -100   | 2  | # Result is -4    |98        | ${result} = | Convert To Integer | 0b100  |    | # Result is 4     |99        | ${result} = | Convert To Integer | -0x100 |    | # Result is -256  |100        See also `Convert To Number`, `Convert To Binary`, `Convert To Octal`,101        `Convert To Hex`, and `Convert To Bytes`.102        """103        self._log_types(item)104        return self._convert_to_integer(item, base)105    def _convert_to_integer(self, orig, base=None):106        try:107            item = self._handle_java_numbers(orig)108            item, base = self._get_base(item, base)109            if base:110                return int(item, self._convert_to_integer(base))111            return int(item)112        except:113            raise RuntimeError("'%s' cannot be converted to an integer: %s"114                               % (orig, get_error_message()))115    def _handle_java_numbers(self, item):116        if not JYTHON:117            return item118        if isinstance(item, String):119            return unic(item)120        if isinstance(item, Number):121            return item.doubleValue()122        return item123    def _get_base(self, item, base):124        if not is_string(item):125            return item, base126        item = normalize(item)127        if item.startswith(('-', '+')):128            sign = item[0]129            item = item[1:]130        else:131            sign = ''132        bases = {'0b': 2, '0o': 8, '0x': 16}133        if base or not item.startswith(tuple(bases)):134            return sign+item, base135        return sign+item[2:], bases[item[:2]]136    def convert_to_binary(self, item, base=None, prefix=None, length=None):137        """Converts the given item to a binary string.138        The ``item``, with an optional ``base``, is first converted to an139        integer using `Convert To Integer` internally. After that it140        is converted to a binary number (base 2) represented as a141        string such as ``1011``.142        The returned value can contain an optional ``prefix`` and can be143        required to be of minimum ``length`` (excluding the prefix and a144        possible minus sign). If the value is initially shorter than145        the required length, it is padded with zeros.146        Examples:147        | ${result} = | Convert To Binary | 10 |         |           | # Result is 1010   |148        | ${result} = | Convert To Binary | F  | base=16 | prefix=0b | # Result is 0b1111 |149        | ${result} = | Convert To Binary | -2 | prefix=B | length=4 | # Result is -B0010 |150        See also `Convert To Integer`, `Convert To Octal` and `Convert To Hex`.151        """152        return self._convert_to_bin_oct_hex(item, base, prefix, length, 'b')153    def convert_to_octal(self, item, base=None, prefix=None, length=None):154        """Converts the given item to an octal string.155        The ``item``, with an optional ``base``, is first converted to an156        integer using `Convert To Integer` internally. After that it157        is converted to an octal number (base 8) represented as a158        string such as ``775``.159        The returned value can contain an optional ``prefix`` and can be160        required to be of minimum ``length`` (excluding the prefix and a161        possible minus sign). If the value is initially shorter than162        the required length, it is padded with zeros.163        Examples:164        | ${result} = | Convert To Octal | 10 |            |          | # Result is 12      |165        | ${result} = | Convert To Octal | -F | base=16    | prefix=0 | # Result is -017    |166        | ${result} = | Convert To Octal | 16 | prefix=oct | length=4 | # Result is oct0020 |167        See also `Convert To Integer`, `Convert To Binary` and `Convert To Hex`.168        """169        return self._convert_to_bin_oct_hex(item, base, prefix, length, 'o')170    def convert_to_hex(self, item, base=None, prefix=None, length=None,171                       lowercase=False):172        """Converts the given item to a hexadecimal string.173        The ``item``, with an optional ``base``, is first converted to an174        integer using `Convert To Integer` internally. After that it175        is converted to a hexadecimal number (base 16) represented as176        a string such as ``FF0A``.177        The returned value can contain an optional ``prefix`` and can be178        required to be of minimum ``length`` (excluding the prefix and a179        possible minus sign). If the value is initially shorter than180        the required length, it is padded with zeros.181        By default the value is returned as an upper case string, but the182        ``lowercase`` argument a true value (see `Boolean arguments`) turns183        the value (but not the given prefix) to lower case.184        Examples:185        | ${result} = | Convert To Hex | 255 |           |              | # Result is FF    |186        | ${result} = | Convert To Hex | -10 | prefix=0x | length=2     | # Result is -0x0A |187        | ${result} = | Convert To Hex | 255 | prefix=X | lowercase=yes | # Result is Xff   |188        See also `Convert To Integer`, `Convert To Binary` and `Convert To Octal`.189        """190        spec = 'x' if is_truthy(lowercase) else 'X'191        return self._convert_to_bin_oct_hex(item, base, prefix, length, spec)192    def _convert_to_bin_oct_hex(self, item, base, prefix, length, format_spec):193        self._log_types(item)194        ret = format(self._convert_to_integer(item, base), format_spec)195        prefix = prefix or ''196        if ret[0] == '-':197            prefix = '-' + prefix198            ret = ret[1:]199        if length:200            ret = ret.rjust(self._convert_to_integer(length), '0')201        return prefix + ret202    def convert_to_number(self, item, precision=None):203        """Converts the given item to a floating point number.204        If the optional ``precision`` is positive or zero, the returned number205        is rounded to that number of decimal digits. Negative precision means206        that the number is rounded to the closest multiple of 10 to the power207        of the absolute precision. If a number is equally close to a certain208        precision, it is always rounded away from zero.209        Examples:210        | ${result} = | Convert To Number | 42.512 |    | # Result is 42.512 |211        | ${result} = | Convert To Number | 42.512 | 1  | # Result is 42.5   |212        | ${result} = | Convert To Number | 42.512 | 0  | # Result is 43.0   |213        | ${result} = | Convert To Number | 42.512 | -1 | # Result is 40.0   |214        Notice that machines generally cannot store floating point numbers215        accurately. This may cause surprises with these numbers in general216        and also when they are rounded. For more information see, for example,217        these resources:218        - http://docs.python.org/2/tutorial/floatingpoint.html219        - http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition220        If you need an integer number, use `Convert To Integer` instead.221        """222        self._log_types(item)223        return self._convert_to_number(item, precision)224    def _convert_to_number(self, item, precision=None):225        number = self._convert_to_number_without_precision(item)226        if precision is not None:227            number = roundup(number, self._convert_to_integer(precision),228                             return_type=float)229        return number230    def _convert_to_number_without_precision(self, item):231        try:232            if JYTHON:233                item = self._handle_java_numbers(item)234            return float(item)235        except:236            error = get_error_message()237            try:238                return float(self._convert_to_integer(item))239            except RuntimeError:240                raise RuntimeError("'%s' cannot be converted to a floating "241                                   "point number: %s" % (item, error))242    def convert_to_string(self, item):243        """Converts the given item to a Unicode string.244        Uses ``__unicode__`` or ``__str__`` method with Python objects and245        ``toString`` with Java objects.246        Use `Encode String To Bytes` and `Decode Bytes To String` keywords247        in ``String`` library if you need to convert between Unicode and byte248        strings using different encodings. Use `Convert To Bytes` if you just249        want to create byte strings.250        """251        self._log_types(item)252        return self._convert_to_string(item)253    def _convert_to_string(self, item):254        return unic(item)255    def convert_to_boolean(self, item):256        """Converts the given item to Boolean true or false.257        Handles strings ``True`` and ``False`` (case-insensitive) as expected,258        otherwise returns item's259        [http://docs.python.org/2/library/stdtypes.html#truth|truth value]260        using Python's ``bool()`` method.261        """262        self._log_types(item)263        if is_string(item):264            if item.upper() == 'TRUE':265                return True266            if item.upper() == 'FALSE':267                return False268        return bool(item)269    def convert_to_bytes(self, input, input_type='text'):270        u"""Converts the given ``input`` to bytes according to the ``input_type``.271        Valid input types are listed below:272        - ``text:`` Converts text to bytes character by character. All273          characters with ordinal below 256 can be used and are converted to274          bytes with same values. Many characters are easiest to represent275          using escapes like ``\\x00`` or ``\\xff``. Supports both Unicode276          strings and bytes.277        - ``int:`` Converts integers separated by spaces to bytes. Similarly as278          with `Convert To Integer`, it is possible to use binary, octal, or279          hex values by prefixing the values with ``0b``, ``0o``, or ``0x``,280          respectively.281        - ``hex:`` Converts hexadecimal values to bytes. Single byte is always282          two characters long (e.g. ``01`` or ``FF``). Spaces are ignored and283          can be used freely as a visual separator.284        - ``bin:`` Converts binary values to bytes. Single byte is always eight285          characters long (e.g. ``00001010``). Spaces are ignored and can be286          used freely as a visual separator.287        In addition to giving the input as a string, it is possible to use288        lists or other iterables containing individual characters or numbers.289        In that case numbers do not need to be padded to certain length and290        they cannot contain extra spaces.291        Examples (last column shows returned bytes):292        | ${bytes} = | Convert To Bytes | hyv\xe4    |     | # hyv\\xe4        |293        | ${bytes} = | Convert To Bytes | \\xff\\x07 |     | # \\xff\\x07      |294        | ${bytes} = | Convert To Bytes | 82 70      | int | # RF              |295        | ${bytes} = | Convert To Bytes | 0b10 0x10  | int | # \\x02\\x10      |296        | ${bytes} = | Convert To Bytes | ff 00 07   | hex | # \\xff\\x00\\x07 |297        | ${bytes} = | Convert To Bytes | 5246212121 | hex | # RF!!!           |298        | ${bytes} = | Convert To Bytes | 0000 1000  | bin | # \\x08           |299        | ${input} = | Create List      | 1          | 2   | 12                |300        | ${bytes} = | Convert To Bytes | ${input}   | int | # \\x01\\x02\\x0c |301        | ${bytes} = | Convert To Bytes | ${input}   | hex | # \\x01\\x02\\x12 |302        Use `Encode String To Bytes` in ``String`` library if you need to303        convert text to bytes using a certain encoding.304        New in Robot Framework 2.8.2.305        """306        try:307            try:308                ordinals = getattr(self, '_get_ordinals_from_%s' % input_type)309            except AttributeError:310                raise RuntimeError("Invalid input type '%s'." % input_type)311            return bytes(bytearray(o for o in ordinals(input)))312        except:313            raise RuntimeError("Creating bytes failed: %s" % get_error_message())314    def _get_ordinals_from_text(self, input):315        # https://github.com/IronLanguages/main/issues/1237316        if IRONPYTHON and isinstance(input, bytearray):317            input = bytes(input)318        for char in input:319            ordinal = char if is_integer(char) else ord(char)320            yield self._test_ordinal(ordinal, char, 'Character')321    def _test_ordinal(self, ordinal, original, type):322        if 0 <= ordinal <= 255:323            return ordinal324        raise RuntimeError("%s '%s' cannot be represented as a byte."325                           % (type, original))326    def _get_ordinals_from_int(self, input):327        if is_string(input):328            input = input.split()329        elif is_integer(input):330            input = [input]331        for integer in input:332            ordinal = self._convert_to_integer(integer)333            yield self._test_ordinal(ordinal, integer, 'Integer')334    def _get_ordinals_from_hex(self, input):335        for token in self._input_to_tokens(input, length=2):336            ordinal = self._convert_to_integer(token, base=16)337            yield self._test_ordinal(ordinal, token, 'Hex value')338    def _get_ordinals_from_bin(self, input):339        for token in self._input_to_tokens(input, length=8):340            ordinal = self._convert_to_integer(token, base=2)341            yield self._test_ordinal(ordinal, token, 'Binary value')342    def _input_to_tokens(self, input, length):343        if not is_string(input):344            return input345        input = ''.join(input.split())346        if len(input) % length != 0:347            raise RuntimeError('Expected input to be multiple of %d.' % length)348        return (input[i:i+length] for i in range(0, len(input), length))349    def create_list(self, *items):350        """Returns a list containing given items.351        The returned list can be assigned both to ``${scalar}`` and ``@{list}``352        variables.353        Examples:354        | @{list} =   | Create List | a    | b    | c    |355        | ${scalar} = | Create List | a    | b    | c    |356        | ${ints} =   | Create List | ${1} | ${2} | ${3} |357        """358        return list(items)359    @run_keyword_variant(resolve=0)360    def create_dictionary(self, *items):361        """Creates and returns a dictionary based on the given ``items``.362        Items are typically given using the ``key=value`` syntax same way as363        ``&{dictionary}`` variables are created in the Variable table. Both364        keys and values can contain variables, and possible equal sign in key365        can be escaped with a backslash like ``escaped\\=key=value``. It is366        also possible to get items from existing dictionaries by simply using367        them like ``&{dict}``.368        Alternatively items can be specified so that keys and values are given369        separately. This and the ``key=value`` syntax can even be combined,370        but separately given items must be first.371        If same key is used multiple times, the last value has precedence.372        The returned dictionary is ordered, and values with strings as keys373        can also be accessed using a convenient dot-access syntax like374        ``${dict.key}``.375        Examples:376        | &{dict} = | Create Dictionary | key=value | foo=bar | | | # key=value syntax |377        | Should Be True | ${dict} == {'key': 'value', 'foo': 'bar'} |378        | &{dict2} = | Create Dictionary | key | value | foo | bar | # separate key and value |379        | Should Be Equal | ${dict} | ${dict2} |380        | &{dict} = | Create Dictionary | ${1}=${2} | &{dict} | foo=new | | # using variables |381        | Should Be True | ${dict} == {1: 2, 'key': 'value', 'foo': 'new'} |382        | Should Be Equal | ${dict.key} | value | | | | # dot-access |383        This keyword was changed in Robot Framework 2.9 in many ways:384        - Moved from ``Collections`` library to ``BuiltIn``.385        - Support also non-string keys in ``key=value`` syntax.386        - Returned dictionary is ordered and dot-accessible.387        - Old syntax to give keys and values separately was deprecated, but388          deprecation was later removed in RF 3.0.1.389        """390        separate, combined = self._split_dict_items(items)391        result = DotDict(self._format_separate_dict_items(separate))392        combined = DictVariableTableValue(combined).resolve(self._variables)393        result.update(combined)394        return result395    def _split_dict_items(self, items):396        separate = []397        for item in items:398            name, value = split_from_equals(item)399            if value is not None or VariableSplitter(item).is_dict_variable():400                break401            separate.append(item)402        return separate, items[len(separate):]403    def _format_separate_dict_items(self, separate):404        separate = self._variables.replace_list(separate)405        if len(separate) % 2 != 0:406            raise DataError('Expected even number of keys and values, got %d.'407                            % len(separate))408        return [separate[i:i+2] for i in range(0, len(separate), 2)]409class _Verify(_BuiltInBase):410    def _set_and_remove_tags(self, tags):411        set_tags = [tag for tag in tags if not tag.startswith('-')]412        remove_tags = [tag[1:] for tag in tags if tag.startswith('-')]413        if remove_tags:414            self.remove_tags(*remove_tags)415        if set_tags:416            self.set_tags(*set_tags)417    def fail(self, msg=None, *tags):418        """Fails the test with the given message and optionally alters its tags.419        The error message is specified using the ``msg`` argument.420        It is possible to use HTML in the given error message, similarly421        as with any other keyword accepting an error message, by prefixing422        the error with ``*HTML*``.423        It is possible to modify tags of the current test case by passing tags424        after the message. Tags starting with a hyphen (e.g. ``-regression``)425        are removed and others added. Tags are modified using `Set Tags` and426        `Remove Tags` internally, and the semantics setting and removing them427        are the same as with these keywords.428        Examples:429        | Fail | Test not ready   |             | | # Fails with the given message.    |430        | Fail | *HTML*<b>Test not ready</b> | | | # Fails using HTML in the message. |431        | Fail | Test not ready   | not-ready   | | # Fails and adds 'not-ready' tag.  |432        | Fail | OS not supported | -regression | | # Removes tag 'regression'.        |433        | Fail | My message       | tag    | -t*  | # Removes all tags starting with 't' except the newly added 'tag'. |434        See `Fatal Error` if you need to stop the whole test execution.435        Support for modifying tags was added in Robot Framework 2.7.4 and436        HTML message support in 2.8.437        """438        self._set_and_remove_tags(tags)439        raise AssertionError(msg) if msg else AssertionError()440    def fatal_error(self, msg=None):441        """Stops the whole test execution.442        The test or suite where this keyword is used fails with the provided443        message, and subsequent tests fail with a canned message.444        Possible teardowns will nevertheless be executed.445        See `Fail` if you only want to stop one test case unconditionally.446        """447        error = AssertionError(msg) if msg else AssertionError()448        error.ROBOT_EXIT_ON_FAILURE = True449        raise error450    def should_not_be_true(self, condition, msg=None):451        """Fails if the given condition is true.452        See `Should Be True` for details about how ``condition`` is evaluated453        and how ``msg`` can be used to override the default error message.454        """455        if self._is_true(condition):456            raise AssertionError(msg or "'%s' should not be true." % condition)457    def should_be_true(self, condition, msg=None):458        """Fails if the given condition is not true.459        If ``condition`` is a string (e.g. ``${rc} < 10``), it is evaluated as460        a Python expression as explained in `Evaluating expressions` and the461        keyword status is decided based on the result. If a non-string item is462        given, the status is got directly from its463        [http://docs.python.org/2/library/stdtypes.html#truth|truth value].464        The default error message (``<condition> should be true``) is not very465        informative, but it can be overridden with the ``msg`` argument.466        Examples:467        | Should Be True | ${rc} < 10            |468        | Should Be True | '${status}' == 'PASS' | # Strings must be quoted |469        | Should Be True | ${number}   | # Passes if ${number} is not zero |470        | Should Be True | ${list}     | # Passes if ${list} is not empty  |471        Variables used like ``${variable}``, as in the examples above, are472        replaced in the expression before evaluation. Variables are also473        available in the evaluation namespace and can be accessed using special474        syntax ``$variable``. This is a new feature in Robot Framework 2.9475        and it is explained more thoroughly in `Evaluating expressions`.476        Examples:477        | Should Be True | $rc < 10          |478        | Should Be True | $status == 'PASS' | # Expected string must be quoted |479        Starting from Robot Framework 2.8, `Should Be True` automatically480        imports Python's [http://docs.python.org/2/library/os.html|os] and481        [http://docs.python.org/2/library/sys.html|sys] modules that contain482        several useful attributes:483        | Should Be True | os.linesep == '\\n'             | # Unixy   |484        | Should Be True | os.linesep == '\\r\\n'          | # Windows |485        | Should Be True | sys.platform == 'darwin'        | # OS X    |486        | Should Be True | sys.platform.startswith('java') | # Jython  |487        """488        if not self._is_true(condition):489            raise AssertionError(msg or "'%s' should be true." % condition)490    def should_be_equal(self, first, second, msg=None, values=True,491                        ignore_case=False):492        """Fails if the given objects are unequal.493        Optional ``msg`` and ``values`` arguments specify how to construct494        the error message if this keyword fails:495        - If ``msg`` is not given, the error message is ``<first> != <second>``.496        - If ``msg`` is given and ``values`` gets a true value (default),497          the error message is ``<msg>: <first> != <second>``.498        - If ``msg`` is given and ``values`` gets a false value, the error499          message is simply ``<msg>``. See `Boolean arguments` for more details500          about using false values.501        If ``ignore_case`` is given a true value (see `Boolean arguments`) and502        arguments are strings, it indicates that comparison should be503        case-insensitive. New option in Robot Framework 3.0.1.504        If both arguments are multiline strings, the comparison is done using505        `multiline string comparisons`.506        Examples:507        | Should Be Equal | ${x} | expected |508        | Should Be Equal | ${x} | expected | Custom error message |509        | Should Be Equal | ${x} | expected | Custom message | values=False |510        | Should Be Equal | ${x} | expected | ignore_case=True |511        """512        self._log_types_at_info_if_different(first, second)513        if is_truthy(ignore_case) and is_string(first) and is_string(second):514            first = first.lower()515            second = second.lower()516        self._should_be_equal(first, second, msg, values)517    def _should_be_equal(self, first, second, msg, values):518        if first == second:519            return520        include_values = self._include_values(values)521        if include_values and is_string(first) and is_string(second):522            self._raise_multi_diff(first, second)523        assert_equal(first, second, msg, include_values)524    def _log_types_at_info_if_different(self, first, second):525        level = 'DEBUG' if type(first) == type(second) else 'INFO'526        self._log_types_at_level(level, first, second)527    def _raise_multi_diff(self, first, second):528        first_lines, second_lines = first.splitlines(), second.splitlines()529        if len(first_lines) < 3 or len(second_lines) < 3:530            return531        self.log("%s\n!=\n%s" % (first, second))532        err = 'Multiline strings are different:\n'533        for line in difflib.unified_diff(first_lines, second_lines,534                                         fromfile='first', tofile='second',535                                         lineterm=''):536            err += line + '\n'537        raise AssertionError(err)538    def _include_values(self, values):539        return is_truthy(values) and str(values).upper() != 'NO VALUES'540    def should_not_be_equal(self, first, second, msg=None, values=True,541                            ignore_case=False):542        """Fails if the given objects are equal.543        See `Should Be Equal` for an explanation on how to override the default544        error message with ``msg`` and ``values``.545        If ``ignore_case`` is given a true value (see `Boolean arguments`) and546        both arguments are strings, it indicates that comparison should be547        case-insensitive. New option in Robot Framework 3.0.1.548        """549        self._log_types_at_info_if_different(first, second)550        if is_truthy(ignore_case) and is_string(first) and is_string(second):551            first = first.lower()552            second = second.lower()553        self._should_not_be_equal(first, second, msg, values)554    def _should_not_be_equal(self, first, second, msg, values):555        assert_not_equal(first, second, msg, self._include_values(values))556    def should_not_be_equal_as_integers(self, first, second, msg=None,557                                        values=True, base=None):558        """Fails if objects are equal after converting them to integers.559        See `Convert To Integer` for information how to convert integers from560        other bases than 10 using ``base`` argument or ``0b/0o/0x`` prefixes.561        See `Should Be Equal` for an explanation on how to override the default562        error message with ``msg`` and ``values``.563        See `Should Be Equal As Integers` for some usage examples.564        """565        self._log_types_at_info_if_different(first, second)566        self._should_not_be_equal(self._convert_to_integer(first, base),567                                  self._convert_to_integer(second, base),568                                  msg, values)569    def should_be_equal_as_integers(self, first, second, msg=None, values=True,570                                    base=None):571        """Fails if objects are unequal after converting them to integers.572        See `Convert To Integer` for information how to convert integers from573        other bases than 10 using ``base`` argument or ``0b/0o/0x`` prefixes.574        See `Should Be Equal` for an explanation on how to override the default575        error message with ``msg`` and ``values``.576        Examples:577        | Should Be Equal As Integers | 42   | ${42} | Error message |578        | Should Be Equal As Integers | ABCD | abcd  | base=16 |579        | Should Be Equal As Integers | 0b1011 | 11  |580        """581        self._log_types_at_info_if_different(first, second)582        self._should_be_equal(self._convert_to_integer(first, base),583                              self._convert_to_integer(second, base),584                              msg, values)585    def should_not_be_equal_as_numbers(self, first, second, msg=None,586                                       values=True, precision=6):587        """Fails if objects are equal after converting them to real numbers.588        The conversion is done with `Convert To Number` keyword using the589        given ``precision``.590        See `Should Be Equal As Numbers` for examples on how to use591        ``precision`` and why it does not always work as expected. See also592        `Should Be Equal` for an explanation on how to override the default593        error message with ``msg`` and ``values``.594        """595        self._log_types_at_info_if_different(first, second)596        first = self._convert_to_number(first, precision)597        second = self._convert_to_number(second, precision)598        self._should_not_be_equal(first, second, msg, values)599    def should_be_equal_as_numbers(self, first, second, msg=None, values=True,600                                   precision=6):601        """Fails if objects are unequal after converting them to real numbers.602        The conversion is done with `Convert To Number` keyword using the603        given ``precision``.604        Examples:605        | Should Be Equal As Numbers | ${x} | 1.1 | | # Passes if ${x} is 1.1 |606        | Should Be Equal As Numbers | 1.123 | 1.1 | precision=1  | # Passes |607        | Should Be Equal As Numbers | 1.123 | 1.4 | precision=0  | # Passes |608        | Should Be Equal As Numbers | 112.3 | 75  | precision=-2 | # Passes |609        As discussed in the documentation of `Convert To Number`, machines610        generally cannot store floating point numbers accurately. Because of611        this limitation, comparing floats for equality is problematic and612        a correct approach to use depends on the context. This keyword uses613        a very naive approach of rounding the numbers before comparing them,614        which is both prone to rounding errors and does not work very well if615        numbers are really big or small. For more information about comparing616        floats, and ideas on how to implement your own context specific617        comparison algorithm, see618        http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/.619        See `Should Not Be Equal As Numbers` for a negative version of this620        keyword and `Should Be Equal` for an explanation on how to override621        the default error message with ``msg`` and ``values``.622        """623        self._log_types_at_info_if_different(first, second)624        first = self._convert_to_number(first, precision)625        second = self._convert_to_number(second, precision)626        self._should_be_equal(first, second, msg, values)627    def should_not_be_equal_as_strings(self, first, second, msg=None,628                                       values=True, ignore_case=False):629        """Fails if objects are equal after converting them to strings.630        If ``ignore_case`` is given a true value (see `Boolean arguments`), it631        indicates that comparison should be case-insensitive. New option in632        Robot Framework 3.0.1.633        See `Should Be Equal` for an explanation on how to override the default634        error message with ``msg`` and ``values``.635        """636        self._log_types_at_info_if_different(first, second)637        first = self._convert_to_string(first)638        second = self._convert_to_string(second)639        if is_truthy(ignore_case):640            first = first.lower()641            second = second.lower()642        self._should_not_be_equal(first, second, msg, values)643    def should_be_equal_as_strings(self, first, second, msg=None, values=True,644                                   ignore_case=False):645        """Fails if objects are unequal after converting them to strings.646        See `Should Be Equal` for an explanation on how to override the default647        error message with ``msg`` and ``values``.648        If ``ignore_case`` is given a true value (see `Boolean arguments`), it649        indicates that comparison should be case-insensitive. New option in650        Robot Framework 3.0.1.651        If both arguments are multiline strings, the comparison is done using652        `multiline string comparisons`.653        """654        self._log_types_at_info_if_different(first, second)655        first = self._convert_to_string(first)656        second = self._convert_to_string(second)657        if is_truthy(ignore_case):658            first = first.lower()659            second = second.lower()660        self._should_be_equal(first, second, msg, values)661    def should_not_start_with(self, str1, str2, msg=None, values=True,662                              ignore_case=False):663        """Fails if the string ``str1`` starts with the string ``str2``.664        See `Should Be Equal` for an explanation on how to override the default665        error message with ``msg`` and ``values``, as well as for semantics666        of the ``ignore_case`` option.667        """668        if is_truthy(ignore_case):669            str1 = str1.lower()670            str2 = str2.lower()671        if str1.startswith(str2):672            raise AssertionError(self._get_string_msg(str1, str2, msg, values,673                                                      'starts with'))674    def should_start_with(self, str1, str2, msg=None, values=True,675                          ignore_case=False):676        """Fails if the string ``str1`` does not start with the string ``str2``.677        See `Should Be Equal` for an explanation on how to override the default678        error message with ``msg`` and ``values``, as well as for semantics679        of the ``ignore_case`` option.680        """681        if is_truthy(ignore_case):682            str1 = str1.lower()683            str2 = str2.lower()684        if not str1.startswith(str2):685            raise AssertionError(self._get_string_msg(str1, str2, msg, values,686                                                      'does not start with'))687    def should_not_end_with(self, str1, str2, msg=None, values=True,688                            ignore_case=False):689        """Fails if the string ``str1`` ends with the string ``str2``.690        See `Should Be Equal` for an explanation on how to override the default691        error message with ``msg`` and ``values``, as well as for semantics692        of the ``ignore_case`` option.693        """694        if is_truthy(ignore_case):695            str1 = str1.lower()696            str2 = str2.lower()697        if str1.endswith(str2):698            raise AssertionError(self._get_string_msg(str1, str2, msg, values,699                                                      'ends with'))700    def should_end_with(self, str1, str2, msg=None, values=True,701                        ignore_case=False):702        """Fails if the string ``str1`` does not end with the string ``str2``.703        See `Should Be Equal` for an explanation on how to override the default704        error message with ``msg`` and ``values``, as well as for semantics705        of the ``ignore_case`` option.706        """707        if is_truthy(ignore_case):708            str1 = str1.lower()709            str2 = str2.lower()710        if not str1.endswith(str2):711            raise AssertionError(self._get_string_msg(str1, str2, msg, values,712                                                      'does not end with'))713    def should_not_contain(self, container, item, msg=None, values=True,714                           ignore_case=False):715        """Fails if ``container`` contains ``item`` one or more times.716        Works with strings, lists, and anything that supports Python's ``in``717        operator.718        See `Should Be Equal` for an explanation on how to override the default719        error message with arguments ``msg`` and ``values``. ``ignore_case``720        has exactly the same semantics as with `Should Contain`.721        Examples:722        | Should Not Contain | ${some list} | value  |723        | Should Not Contain | ${output}    | FAILED | ignore_case=True |724        """725        # TODO: It is inconsistent that errors show original case in 'container'726        # 'item' is in lower case. Should rather show original case everywhere727        # and add separate '(case-insensitive)' not to the error message.728        # This same logic should be used with all keywords supporting729        # case-insensitive comparisons.730        orig_container = container731        if is_truthy(ignore_case) and is_string(item):732            item = item.lower()733            if is_string(container):734                container = container.lower()735            elif is_list_like(container):736                container = set(x.lower() if is_string(x) else x for x in container)737        if item in container:738            raise AssertionError(self._get_string_msg(orig_container, item, msg,739                                                      values, 'contains'))740    def should_contain(self, container, item, msg=None, values=True,741                       ignore_case=False):742        """Fails if ``container`` does not contain ``item`` one or more times.743        Works with strings, lists, and anything that supports Python's ``in``744        operator.745        See `Should Be Equal` for an explanation on how to override the default746        error message with arguments ``msg`` and ``values``.747        If ``ignore_case`` is given a true value (see `Boolean arguments`) and748        compared items are strings, it indicates that comparison should be749        case-insensitive. If the ``container`` is a list-like object, string750        items in it are compared case-insensitively. New option in Robot751        Framework 3.0.1.752        Examples:753        | Should Contain | ${output}    | PASS  |754        | Should Contain | ${some list} | value | msg=Failure! | values=False |755        | Should Contain | ${some list} | value | case_insensitive=True |756        """757        orig_container = container758        if is_truthy(ignore_case) and is_string(item):759            item = item.lower()760            if is_string(container):761                container = container.lower()762            elif is_list_like(container):763                container = set(x.lower() if is_string(x) else x for x in container)764        if item not in container:765            raise AssertionError(self._get_string_msg(orig_container, item, msg,766                                                      values, 'does not contain'))767    def should_contain_any(self, container, *items, **configuration):768        """Fails if ``container`` does not contain any of the ``*items``.769        Works with strings, lists, and anything that supports Python's ``in``770        operator.771        Supports additional configuration parameters ``msg``, ``values``772        and ``ignore_case``, which have exactly the same semantics as arguments773        with same names have with `Should Contain`. These arguments must774        always be given using ``name=value`` syntax after all ``items``.775        Note that possible equal signs in ``items`` must be escaped with776        a backslash (e.g. ``foo\\=bar``) to avoid them to be passed in777        as ``**configuration``.778        Examples:779        | Should Contain Any | ${string} | substring 1 | substring 2 |780        | Should Contain Any | ${list}   | item 1 | item 2 | item 3 |781        | Should Contain Any | ${list}   | item 1 | item 2 | item 3 | ignore_case=True |782        | Should Contain Any | ${list}   | @{items} | msg=Custom message | values=False |783        New in Robot Framework 3.0.1.784        """785        msg = configuration.pop('msg', None)786        values = configuration.pop('values', True)787        ignore_case = configuration.pop('ignore_case', False)788        if configuration:789            raise RuntimeError("Unsupported configuration parameter%s: %s."790                               % (s(configuration),791                                  seq2str(sorted(configuration))))792        if not items:793            raise RuntimeError('One or more items required.')794        orig_container = container795        if is_truthy(ignore_case):796            items = [x.lower() if is_string(x) else x for x in items]797            if is_string(container):798                container = container.lower()799            elif is_list_like(container):800                container = set(x.lower() if is_string(x) else x for x in container)801        if not any(item in container for item in items):802            msg = self._get_string_msg(orig_container,803                                       seq2str(items, lastsep=' or '),804                                       msg, values,805                                       'does not contain any of',806                                       quote_item2=False)807            raise AssertionError(msg)808    def should_not_contain_any(self, container, *items, **configuration):809        """Fails if ``container`` contains one or more of the ``*items``.810        Works with strings, lists, and anything that supports Python's ``in``811        operator.812        Supports additional configuration parameters ``msg``, ``values``813        and ``ignore_case``, which have exactly the same semantics as arguments814        with same names have with `Should Contain`. These arguments must815        always be given using ``name=value`` syntax after all ``items``.816        Note that possible equal signs in ``items`` must be escaped with817        a backslash (e.g. ``foo\\=bar``) to avoid them to be passed in818        as ``**configuration``.819        Examples:820        | Should Not Contain Any | ${string} | substring 1 | substring 2 |821        | Should Not Contain Any | ${list}   | item 1 | item 2 | item 3 |822        | Should Not Contain Any | ${list}   | item 1 | item 2 | item 3 | ignore_case=True |823        | Should Not Contain Any | ${list}   | @{items} | msg=Custom message | values=False |824        New in Robot Framework 3.0.1.825        """826        msg = configuration.pop('msg', None)827        values = configuration.pop('values', True)828        ignore_case = configuration.pop('ignore_case', False)829        if configuration:830            raise RuntimeError("Unsupported configuration parameter%s: %s."831                               % (s(configuration),832                                  seq2str(sorted(configuration))))833        if not items:834            raise RuntimeError('One or more items required.')835        orig_container = container836        if is_truthy(ignore_case):837            items = [x.lower() if is_string(x) else x for x in items]838            if is_string(container):839                container = container.lower()840            elif is_list_like(container):841                container = set(x.lower() if is_string(x) else x for x in container)842        if any(item in container for item in items):843            msg = self._get_string_msg(orig_container,844                                       seq2str(items, lastsep=' or '),845                                       msg, values,846                                       'contains one or more of',847                                       quote_item2=False)848            raise AssertionError(msg)849    def should_contain_x_times(self, item1, item2, count, msg=None,850                               ignore_case=False):851        """Fails if ``item1`` does not contain ``item2`` ``count`` times.852        Works with strings, lists and all objects that `Get Count` works853        with. The default error message can be overridden with ``msg`` and854        the actual count is always logged.855        If ``ignore_case`` is given a true value (see `Boolean arguments`) and856        compared items are strings, it indicates that comparison should be857        case-insensitive. If the ``item1`` is a list-like object, string858        items in it are compared case-insensitively. New option in Robot859        Framework 3.0.1.860        Examples:861        | Should Contain X Times | ${output}    | hello | 2 |862        | Should Contain X Times | ${some list} | value | 3 | ignore_case=True |863        """864        # TODO: Rename 'item1' and 'item2' to 'container' and 'item' in RF 3.1.865        # Other 'contain' keywords use these names. And 'Get Count' should too.866        # Cannot be done in minor release due to backwards compatibility.867        # Remember to update it also in the docstring!!868        count = self._convert_to_integer(count)869        orig_item1 = item1870        if is_truthy(ignore_case) and is_string(item2):871            item2 = item2.lower()872            if is_string(item1):873                item1 = item1.lower()874            elif is_list_like(item1):875                item1 = [x.lower() if is_string(x) else x for x in item1]876        x = self.get_count(item1, item2)877        if not msg:878            msg = "'%s' contains '%s' %d time%s, not %d time%s." \879                    % (unic(orig_item1), unic(item2), x, s(x), count, s(count))880        self.should_be_equal_as_integers(x, count, msg, values=False)881    def get_count(self, item1, item2):882        """Returns and logs how many times ``item2`` is found from ``item1``.883        This keyword works with Python strings and lists and all objects884        that either have ``count`` method or can be converted to Python lists.885        Example:886        | ${count} = | Get Count | ${some item} | interesting value |887        | Should Be True | 5 < ${count} < 10 |888        """889        if not hasattr(item1, 'count'):890            try:891                item1 = list(item1)892            except:893                raise RuntimeError("Converting '%s' to list failed: %s"894                                   % (item1, get_error_message()))895        count = item1.count(item2)896        self.log('Item found from the first item %d time%s' % (count, s(count)))897        return count898    def should_not_match(self, string, pattern, msg=None, values=True,899                         ignore_case=False):900        """Fails if the given ``string`` matches the given ``pattern``.901        Pattern matching is similar as matching files in a shell, and it is902        always case-sensitive. In the pattern ``*`` matches to anything and903        ``?`` matches to any single character.904        See `Should Be Equal` for an explanation on how to override the default905        error message with ``msg`` and ``values``, as well as for semantics906        of the ``ignore_case`` option.907        """908        if is_truthy(ignore_case):909            string = string.lower()910            pattern = pattern.lower()911        if self._matches(string, pattern):912            raise AssertionError(self._get_string_msg(string, pattern, msg,913                                                      values, 'matches'))914    def should_match(self, string, pattern, msg=None, values=True,915                     ignore_case=False):916        """Fails unless the given ``string`` matches the given ``pattern``.917        Pattern matching is similar as matching files in a shell, and it is918        always case-sensitive. In the pattern, ``*`` matches to anything and919        ``?`` matches to any single character.920        See `Should Be Equal` for an explanation on how to override the default921        error message with ``msg`` and ``values``, as well as for semantics922        of the ``ignore_case`` option.923        """924        if is_truthy(ignore_case):925            string = string.lower()926            pattern = pattern.lower()927        if not self._matches(string, pattern):928            raise AssertionError(self._get_string_msg(string, pattern, msg,929                                                      values, 'does not match'))930    def should_match_regexp(self, string, pattern, msg=None, values=True):931        """Fails if ``string`` does not match ``pattern`` as a regular expression.932        Regular expression check is implemented using the Python933        [http://docs.python.org/2/library/re.html|re module]. Python's regular934        expression syntax is derived from Perl, and it is thus also very935        similar to the syntax used, for example, in Java, Ruby and .NET.936        Things to note about the regexp syntax in Robot Framework test data:937        1) Backslash is an escape character in the test data, and possible938        backslashes in the pattern must thus be escaped with another backslash939        (e.g. ``\\\\d\\\\w+``).940        2) Strings that may contain special characters, but should be handled941        as literal strings, can be escaped with the `Regexp Escape` keyword.942        3) The given pattern does not need to match the whole string. For943        example, the pattern ``ello`` matches the string ``Hello world!``. If944        a full match is needed, the ``^`` and ``$`` characters can be used to945        denote the beginning and end of the string, respectively. For example,946        ``^ello$`` only matches the exact string ``ello``.947        4) Possible flags altering how the expression is parsed (e.g.948        ``re.IGNORECASE``, ``re.MULTILINE``) can be set by prefixing the949        pattern with the ``(?iLmsux)`` group like ``(?im)pattern``. The950        available flags are ``i`` (case-insensitive), ``m`` (multiline mode),951        ``s`` (dotall mode), ``x`` (verbose), ``u`` (Unicode dependent) and952        ``L`` (locale dependent).953        If this keyword passes, it returns the portion of the string that954        matched the pattern. Additionally, the possible captured groups are955        returned.956        See the `Should Be Equal` keyword for an explanation on how to override957        the default error message with the ``msg`` and ``values`` arguments.958        Examples:959        | Should Match Regexp | ${output} | \\\\d{6}   | # Output contains six numbers  |960        | Should Match Regexp | ${output} | ^\\\\d{6}$ | # Six numbers and nothing more |961        | ${ret} = | Should Match Regexp | Foo: 42 | (?i)foo: \\\\d+ |962        | ${match} | ${group1} | ${group2} = |963        | ...      | Should Match Regexp | Bar: 43 | (Foo|Bar): (\\\\d+) |964        =>965        | ${ret} = 'Foo: 42'966        | ${match} = 'Bar: 43'967        | ${group1} = 'Bar'968        | ${group2} = '43'969        """970        res = re.search(pattern, string)971        if res is None:972            raise AssertionError(self._get_string_msg(string, pattern, msg,973                                                      values, 'does not match'))974        match = res.group(0)975        groups = res.groups()976        if groups:977            return [match] + list(groups)978        return match979    def should_not_match_regexp(self, string, pattern, msg=None, values=True):980        """Fails if ``string`` matches ``pattern`` as a regular expression.981        See `Should Match Regexp` for more information about arguments.982        """983        if re.search(pattern, string) is not None:984            raise AssertionError(self._get_string_msg(string, pattern, msg,985                                                      values, 'matches'))986    def get_length(self, item):987        """Returns and logs the length of the given item as an integer.988        The item can be anything that has a length, for example, a string,989        a list, or a mapping. The keyword first tries to get the length with990        the Python function ``len``, which calls the  item's ``__len__`` method991        internally. If that fails, the keyword tries to call the item's992        possible ``length`` and ``size`` methods directly. The final attempt is993        trying to get the value of the item's ``length`` attribute. If all994        these attempts are unsuccessful, the keyword fails.995        Examples:996        | ${length} = | Get Length    | Hello, world! |        |997        | Should Be Equal As Integers | ${length}     | 13     |998        | @{list} =   | Create List   | Hello,        | world! |999        | ${length} = | Get Length    | ${list}       |        |1000        | Should Be Equal As Integers | ${length}     | 2      |1001        See also `Length Should Be`, `Should Be Empty` and `Should Not Be1002        Empty`.1003        """1004        length = self._get_length(item)1005        self.log('Length is %d' % length)1006        return length1007    def _get_length(self, item):1008        try:1009            return len(item)1010        except RERAISED_EXCEPTIONS:1011            raise1012        except:1013            try:1014                return item.length()1015            except RERAISED_EXCEPTIONS:1016                raise1017            except:1018                try:1019                    return item.size()1020                except RERAISED_EXCEPTIONS:1021                    raise1022                except:1023                    try:1024                        return item.length1025                    except RERAISED_EXCEPTIONS:1026                        raise1027                    except:1028                        raise RuntimeError("Could not get length of '%s'." % item)1029    def length_should_be(self, item, length, msg=None):1030        """Verifies that the length of the given item is correct.1031        The length of the item is got using the `Get Length` keyword. The1032        default error message can be overridden with the ``msg`` argument.1033        """1034        length = self._convert_to_integer(length)1035        actual = self.get_length(item)1036        if actual != length:1037            raise AssertionError(msg or "Length of '%s' should be %d but is %d."1038                                        % (item, length, actual))1039    def should_be_empty(self, item, msg=None):1040        """Verifies that the given item is empty.1041        The length of the item is got using the `Get Length` keyword. The1042        default error message can be overridden with the ``msg`` argument.1043        """1044        if self.get_length(item) > 0:1045            raise AssertionError(msg or "'%s' should be empty." % item)1046    def should_not_be_empty(self, item, msg=None):1047        """Verifies that the given item is not empty.1048        The length of the item is got using the `Get Length` keyword. The1049        default error message can be overridden with the ``msg`` argument.1050        """1051        if self.get_length(item) == 0:1052            raise AssertionError(msg or "'%s' should not be empty." % item)1053    def _get_string_msg(self, item1, item2, custom_message, include_values,1054                        delimiter, quote_item1=True, quote_item2=True):1055        if custom_message and not self._include_values(include_values):1056            return custom_message1057        item1 = "'%s'" % unic(item1) if quote_item1 else unic(item1)1058        item2 = "'%s'" % unic(item2) if quote_item2 else unic(item2)1059        default_message = '%s %s %s' % (item1, delimiter, item2)1060        if not custom_message:1061            return default_message1062        return '%s: %s' % (custom_message, default_message)1063class _Variables(_BuiltInBase):1064    def get_variables(self, no_decoration=False):1065        """Returns a dictionary containing all variables in the current scope.1066        Variables are returned as a special dictionary that allows accessing1067        variables in space, case, and underscore insensitive manner similarly1068        as accessing variables in the test data. This dictionary supports all1069        same operations as normal Python dictionaries and, for example,1070        Collections library can be used to access or modify it. Modifying the1071        returned dictionary has no effect on the variables available in the1072        current scope.1073        By default variables are returned with ``${}``, ``@{}`` or ``&{}``1074        decoration based on variable types. Giving a true value (see `Boolean1075        arguments`) to the optional argument ``no_decoration`` will return1076        the variables without the decoration. This option is new in Robot1077        Framework 2.9.1078        Example:1079        | ${example_variable} =         | Set Variable | example value         |1080        | ${variables} =                | Get Variables |                      |1081        | Dictionary Should Contain Key | ${variables} | \\${example_variable} |1082        | Dictionary Should Contain Key | ${variables} | \\${ExampleVariable}  |1083        | Set To Dictionary             | ${variables} | \\${name} | value     |1084        | Variable Should Not Exist     | \\${name}    |           |           |1085        | ${no decoration} =            | Get Variables | no_decoration=Yes |1086        | Dictionary Should Contain Key | ${no decoration} | example_variable |1087        Note: Prior to Robot Framework 2.7.4 variables were returned as1088        a custom object that did not support all dictionary methods.1089        """1090        return self._variables.as_dict(decoration=is_falsy(no_decoration))1091    @run_keyword_variant(resolve=0)1092    def get_variable_value(self, name, default=None):1093        """Returns variable value or ``default`` if the variable does not exist.1094        The name of the variable can be given either as a normal variable name1095        (e.g. ``${NAME}``) or in escaped format (e.g. ``\\${NAME}``). Notice1096        that the former has some limitations explained in `Set Suite Variable`.1097        Examples:1098        | ${x} = | Get Variable Value | ${a} | default |1099        | ${y} = | Get Variable Value | ${a} | ${b}    |1100        | ${z} = | Get Variable Value | ${z} |         |1101        =>1102        | ${x} gets value of ${a} if ${a} exists and string 'default' otherwise1103        | ${y} gets value of ${a} if ${a} exists and value of ${b} otherwise1104        | ${z} is set to Python None if it does not exist previously1105        See `Set Variable If` for another keyword to set variables dynamically.1106        """1107        try:1108            return self._variables[self._get_var_name(name)]1109        except DataError:1110            return self._variables.replace_scalar(default)1111    def log_variables(self, level='INFO'):1112        """Logs all variables in the current scope with given log level."""1113        variables = self.get_variables()1114        for name in sorted(variables, key=lambda s: s[2:-1].lower()):1115            msg = format_assign_message(name, variables[name], cut_long=False)1116            self.log(msg, level)1117    @run_keyword_variant(resolve=0)1118    def variable_should_exist(self, name, msg=None):1119        """Fails unless the given variable exists within the current scope.1120        The name of the variable can be given either as a normal variable name1121        (e.g. ``${NAME}``) or in escaped format (e.g. ``\\${NAME}``). Notice1122        that the former has some limitations explained in `Set Suite Variable`.1123        The default error message can be overridden with the ``msg`` argument.1124        See also `Variable Should Not Exist` and `Keyword Should Exist`.1125        """1126        name = self._get_var_name(name)1127        msg = self._variables.replace_string(msg) if msg \1128            else "Variable %s does not exist." % name1129        try:1130            self._variables[name]1131        except DataError:1132            raise AssertionError(msg)1133    @run_keyword_variant(resolve=0)1134    def variable_should_not_exist(self, name, msg=None):1135        """Fails if the given variable exists within the current scope.1136        The name of the variable can be given either as a normal variable name1137        (e.g. ``${NAME}``) or in escaped format (e.g. ``\\${NAME}``). Notice1138        that the former has some limitations explained in `Set Suite Variable`.1139        The default error message can be overridden with the ``msg`` argument.1140        See also `Variable Should Exist` and `Keyword Should Exist`.1141        """1142        name = self._get_var_name(name)1143        msg = self._variables.replace_string(msg) if msg \1144            else "Variable %s exists." % name1145        try:1146            self._variables[name]1147        except DataError:1148            pass1149        else:1150            raise AssertionError(msg)1151    def replace_variables(self, text):1152        """Replaces variables in the given text with their current values.1153        If the text contains undefined variables, this keyword fails.1154        If the given ``text`` contains only a single variable, its value is1155        returned as-is and it can be any object. Otherwise this keyword1156        always returns a string.1157        Example:1158        The file ``template.txt`` contains ``Hello ${NAME}!`` and variable1159        ``${NAME}`` has the value ``Robot``.1160        | ${template} =   | Get File          | ${CURDIR}/template.txt |1161        | ${message} =    | Replace Variables | ${template}            |1162        | Should Be Equal | ${message}        | Hello Robot!           |1163        """1164        return self._variables.replace_scalar(text)1165    def set_variable(self, *values):1166        """Returns the given values which can then be assigned to a variables.1167        This keyword is mainly used for setting scalar variables.1168        Additionally it can be used for converting a scalar variable1169        containing a list to a list variable or to multiple scalar variables.1170        It is recommended to use `Create List` when creating new lists.1171        Examples:1172        | ${hi} =   | Set Variable | Hello, world! |1173        | ${hi2} =  | Set Variable | I said: ${hi} |1174        | ${var1}   | ${var2} =    | Set Variable | Hello | world |1175        | @{list} = | Set Variable | ${list with some items} |1176        | ${item1}  | ${item2} =   | Set Variable  | ${list with 2 items} |1177        Variables created with this keyword are available only in the1178        scope where they are created. See `Set Global Variable`,1179        `Set Test Variable` and `Set Suite Variable` for information on how to1180        set variables so that they are available also in a larger scope.1181        """1182        if len(values) == 0:1183            return ''1184        elif len(values) == 1:1185            return values[0]1186        else:1187            return list(values)1188    @run_keyword_variant(resolve=0)1189    def set_test_variable(self, name, *values):1190        """Makes a variable available everywhere within the scope of the current test.1191        Variables set with this keyword are available everywhere within the1192        scope of the currently executed test case. For example, if you set a1193        variable in a user keyword, it is available both in the test case level1194        and also in all other user keywords used in the current test. Other1195        test cases will not see variables set with this keyword.1196        See `Set Suite Variable` for more information and examples.1197        """1198        name = self._get_var_name(name)1199        value = self._get_var_value(name, values)1200        self._variables.set_test(name, value)1201        self._log_set_variable(name, value)1202    @run_keyword_variant(resolve=0)1203    def set_suite_variable(self, name, *values):1204        """Makes a variable available everywhere within the scope of the current suite.1205        Variables set with this keyword are available everywhere within the1206        scope of the currently executed test suite. Setting variables with this1207        keyword thus has the same effect as creating them using the Variable1208        table in the test data file or importing them from variable files.1209        Possible child test suites do not see variables set with this keyword1210        by default. Starting from Robot Framework 2.9, that can be controlled1211        by using ``children=<option>`` as the last argument. If the specified1212        ``<option>`` is a non-empty string or any other value considered true1213        in Python, the variable is set also to the child suites. Parent and1214        sibling suites will never see variables set with this keyword.1215        The name of the variable can be given either as a normal variable name1216        (e.g. ``${NAME}``) or in escaped format as ``\\${NAME}`` or ``$NAME``.1217        Variable value can be given using the same syntax as when variables1218        are created in the Variable table.1219        If a variable already exists within the new scope, its value will be1220        overwritten. Otherwise a new variable is created. If a variable already1221        exists within the current scope, the value can be left empty and the1222        variable within the new scope gets the value within the current scope.1223        Examples:1224        | Set Suite Variable | ${SCALAR} | Hello, world! |1225        | Set Suite Variable | ${SCALAR} | Hello, world! | children=true |1226        | Set Suite Variable | @{LIST}   | First item    | Second item   |1227        | Set Suite Variable | &{DICT}   | key=value     | foo=bar       |1228        | ${ID} =            | Get ID    |1229        | Set Suite Variable | ${ID}     |1230        To override an existing value with an empty value, use built-in1231        variables ``${EMPTY}``, ``@{EMPTY}`` or ``&{EMPTY}``:1232        | Set Suite Variable | ${SCALAR} | ${EMPTY} |1233        | Set Suite Variable | @{LIST}   | @{EMPTY} | # New in RF 2.7.4 |1234        | Set Suite Variable | &{DICT}   | &{EMPTY} | # New in RF 2.9   |1235        *NOTE:* If the variable has value which itself is a variable (escaped1236        or not), you must always use the escaped format to set the variable:1237        Example:1238        | ${NAME} =          | Set Variable | \\${var} |1239        | Set Suite Variable | ${NAME}      | value | # Sets variable ${var}  |1240        | Set Suite Variable | \\${NAME}    | value | # Sets variable ${NAME} |1241        This limitation applies also to `Set Test Variable`, `Set Global1242        Variable`, `Variable Should Exist`, `Variable Should Not Exist` and1243        `Get Variable Value` keywords.1244        """1245        name = self._get_var_name(name)1246        if (values and is_string(values[-1]) and1247                values[-1].startswith('children=')):1248            children = self._variables.replace_scalar(values[-1][9:])1249            children = is_truthy(children)1250            values = values[:-1]1251        else:1252            children = False1253        value = self._get_var_value(name, values)1254        self._variables.set_suite(name, value, children=children)1255        self._log_set_variable(name, value)1256    @run_keyword_variant(resolve=0)1257    def set_global_variable(self, name, *values):1258        """Makes a variable available globally in all tests and suites.1259        Variables set with this keyword are globally available in all test1260        cases and suites executed after setting them. Setting variables with1261        this keyword thus has the same effect as creating from the command line1262        using the options ``--variable`` or ``--variablefile``. Because this1263        keyword can change variables everywhere, it should be used with care.1264        See `Set Suite Variable` for more information and examples.1265        """1266        name = self._get_var_name(name)1267        value = self._get_var_value(name, values)1268        self._variables.set_global(name, value)1269        self._log_set_variable(name, value)1270    # Helpers1271    def _get_var_name(self, orig):1272        name = self._resolve_possible_variable(orig)1273        try:1274            return self._unescape_variable_if_needed(name)1275        except ValueError:1276            raise RuntimeError("Invalid variable syntax '%s'." % orig)1277    def _resolve_possible_variable(self, name):1278        try:1279            resolved = self._variables.replace_string(name)1280            return self._unescape_variable_if_needed(resolved)1281        except (KeyError, ValueError, DataError):1282            return name1283    def _unescape_variable_if_needed(self, name):1284        if name.startswith('\\'):1285            name = name[1:]1286        if len(name) < 2:1287            raise ValueError1288        if name[0] in '$@&' and name[1] != '{':1289            name = '%s{%s}' % (name[0], name[1:])1290        if is_var(name):1291            return name1292        # Support for possible internal variables (issue 397)1293        name = '%s{%s}' % (name[0], self.replace_variables(name[2:-1]))1294        if is_var(name):1295            return name1296        raise ValueError1297    def _get_var_value(self, name, values):1298        if not values:1299            return self._variables[name]1300        if name[0] == '$':1301            # We could consider catenating values similarly as when creating1302            # scalar variables in the variable table, but that would require1303            # handling non-string values somehow. For details see1304            # https://github.com/robotframework/robotframework/issues/19191305            if len(values) != 1 or VariableSplitter(values[0]).is_list_variable():1306                raise DataError("Setting list value to scalar variable '%s' "1307                                "is not supported anymore. Create list "1308                                "variable '@%s' instead." % (name, name[1:]))1309            return self._variables.replace_scalar(values[0])1310        return VariableTableValue(values, name).resolve(self._variables)1311    def _log_set_variable(self, name, value):1312        self.log(format_assign_message(name, value))1313class _RunKeyword(_BuiltInBase):1314    # If you use any of these run keyword variants from another library, you1315    # should register those keywords with 'register_run_keyword' method. See1316    # the documentation of that method at the end of this file. There are also1317    # other run keyword variant keywords in BuiltIn which can also be seen1318    # at the end of this file.1319    @run_keyword_variant(resolve=1)1320    def run_keyword(self, name, *args):1321        """Executes the given keyword with the given arguments.1322        Because the name of the keyword to execute is given as an argument, it1323        can be a variable and thus set dynamically, e.g. from a return value of1324        another keyword or from the command line.1325        """1326        if not is_string(name):1327            raise RuntimeError('Keyword name must be a string.')1328        kw = Keyword(name, args=args)1329        return kw.run(self._context)1330    @run_keyword_variant(resolve=0)1331    def run_keywords(self, *keywords):1332        """Executes all the given keywords in a sequence.1333        This keyword is mainly useful in setups and teardowns when they need1334        to take care of multiple actions and creating a new higher level user1335        keyword would be an overkill.1336        By default all arguments are expected to be keywords to be executed.1337        Examples:1338        | Run Keywords | Initialize database | Start servers | Clear logs |1339        | Run Keywords | ${KW 1} | ${KW 2} |1340        | Run Keywords | @{KEYWORDS} |1341        Starting from Robot Framework 2.7.6, keywords can also be run with1342        arguments using upper case ``AND`` as a separator between keywords.1343        The keywords are executed so that the first argument is the first1344        keyword and proceeding arguments until the first ``AND`` are arguments1345        to it. First argument after the first ``AND`` is the second keyword and1346        proceeding arguments until the next ``AND`` are its arguments. And so on.1347        Examples:1348        | Run Keywords | Initialize database | db1 | AND | Start servers | server1 | server2 |1349        | Run Keywords | Initialize database | ${DB NAME} | AND | Start servers | @{SERVERS} | AND | Clear logs |1350        | Run Keywords | ${KW} | AND | @{KW WITH ARGS} |1351        Notice that the ``AND`` control argument must be used explicitly and1352        cannot itself come from a variable. If you need to use literal ``AND``1353        string as argument, you can either use variables or escape it with1354        a backslash like ``\\AND``.1355        """1356        self._run_keywords(self._split_run_keywords(list(keywords)))1357    def _run_keywords(self, iterable):1358        errors = []1359        for kw, args in iterable:1360            try:1361                self.run_keyword(kw, *args)1362            except ExecutionPassed as err:1363                err.set_earlier_failures(errors)1364                raise err1365            except ExecutionFailed as err:1366                errors.extend(err.get_errors())1367                if not err.can_continue(self._context.in_teardown):1368                    break1369        if errors:1370            raise ExecutionFailures(errors)1371    def _split_run_keywords(self, keywords):1372        if 'AND' not in keywords:1373            for name in self._variables.replace_list(keywords):1374                yield name, ()1375        else:1376            for name, args in self._split_run_keywords_from_and(keywords):1377                yield name, args1378    def _split_run_keywords_from_and(self, keywords):1379        while 'AND' in keywords:1380            index = keywords.index('AND')1381            yield self._resolve_run_keywords_name_and_args(keywords[:index])1382            keywords = keywords[index+1:]1383        yield self._resolve_run_keywords_name_and_args(keywords)1384    def _resolve_run_keywords_name_and_args(self, kw_call):1385        kw_call = self._variables.replace_list(kw_call, replace_until=1)1386        if not kw_call:1387            raise DataError('Incorrect use of AND')1388        return kw_call[0], kw_call[1:]1389    @run_keyword_variant(resolve=2)1390    def run_keyword_if(self, condition, name, *args):1391        """Runs the given keyword with the given arguments, if ``condition`` is true.1392        The given ``condition`` is evaluated in Python as explained in1393        `Evaluating expressions`, and ``name`` and ``*args`` have same1394        semantics as with `Run Keyword`.1395        Example, a simple if/else construct:1396        | ${status} | ${value} = | `Run Keyword And Ignore Error` | `My Keyword` |1397        | `Run Keyword If`     | '${status}' == 'PASS' | `Some Action`    | arg |1398        | `Run Keyword Unless` | '${status}' == 'PASS' | `Another Action` |1399        In this example, only either `Some Action` or `Another Action` is1400        executed, based on the status of `My Keyword`. Instead of `Run Keyword1401        And Ignore Error` you can also use `Run Keyword And Return Status`.1402        Variables used like ``${variable}``, as in the examples above, are1403        replaced in the expression before evaluation. Variables are also1404        available in the evaluation namespace and can be accessed using special1405        syntax ``$variable``. This is a new feature in Robot Framework 2.91406        and it is explained more thoroughly in `Evaluating expressions`.1407        Example:1408        | `Run Keyword If` | $result is None or $result == 'FAIL' | `Keyword` |1409        Starting from Robot version 2.7.4, this keyword supports also optional1410        ELSE and ELSE IF branches. Both of these are defined in ``*args`` and1411        must use exactly format ``ELSE`` or ``ELSE IF``, respectively. ELSE1412        branches must contain first the name of the keyword to execute and then1413        its possible arguments. ELSE IF branches must first contain a condition,1414        like the first argument to this keyword, and then the keyword to execute1415        and its possible arguments. It is possible to have ELSE branch after1416        ELSE IF and to have multiple ELSE IF branches.1417        Given previous example, if/else construct can also be created like this:1418        | ${status} | ${value} = | `Run Keyword And Ignore Error` | My Keyword |1419        | `Run Keyword If` | '${status}' == 'PASS' | `Some Action` | arg | ELSE | `Another Action` |1420        The return value is the one of the keyword that was executed or None if1421        no keyword was executed (i.e. if ``condition`` was false). Hence, it is1422        recommended to use ELSE and/or ELSE IF branches to conditionally assign1423        return values from keyword to variables (to conditionally assign fixed1424        values to variables, see `Set Variable If`). This is illustrated by the1425        example below:1426        | ${var1} =   | `Run Keyword If` | ${rc} == 0     | `Some keyword returning a value` |1427        | ...         | ELSE IF          | 0 < ${rc} < 42 | `Another keyword` |1428        | ...         | ELSE IF          | ${rc} < 0      | `Another keyword with args` | ${rc} | arg2 |1429        | ...         | ELSE             | `Final keyword to handle abnormal cases` | ${rc} |1430        | ${var2} =   | `Run Keyword If` | ${condition}  | `Some keyword` |1431        In this example, ${var2} will be set to None if ${condition} is false.1432        Notice that ``ELSE`` and ``ELSE IF`` control words must be used1433        explicitly and thus cannot come from variables. If you need to use1434        literal ``ELSE`` and ``ELSE IF`` strings as arguments, you can escape1435        them with a backslash like ``\\ELSE`` and ``\\ELSE IF``.1436        Starting from Robot Framework 2.8, Python's1437        [http://docs.python.org/2/library/os.html|os] and1438        [http://docs.python.org/2/library/sys.html|sys] modules are1439        automatically imported when evaluating the ``condition``.1440        Attributes they contain can thus be used in the condition:1441        | `Run Keyword If` | os.sep == '/' | `Unix Keyword`        |1442        | ...              | ELSE IF       | sys.platform.startswith('java') | `Jython Keyword` |1443        | ...              | ELSE          | `Windows Keyword`     |1444        """1445        args, branch = self._split_elif_or_else_branch(args)1446        if self._is_true(condition):1447            return self.run_keyword(name, *args)1448        return branch()1449    def _split_elif_or_else_branch(self, args):1450        if 'ELSE IF' in args:1451            args, branch = self._split_branch(args, 'ELSE IF', 2,1452                                              'condition and keyword')1453            return args, lambda: self.run_keyword_if(*branch)1454        if 'ELSE' in args:1455            args, branch = self._split_branch(args, 'ELSE', 1, 'keyword')1456            return args, lambda: self.run_keyword(*branch)1457        return args, lambda: None1458    def _split_branch(self, args, control_word, required, required_error):1459        index = list(args).index(control_word)1460        branch = self._variables.replace_list(args[index+1:], required)1461        if len(branch) < required:1462            raise DataError('%s requires %s.' % (control_word, required_error))1463        return args[:index], branch1464    @run_keyword_variant(resolve=2)1465    def run_keyword_unless(self, condition, name, *args):1466        """Runs the given keyword with the given arguments, if ``condition`` is false.1467        See `Run Keyword If` for more information and an example.1468        """1469        if not self._is_true(condition):1470            return self.run_keyword(name, *args)1471    @run_keyword_variant(resolve=1)1472    def run_keyword_and_ignore_error(self, name, *args):1473        """Runs the given keyword with the given arguments and ignores possible error.1474        This keyword returns two values, so that the first is either string1475        ``PASS`` or ``FAIL``, depending on the status of the executed keyword.1476        The second value is either the return value of the keyword or the1477        received error message. See `Run Keyword And Return Status` If you are1478        only interested in the execution status.1479        The keyword name and arguments work as in `Run Keyword`. See1480        `Run Keyword If` for a usage example.1481        Errors caused by invalid syntax, timeouts, or fatal exceptions are not1482        caught by this keyword. Otherwise this keyword itself never fails.1483        Since Robot Framework 2.9, variable errors are caught by this keyword.1484        """1485        try:1486            return 'PASS', self.run_keyword(name, *args)1487        except ExecutionFailed as err:1488            if err.dont_continue:1489                raise1490            return 'FAIL', unic(err)1491    @run_keyword_variant(resolve=1)1492    def run_keyword_and_return_status(self, name, *args):1493        """Runs the given keyword with given arguments and returns the status as a Boolean value.1494        This keyword returns Boolean ``True`` if the keyword that is executed1495        succeeds and ``False`` if it fails. This is useful, for example, in1496        combination with `Run Keyword If`. If you are interested in the error1497        message or return value, use `Run Keyword And Ignore Error` instead.1498        The keyword name and arguments work as in `Run Keyword`.1499        Example:1500        | ${passed} = | `Run Keyword And Return Status` | Keyword | args |1501        | `Run Keyword If` | ${passed} | Another keyword |1502        Errors caused by invalid syntax, timeouts, or fatal exceptions are not1503        caught by this keyword. Otherwise this keyword itself never fails.1504        New in Robot Framework 2.7.6.1505        """1506        status, _ = self.run_keyword_and_ignore_error(name, *args)1507        return status == 'PASS'1508    @run_keyword_variant(resolve=1)1509    def run_keyword_and_continue_on_failure(self, name, *args):1510        """Runs the keyword and continues execution even if a failure occurs.1511        The keyword name and arguments work as with `Run Keyword`.1512        Example:1513        | Run Keyword And Continue On Failure | Fail | This is a stupid example |1514        | Log | This keyword is executed |1515        The execution is not continued if the failure is caused by invalid syntax,1516        timeout, or fatal exception.1517        Since Robot Framework 2.9, variable errors are caught by this keyword.1518        """1519        try:1520            return self.run_keyword(name, *args)1521        except ExecutionFailed as err:1522            if not err.dont_continue:1523                err.continue_on_failure = True1524            raise err1525    @run_keyword_variant(resolve=2)1526    def run_keyword_and_expect_error(self, expected_error, name, *args):1527        """Runs the keyword and checks that the expected error occurred.1528        The expected error must be given in the same format as in1529        Robot Framework reports. It can be a pattern containing1530        characters ``?``, which matches to any single character and1531        ``*``, which matches to any number of any characters. ``name`` and1532        ``*args`` have same semantics as with `Run Keyword`.1533        If the expected error occurs, the error message is returned and it can1534        be further processed/tested, if needed. If there is no error, or the1535        error does not match the expected error, this keyword fails.1536        Examples:1537        | Run Keyword And Expect Error | My error | Some Keyword | arg1 | arg2 |1538        | ${msg} = | Run Keyword And Expect Error | * | My KW |1539        | Should Start With | ${msg} | Once upon a time in |1540        Errors caused by invalid syntax, timeouts, or fatal exceptions are not1541        caught by this keyword.1542        Since Robot Framework 2.9, variable errors are caught by this keyword.1543        """1544        try:1545            self.run_keyword(name, *args)1546        except ExecutionFailed as err:1547            if err.dont_continue:1548                raise1549            error = err1550        else:1551            raise AssertionError("Expected error '%s' did not occur."1552                                 % expected_error)1553        if not self._matches(unic(error), expected_error):1554            raise AssertionError("Expected error '%s' but got '%s'."1555                                 % (expected_error, error))1556        return unic(error)1557    @run_keyword_variant(resolve=2)1558    def repeat_keyword(self, repeat, name, *args):1559        """Executes the specified keyword multiple times.1560        ``name`` and ``args`` define the keyword that is executed similarly as1561        with `Run Keyword`. ``repeat`` specifies how many times (as a count) or1562        how long time (as a timeout) the keyword should be executed.1563        If ``repeat`` is given as count, it specifies how many times the1564        keyword should be executed. ``repeat`` can be given as an integer or1565        as a string that can be converted to an integer. If it is a string,1566        it can have postfix ``times`` or ``x`` (case and space insensitive)1567        to make the expression more explicit.1568        If ``repeat`` is given as timeout, it must be in Robot Framework's1569        time format (e.g. ``1 minute``, ``2 min 3 s``). Using a number alone1570        (e.g. ``1`` or ``1.5``) does not work in this context.1571        If ``repeat`` is zero or negative, the keyword is not executed at1572        all. This keyword fails immediately if any of the execution1573        rounds fails.1574        Examples:1575        | Repeat Keyword | 5 times   | Go to Previous Page |1576        | Repeat Keyword | ${var}    | Some Keyword | arg1 | arg2 |1577        | Repeat Keyword | 2 minutes | Some Keyword | arg1 | arg2 |1578        Specifying ``repeat`` as a timeout is new in Robot Framework 3.0.1579        """1580        try:1581            count = self._get_repeat_count(repeat)1582        except RuntimeError as err:1583            timeout = self._get_repeat_timeout(repeat)1584            if timeout is None:1585                raise err1586            keywords = self._keywords_repeated_by_timeout(timeout, name, args)1587        else:1588            keywords = self._keywords_repeated_by_count(count, name, args)1589        self._run_keywords(keywords)1590    def _get_repeat_count(self, times, require_postfix=False):1591        times = normalize(str(times))1592        if times.endswith('times'):1593            times = times[:-5]1594        elif times.endswith('x'):1595            times = times[:-1]1596        elif require_postfix:1597            raise ValueError1598        return self._convert_to_integer(times)1599    def _get_repeat_timeout(self, timestr):1600        try:1601            float(timestr)1602        except ValueError:1603            pass1604        else:1605            return None1606        try:1607            return timestr_to_secs(timestr)1608        except ValueError:1609            return None1610    def _keywords_repeated_by_count(self, count, name, args):1611        if count <= 0:1612            self.log("Keyword '%s' repeated zero times." % name)1613        for i in range(count):1614            self.log("Repeating keyword, round %d/%d." % (i + 1, count))1615            yield name, args1616    def _keywords_repeated_by_timeout(self, timeout, name, args):1617        if timeout <= 0:1618            self.log("Keyword '%s' repeated zero times." % name)1619        repeat_round = 01620        maxtime = time.time() + timeout1621        while time.time() < maxtime:1622            repeat_round += 11623            self.log("Repeating keyword, round %d, %s remaining."1624                     % (repeat_round,1625                        secs_to_timestr(maxtime - time.time(), compact=True)))1626            yield name, args1627    @run_keyword_variant(resolve=3)1628    def wait_until_keyword_succeeds(self, retry, retry_interval, name, *args):1629        """Runs the specified keyword and retries if it fails.1630        ``name`` and ``args`` define the keyword that is executed similarly1631        as with `Run Keyword`. How long to retry running the keyword is1632        defined using ``retry`` argument either as timeout or count.1633        ``retry_interval`` is the time to wait before trying to run the1634        keyword again after the previous run has failed.1635        If ``retry`` is given as timeout, it must be in Robot Framework's1636        time format (e.g. ``1 minute``, ``2 min 3 s``, ``4.5``) that is1637        explained in an appendix of Robot Framework User Guide. If it is1638        given as count, it must have ``times`` or ``x`` postfix (e.g.1639        ``5 times``, ``10 x``). ``retry_interval`` must always be given in1640        Robot Framework's time format.1641        If the keyword does not succeed regardless of retries, this keyword1642        fails. If the executed keyword passes, its return value is returned.1643        Examples:1644        | Wait Until Keyword Succeeds | 2 min | 5 sec | My keyword | argument |1645        | ${result} = | Wait Until Keyword Succeeds | 3x | 200ms | My keyword |1646        All normal failures are caught by this keyword. Errors caused by1647        invalid syntax, test or keyword timeouts, or fatal exceptions (caused1648        e.g. by `Fatal Error`) are not caught.1649        Running the same keyword multiple times inside this keyword can create1650        lots of output and considerably increase the size of the generated1651        output files. Starting from Robot Framework 2.7, it is possible to1652        remove unnecessary keywords from the outputs using1653        ``--RemoveKeywords WUKS`` command line option.1654        Support for specifying ``retry`` as a number of times to retry is1655        a new feature in Robot Framework 2.9.1656        Since Robot Framework 2.9, variable errors are caught by this keyword.1657        """1658        maxtime = count = -11659        try:1660            count = self._get_repeat_count(retry, require_postfix=True)1661        except ValueError:1662            timeout = timestr_to_secs(retry)1663            maxtime = time.time() + timeout1664            message = 'for %s' % secs_to_timestr(timeout)1665        else:1666            if count <= 0:1667                raise ValueError('Retry count %d is not positive.' % count)1668            message = '%d time%s' % (count, s(count))1669        retry_interval = timestr_to_secs(retry_interval)1670        while True:1671            try:1672                return self.run_keyword(name, *args)1673            except ExecutionFailed as err:1674                if err.dont_continue:1675                    raise1676                count -= 11677                if time.time() > maxtime > 0 or count == 0:1678                    raise AssertionError("Keyword '%s' failed after retrying "1679                                         "%s. The last error was: %s"1680                                         % (name, message, err))1681                self._sleep_in_parts(retry_interval)1682    @run_keyword_variant(resolve=1)1683    def set_variable_if(self, condition, *values):1684        """Sets variable based on the given condition.1685        The basic usage is giving a condition and two values. The1686        given condition is first evaluated the same way as with the1687        `Should Be True` keyword. If the condition is true, then the1688        first value is returned, and otherwise the second value is1689        returned. The second value can also be omitted, in which case1690        it has a default value None. This usage is illustrated in the1691        examples below, where ``${rc}`` is assumed to be zero.1692        | ${var1} = | Set Variable If | ${rc} == 0 | zero     | nonzero |1693        | ${var2} = | Set Variable If | ${rc} > 0  | value1   | value2  |1694        | ${var3} = | Set Variable If | ${rc} > 0  | whatever |         |1695        =>1696        | ${var1} = 'zero'1697        | ${var2} = 'value2'1698        | ${var3} = None1699        It is also possible to have 'else if' support by replacing the1700        second value with another condition, and having two new values1701        after it. If the first condition is not true, the second is1702        evaluated and one of the values after it is returned based on1703        its truth value. This can be continued by adding more1704        conditions without a limit.1705        | ${var} = | Set Variable If | ${rc} == 0        | zero           |1706        | ...      | ${rc} > 0       | greater than zero | less then zero |1707        |          |1708        | ${var} = | Set Variable If |1709        | ...      | ${rc} == 0      | zero              |1710        | ...      | ${rc} == 1      | one               |1711        | ...      | ${rc} == 2      | two               |1712        | ...      | ${rc} > 2       | greater than two  |1713        | ...      | ${rc} < 0       | less than zero    |1714        Use `Get Variable Value` if you need to set variables1715        dynamically based on whether a variable exist or not.1716        """1717        values = self._verify_values_for_set_variable_if(list(values))1718        if self._is_true(condition):1719            return self._variables.replace_scalar(values[0])1720        values = self._verify_values_for_set_variable_if(values[1:], True)1721        if len(values) == 1:1722            return self._variables.replace_scalar(values[0])1723        return self.run_keyword('BuiltIn.Set Variable If', *values[0:])1724    def _verify_values_for_set_variable_if(self, values, default=False):1725        if not values:1726            if default:1727                return [None]1728            raise RuntimeError('At least one value is required')1729        if is_list_var(values[0]):1730            values[:1] = [escape(item) for item in self._variables[values[0]]]1731            return self._verify_values_for_set_variable_if(values)1732        return values1733    @run_keyword_variant(resolve=1)1734    def run_keyword_if_test_failed(self, name, *args):1735        """Runs the given keyword with the given arguments, if the test failed.1736        This keyword can only be used in a test teardown. Trying to use it1737        anywhere else results in an error.1738        Otherwise, this keyword works exactly like `Run Keyword`, see its1739        documentation for more details.1740        Prior to Robot Framework 2.9 failures in test teardown itself were1741        not detected by this keyword.1742        """1743        test = self._get_test_in_teardown('Run Keyword If Test Failed')1744        if not test.passed:1745            return self.run_keyword(name, *args)1746    @run_keyword_variant(resolve=1)1747    def run_keyword_if_test_passed(self, name, *args):1748        """Runs the given keyword with the given arguments, if the test passed.1749        This keyword can only be used in a test teardown. Trying to use it1750        anywhere else results in an error.1751        Otherwise, this keyword works exactly like `Run Keyword`, see its1752        documentation for more details.1753        Prior to Robot Framework 2.9 failures in test teardown itself were1754        not detected by this keyword.1755        """1756        test = self._get_test_in_teardown('Run Keyword If Test Passed')1757        if test.passed:1758            return self.run_keyword(name, *args)1759    @run_keyword_variant(resolve=1)1760    def run_keyword_if_timeout_occurred(self, name, *args):1761        """Runs the given keyword if either a test or a keyword timeout has occurred.1762        This keyword can only be used in a test teardown. Trying to use it1763        anywhere else results in an error.1764        Otherwise, this keyword works exactly like `Run Keyword`, see its1765        documentation for more details.1766        """1767        self._get_test_in_teardown('Run Keyword If Timeout Occurred')1768        if self._context.timeout_occurred:1769            return self.run_keyword(name, *args)1770    def _get_test_in_teardown(self, kwname):1771        ctx = self._context1772        if ctx.test and ctx.in_test_teardown:1773            return ctx.test1774        raise RuntimeError("Keyword '%s' can only be used in test teardown."1775                           % kwname)1776    @run_keyword_variant(resolve=1)1777    def run_keyword_if_all_critical_tests_passed(self, name, *args):1778        """Runs the given keyword with the given arguments, if all critical tests passed.1779        This keyword can only be used in suite teardown. Trying to use it in1780        any other place will result in an error.1781        Otherwise, this keyword works exactly like `Run Keyword`, see its1782        documentation for more details.1783        """1784        suite = self._get_suite_in_teardown('Run Keyword If '1785                                            'All Critical Tests Passed')1786        if suite.statistics.critical.failed == 0:1787            return self.run_keyword(name, *args)1788    @run_keyword_variant(resolve=1)1789    def run_keyword_if_any_critical_tests_failed(self, name, *args):1790        """Runs the given keyword with the given arguments, if any critical tests failed.1791        This keyword can only be used in a suite teardown. Trying to use it1792        anywhere else results in an error.1793        Otherwise, this keyword works exactly like `Run Keyword`, see its1794        documentation for more details.1795        """1796        suite = self._get_suite_in_teardown('Run Keyword If '1797                                            'Any Critical Tests Failed')1798        if suite.statistics.critical.failed > 0:1799            return self.run_keyword(name, *args)1800    @run_keyword_variant(resolve=1)1801    def run_keyword_if_all_tests_passed(self, name, *args):1802        """Runs the given keyword with the given arguments, if all tests passed.1803        This keyword can only be used in a suite teardown. Trying to use it1804        anywhere else results in an error.1805        Otherwise, this keyword works exactly like `Run Keyword`, see its1806        documentation for more details.1807        """1808        suite = self._get_suite_in_teardown('Run Keyword If All Tests Passed')1809        if suite.statistics.all.failed == 0:1810            return self.run_keyword(name, *args)1811    @run_keyword_variant(resolve=1)1812    def run_keyword_if_any_tests_failed(self, name, *args):1813        """Runs the given keyword with the given arguments, if one or more tests failed.1814        This keyword can only be used in a suite teardown. Trying to use it1815        anywhere else results in an error.1816        Otherwise, this keyword works exactly like `Run Keyword`, see its1817        documentation for more details.1818        """1819        suite = self._get_suite_in_teardown('Run Keyword If Any Tests Failed')1820        if suite.statistics.all.failed > 0:1821            return self.run_keyword(name, *args)1822    def _get_suite_in_teardown(self, kwname):1823        if not self._context.in_suite_teardown:1824            raise RuntimeError("Keyword '%s' can only be used in suite teardown."1825                               % kwname)1826        return self._context.suite1827class _Control(_BuiltInBase):1828    def continue_for_loop(self):1829        """Skips the current for loop iteration and continues from the next.1830        Skips the remaining keywords in the current for loop iteration and1831        continues from the next one. Can be used directly in a for loop or1832        in a keyword that the loop uses.1833        Example:1834        | :FOR | ${var}         | IN                     | @{VALUES}         |1835        |      | Run Keyword If | '${var}' == 'CONTINUE' | Continue For Loop |1836        |      | Do Something   | ${var}                 |1837        See `Continue For Loop If` to conditionally continue a for loop without1838        using `Run Keyword If` or other wrapper keywords.1839        New in Robot Framework 2.8.1840        """1841        self.log("Continuing for loop from the next iteration.")1842        raise ContinueForLoop()1843    def continue_for_loop_if(self, condition):1844        """Skips the current for loop iteration if the ``condition`` is true.1845        A wrapper for `Continue For Loop` to continue a for loop based on1846        the given condition. The condition is evaluated using the same1847        semantics as with `Should Be True` keyword.1848        Example:1849        | :FOR | ${var}               | IN                     | @{VALUES} |1850        |      | Continue For Loop If | '${var}' == 'CONTINUE' |1851        |      | Do Something         | ${var}                 |1852        New in Robot Framework 2.8.1853        """1854        if self._is_true(condition):1855            self.continue_for_loop()1856    def exit_for_loop(self):1857        """Stops executing the enclosing for loop.1858        Exits the enclosing for loop and continues execution after it.1859        Can be used directly in a for loop or in a keyword that the loop uses.1860        Example:1861        | :FOR | ${var}         | IN                 | @{VALUES}     |1862        |      | Run Keyword If | '${var}' == 'EXIT' | Exit For Loop |1863        |      | Do Something   | ${var} |1864        See `Exit For Loop If` to conditionally exit a for loop without1865        using `Run Keyword If` or other wrapper keywords.1866        """1867        self.log("Exiting for loop altogether.")1868        raise ExitForLoop()1869    def exit_for_loop_if(self, condition):1870        """Stops executing the enclosing for loop if the ``condition`` is true.1871        A wrapper for `Exit For Loop` to exit a for loop based on1872        the given condition. The condition is evaluated using the same1873        semantics as with `Should Be True` keyword.1874        Example:1875        | :FOR | ${var}           | IN                 | @{VALUES} |1876        |      | Exit For Loop If | '${var}' == 'EXIT' |1877        |      | Do Something     | ${var}             |1878        New in Robot Framework 2.8.1879        """1880        if self._is_true(condition):1881            self.exit_for_loop()1882    @run_keyword_variant(resolve=0)1883    def return_from_keyword(self, *return_values):1884        """Returns from the enclosing user keyword.1885        This keyword can be used to return from a user keyword with PASS status1886        without executing it fully. It is also possible to return values1887        similarly as with the ``[Return]`` setting. For more detailed information1888        about working with the return values, see the User Guide.1889        This keyword is typically wrapped to some other keyword, such as1890        `Run Keyword If` or `Run Keyword If Test Passed`, to return based1891        on a condition:1892        | Run Keyword If | ${rc} < 0 | Return From Keyword |1893        | Run Keyword If Test Passed | Return From Keyword |1894        It is possible to use this keyword to return from a keyword also inside1895        a for loop. That, as well as returning values, is demonstrated by the1896        `Find Index` keyword in the following somewhat advanced example.1897        Notice that it is often a good idea to move this kind of complicated1898        logic into a test library.1899        | ***** Variables *****1900        | @{LIST} =    foo    baz1901        |1902        | ***** Test Cases *****1903        | Example1904        |     ${index} =    Find Index    baz    @{LIST}1905        |     Should Be Equal    ${index}    ${1}1906        |     ${index} =    Find Index    non existing    @{LIST}1907        |     Should Be Equal    ${index}    ${-1}1908        |1909        | ***** Keywords *****1910        | Find Index1911        |    [Arguments]    ${element}    @{items}1912        |    ${index} =    Set Variable    ${0}1913        |    :FOR    ${item}    IN    @{items}1914        |    \\    Run Keyword If    '${item}' == '${element}'    Return From Keyword    ${index}1915        |    \\    ${index} =    Set Variable    ${index + 1}1916        |    Return From Keyword    ${-1}    # Also [Return] would work here.1917        The most common use case, returning based on an expression, can be1918        accomplished directly with `Return From Keyword If`. Both of these1919        keywords are new in Robot Framework 2.8.1920        See also `Run Keyword And Return` and `Run Keyword And Return If`.1921        """1922        self.log('Returning from the enclosing user keyword.')1923        raise ReturnFromKeyword(return_values)1924    @run_keyword_variant(resolve=1)1925    def return_from_keyword_if(self, condition, *return_values):1926        """Returns from the enclosing user keyword if ``condition`` is true.1927        A wrapper for `Return From Keyword` to return based on the given1928        condition. The condition is evaluated using the same semantics as1929        with `Should Be True` keyword.1930        Given the same example as in `Return From Keyword`, we can rewrite the1931        `Find Index` keyword as follows:1932        | ***** Keywords *****1933        | Find Index1934        |    [Arguments]    ${element}    @{items}1935        |    ${index} =    Set Variable    ${0}1936        |    :FOR    ${item}    IN    @{items}1937        |    \\    Return From Keyword If    '${item}' == '${element}'    ${index}1938        |    \\    ${index} =    Set Variable    ${index + 1}1939        |    Return From Keyword    ${-1}    # Also [Return] would work here.1940        See also `Run Keyword And Return` and `Run Keyword And Return If`.1941        New in Robot Framework 2.8.1942        """1943        if self._is_true(condition):1944            self.return_from_keyword(*return_values)1945    @run_keyword_variant(resolve=1)1946    def run_keyword_and_return(self, name, *args):1947        """Runs the specified keyword and returns from the enclosing user keyword.1948        The keyword to execute is defined with ``name`` and ``*args`` exactly1949        like with `Run Keyword`. After running the keyword, returns from the1950        enclosing user keyword and passes possible return value from the1951        executed keyword further. Returning from a keyword has exactly same1952        semantics as with `Return From Keyword`.1953        Example:1954        | `Run Keyword And Return`  | `My Keyword` | arg1 | arg2 |1955        | # Above is equivalent to: |1956        | ${result} =               | `My Keyword` | arg1 | arg2 |1957        | `Return From Keyword`     | ${result}    |      |      |1958        Use `Run Keyword And Return If` if you want to run keyword and return1959        based on a condition.1960        New in Robot Framework 2.8.2.1961        """1962        ret = self.run_keyword(name, *args)1963        self.return_from_keyword(escape(ret))1964    @run_keyword_variant(resolve=2)1965    def run_keyword_and_return_if(self, condition, name, *args):1966        """Runs the specified keyword and returns from the enclosing user keyword.1967        A wrapper for `Run Keyword And Return` to run and return based on1968        the given ``condition``. The condition is evaluated using the same1969        semantics as with `Should Be True` keyword.1970        Example:1971        | `Run Keyword And Return If` | ${rc} > 0 | `My Keyword` | arg1 | arg2 |1972        | # Above is equivalent to:   |1973        | `Run Keyword If`            | ${rc} > 0 | `Run Keyword And Return` | `My Keyword ` | arg1 | arg2 |1974        Use `Return From Keyword If` if you want to return a certain value1975        based on a condition.1976        New in Robot Framework 2.8.2.1977        """1978        if self._is_true(condition):1979            self.run_keyword_and_return(name, *args)1980    def pass_execution(self, message, *tags):1981        """Skips rest of the current test, setup, or teardown with PASS status.1982        This keyword can be used anywhere in the test data, but the place where1983        used affects the behavior:1984        - When used in any setup or teardown (suite, test or keyword), passes1985          that setup or teardown. Possible keyword teardowns of the started1986          keywords are executed. Does not affect execution or statuses1987          otherwise.1988        - When used in a test outside setup or teardown, passes that particular1989          test case. Possible test and keyword teardowns are executed.1990        Possible continuable failures before this keyword is used, as well as1991        failures in executed teardowns, will fail the execution.1992        It is mandatory to give a message explaining why execution was passed.1993        By default the message is considered plain text, but starting it with1994        ``*HTML*`` allows using HTML formatting.1995        It is also possible to modify test tags passing tags after the message1996        similarly as with `Fail` keyword. Tags starting with a hyphen1997        (e.g. ``-regression``) are removed and others added. Tags are modified1998        using `Set Tags` and `Remove Tags` internally, and the semantics1999        setting and removing them are the same as with these keywords.2000        Examples:2001        | Pass Execution | All features available in this version tested. |2002        | Pass Execution | Deprecated test. | deprecated | -regression    |2003        This keyword is typically wrapped to some other keyword, such as2004        `Run Keyword If`, to pass based on a condition. The most common case2005        can be handled also with `Pass Execution If`:2006        | Run Keyword If    | ${rc} < 0 | Pass Execution | Negative values are cool. |2007        | Pass Execution If | ${rc} < 0 | Negative values are cool. |2008        Passing execution in the middle of a test, setup or teardown should be2009        used with care. In the worst case it leads to tests that skip all the2010        parts that could actually uncover problems in the tested application.2011        In cases where execution cannot continue do to external factors,2012        it is often safer to fail the test case and make it non-critical.2013        New in Robot Framework 2.8.2014        """2015        message = message.strip()2016        if not message:2017            raise RuntimeError('Message cannot be empty.')2018        self._set_and_remove_tags(tags)2019        log_message, level = self._get_logged_test_message_and_level(message)2020        self.log('Execution passed with message:\n%s' % log_message, level)2021        raise PassExecution(message)2022    @run_keyword_variant(resolve=1)2023    def pass_execution_if(self, condition, message, *tags):2024        """Conditionally skips rest of the current test, setup, or teardown with PASS status.2025        A wrapper for `Pass Execution` to skip rest of the current test,2026        setup or teardown based the given ``condition``. The condition is2027        evaluated similarly as with `Should Be True` keyword, and ``message``2028        and ``*tags`` have same semantics as with `Pass Execution`.2029        Example:2030        | :FOR | ${var}            | IN                     | @{VALUES}               |2031        |      | Pass Execution If | '${var}' == 'EXPECTED' | Correct value was found |2032        |      | Do Something      | ${var}                 |2033        New in Robot Framework 2.8.2034        """2035        if self._is_true(condition):2036            message = self._variables.replace_string(message)2037            tags = self._variables.replace_list(tags)2038            self.pass_execution(message, *tags)2039class _Misc(_BuiltInBase):2040    def no_operation(self):2041        """Does absolutely nothing."""2042    def sleep(self, time_, reason=None):2043        """Pauses the test executed for the given time.2044        ``time`` may be either a number or a time string. Time strings are in2045        a format such as ``1 day 2 hours 3 minutes 4 seconds 5milliseconds`` or2046        ``1d 2h 3m 4s 5ms``, and they are fully explained in an appendix of2047        Robot Framework User Guide. Optional `reason` can be used to explain why2048        sleeping is necessary. Both the time slept and the reason are logged.2049        Examples:2050        | Sleep | 42                   |2051        | Sleep | 1.5                  |2052        | Sleep | 2 minutes 10 seconds |2053        | Sleep | 10s                  | Wait for a reply |2054        """2055        seconds = timestr_to_secs(time_)2056        # Python hangs with negative values2057        if seconds < 0:2058            seconds = 02059        self._sleep_in_parts(seconds)2060        self.log('Slept %s' % secs_to_timestr(seconds))2061        if reason:2062            self.log(reason)2063    def _sleep_in_parts(self, seconds):2064        # time.sleep can't be stopped in windows2065        # to ensure that we can signal stop (with timeout)2066        # split sleeping to small pieces2067        endtime = time.time() + float(seconds)2068        while True:2069            remaining = endtime - time.time()2070            if remaining <= 0:2071                break2072            time.sleep(min(remaining, 0.01))2073    def catenate(self, *items):2074        """Catenates the given items together and returns the resulted string.2075        By default, items are catenated with spaces, but if the first item2076        contains the string ``SEPARATOR=<sep>``, the separator ``<sep>`` is2077        used instead. Items are converted into strings when necessary.2078        Examples:2079        | ${str1} = | Catenate | Hello         | world |       |2080        | ${str2} = | Catenate | SEPARATOR=--- | Hello | world |2081        | ${str3} = | Catenate | SEPARATOR=    | Hello | world |2082        =>2083        | ${str1} = 'Hello world'2084        | ${str2} = 'Hello---world'2085        | ${str3} = 'Helloworld'2086        """2087        if not items:2088            return ''2089        items = [unic(item) for item in items]2090        if items[0].startswith('SEPARATOR='):2091            sep = items[0][len('SEPARATOR='):]2092            items = items[1:]2093        else:2094            sep = ' '2095        return sep.join(items)2096    def log(self, message, level='INFO', html=False, console=False, repr=False):2097        u"""Logs the given message with the given level.2098        Valid levels are TRACE, DEBUG, INFO (default), HTML, WARN, and ERROR.2099        Messages below the current active log level are ignored. See2100        `Set Log Level` keyword and ``--loglevel`` command line option2101        for more details about setting the level.2102        Messages logged with the WARN or ERROR levels will be automatically2103        visible also in the console and in the Test Execution Errors section2104        in the log file.2105        Logging can be configured using optional ``html``, ``console`` and2106        ``repr`` arguments. They are off by default, but can be enabled2107        by giving them a true value. See `Boolean arguments` section for more2108        information about true and false values.2109        If the ``html`` argument is given a true value, the message will be2110        considered HTML and special characters such as ``<`` in it are not2111        escaped. For example, logging ``<img src="image.png">`` creates an2112        image when ``html`` is true, but otherwise the message is that exact2113        string. An alternative to using the ``html`` argument is using the HTML2114        pseudo log level. It logs the message as HTML using the INFO level.2115        If the ``console`` argument is true, the message will be written to2116        the console where test execution was started from in addition to2117        the log file. This keyword always uses the standard output stream2118        and adds a newline after the written message. Use `Log To Console`2119        instead if either of these is undesirable,2120        If the ``repr`` argument is true, the given item will be passed through2121        a custom version of Python's ``pprint.pformat()`` function before2122        logging it. This is useful, for example, when working with strings or2123        bytes containing invisible characters, or when working with nested data2124        structures. The custom version differs from the standard one so that it2125        omits the ``u`` prefix from Unicode strings and adds ``b`` prefix to2126        byte strings.2127        Examples:2128        | Log | Hello, world!        |          |   | # Normal INFO message.   |2129        | Log | Warning, world!      | WARN     |   | # Warning.               |2130        | Log | <b>Hello</b>, world! | html=yes |   | # INFO message as HTML.  |2131        | Log | <b>Hello</b>, world! | HTML     |   | # Same as above.         |2132        | Log | <b>Hello</b>, world! | DEBUG    | html=true | # DEBUG as HTML. |2133        | Log | Hello, console!   | console=yes | | # Log also to the console. |2134        | Log | Hyv\xe4 \\x00     | repr=yes    | | # Log ``'Hyv\\xe4 \\x00'``. |2135        See `Log Many` if you want to log multiple messages in one go, and2136        `Log To Console` if you only want to write to the console.2137        Arguments ``html``, ``console``, and ``repr`` are new in Robot Framework2138        2.8.2.2139        Pprint support when ``repr`` is used is new in Robot Framework 2.8.6,2140        and it was changed to drop the ``u`` prefix and add the ``b`` prefix2141        in Robot Framework 2.9.2142        """2143        if is_truthy(repr):2144            message = prepr(message, width=80)2145        logger.write(message, level, is_truthy(html))2146        if is_truthy(console):2147            logger.console(message)2148    @run_keyword_variant(resolve=0)2149    def log_many(self, *messages):2150        """Logs the given messages as separate entries using the INFO level.2151        Supports also logging list and dictionary variable items individually.2152        Examples:2153        | Log Many | Hello   | ${var}  |2154        | Log Many | @{list} | &{dict} |2155        See `Log` and `Log To Console` keywords if you want to use alternative2156        log levels, use HTML, or log to the console.2157        """2158        for msg in self._yield_logged_messages(messages):2159            self.log(msg)2160    def _yield_logged_messages(self, messages):2161        for msg in messages:2162            var = VariableSplitter(msg)2163            value = self._variables.replace_scalar(msg)2164            if var.is_list_variable():2165                for item in value:2166                    yield item2167            elif var.is_dict_variable():2168                for name, value in value.items():2169                    yield '%s=%s' % (name, value)2170            else:2171                yield value2172    def log_to_console(self, message, stream='STDOUT', no_newline=False):2173        """Logs the given message to the console.2174        By default uses the standard output stream. Using the standard error2175        stream is possibly by giving the ``stream`` argument value ``STDERR``2176        (case-insensitive).2177        By default appends a newline to the logged message. This can be2178        disabled by giving the ``no_newline`` argument a true value (see2179        `Boolean arguments`).2180        Examples:2181        | Log To Console | Hello, console!             |                 |2182        | Log To Console | Hello, stderr!              | STDERR          |2183        | Log To Console | Message starts here and is  | no_newline=true |2184        | Log To Console | continued without newline.  |                 |2185        This keyword does not log the message to the normal log file. Use2186        `Log` keyword, possibly with argument ``console``, if that is desired.2187        New in Robot Framework 2.8.2.2188        """2189        logger.console(message, newline=is_falsy(no_newline), stream=stream)2190    @run_keyword_variant(resolve=0)2191    def comment(self, *messages):2192        """Displays the given messages in the log file as keyword arguments.2193        This keyword does nothing with the arguments it receives, but as they2194        are visible in the log, this keyword can be used to display simple2195        messages. Given arguments are ignored so thoroughly that they can even2196        contain non-existing variables. If you are interested about variable2197        values, you can use the `Log` or `Log Many` keywords.2198        """2199        pass2200    def set_log_level(self, level):2201        """Sets the log threshold to the specified level and returns the old level.2202        Messages below the level will not logged. The default logging level is2203        INFO, but it can be overridden with the command line option2204        ``--loglevel``.2205        The available levels: TRACE, DEBUG, INFO (default), WARN, ERROR and NONE (no2206        logging).2207        """2208        try:2209            old = self._context.output.set_log_level(level)2210        except DataError as err:2211            raise RuntimeError(unic(err))2212        self._namespace.variables.set_global('${LOG_LEVEL}', level.upper())2213        self.log('Log level changed from %s to %s.' % (old, level.upper()))2214        return old2215    def reload_library(self, name_or_instance):2216        """Rechecks what keywords the specified library provides.2217        Can be called explicitly in the test data or by a library itself2218        when keywords it provides have changed.2219        The library can be specified by its name or as the active instance of2220        the library. The latter is especially useful if the library itself2221        calls this keyword as a method.2222        New in Robot Framework 2.9.2223        """2224        library = self._namespace.reload_library(name_or_instance)2225        self.log('Reloaded library %s with %s keywords.' % (library.name,2226                                                            len(library)))2227    @run_keyword_variant(resolve=0)2228    def import_library(self, name, *args):2229        """Imports a library with the given name and optional arguments.2230        This functionality allows dynamic importing of libraries while tests2231        are running. That may be necessary, if the library itself is dynamic2232        and not yet available when test data is processed. In a normal case,2233        libraries should be imported using the Library setting in the Setting2234        table.2235        This keyword supports importing libraries both using library2236        names and physical paths. When paths are used, they must be2237        given in absolute format or found from2238        [http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pythonpath-jythonpath-and-ironpythonpath|2239        search path]. Forward slashes can be used as path separators in all2240        operating systems.2241        It is possible to pass arguments to the imported library and also2242        named argument syntax works if the library supports it. ``WITH NAME``2243        syntax can be used to give a custom name to the imported library.2244        Examples:2245        | Import Library | MyLibrary |2246        | Import Library | ${CURDIR}/../Library.py | arg1 | named=arg2 |2247        | Import Library | ${LIBRARIES}/Lib.java | arg | WITH NAME | JavaLib |2248        """2249        try:2250            self._namespace.import_library(name, list(args))2251        except DataError as err:2252            raise RuntimeError(unic(err))2253    @run_keyword_variant(resolve=0)2254    def import_variables(self, path, *args):2255        """Imports a variable file with the given path and optional arguments.2256        Variables imported with this keyword are set into the test suite scope2257        similarly when importing them in the Setting table using the Variables2258        setting. These variables override possible existing variables with2259        the same names. This functionality can thus be used to import new2260        variables, for example, for each test in a test suite.2261        The given path must be absolute or found from2262        [http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pythonpath-jythonpath-and-ironpythonpath|2263        search path]. Forward slashes can be used as path separator regardless2264        the operating system.2265        Examples:2266        | Import Variables | ${CURDIR}/variables.py   |      |      |2267        | Import Variables | ${CURDIR}/../vars/env.py | arg1 | arg2 |2268        | Import Variables | file_from_pythonpath.py  |      |      |2269        """2270        try:2271            self._namespace.import_variables(path, list(args), overwrite=True)2272        except DataError as err:2273            raise RuntimeError(unic(err))2274    @run_keyword_variant(resolve=0)2275    def import_resource(self, path):2276        """Imports a resource file with the given path.2277        Resources imported with this keyword are set into the test suite scope2278        similarly when importing them in the Setting table using the Resource2279        setting.2280        The given path must be absolute or found from2281        [http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pythonpath-jythonpath-and-ironpythonpath|2282        search path]. Forward slashes can be used as path separator regardless2283        the operating system.2284        Examples:2285        | Import Resource | ${CURDIR}/resource.txt |2286        | Import Resource | ${CURDIR}/../resources/resource.html |2287        | Import Resource | found_from_pythonpath.robot |2288        """...keywords.py
Source:keywords.py  
...27        if show_intro:28            print_output('\n>>>>>', 'Exit shell.')29        # put stdout back where it was30        sys.stdout = old_stdout31    @run_keyword_variant(resolve=1)32    def debug_if(self, condition, *args):33        """Runs the Debug keyword if condition is true."""34        return run_debug_if(condition, *args)35    def get_remote_url(self):36        """Get selenium URL for connecting to remote WebDriver."""37        return get_remote_url()38    def get_session_id(self):39        """Get selenium browser session id."""40        return get_session_id()41    def get_webdriver_remote(self):42        """Print the way connecting to remote selenium server."""...MyLib2.py
Source:MyLib2.py  
...3from robot.running import Keyword, RUN_KW_REGISTER4from enum import Enum567def run_keyword_variant(resolve):8    def decorator(method):9        RUN_KW_REGISTER.register_run_keyword('MyLib2', method.__name__, resolve, deprecation_warning=False)10        return method11    return decorator121314class MyLib2:15    '''*Das ist meine Doku*1617    Hier weitere Doku18    '''1920    ROBOT_LIBRARY_SCOPE = 'GLOBAL'2122    def __init__(self, ip='127.0.0.1'):23        """Das ding hat ne Option IP"""24        self.ip = ip2526    def my_keyword(self):27        """Das ist ein keyword"""28        logger.debug('Hello World')2930    def hello_someone(self, name: str):31        print(f'Hello {name}')3233    @run_keyword_variant(resolve=0)34    def set_my_var(self, var, val):35        BuiltIn().set_test_variable(var, val)
...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
