def _get_dict_variable_item(self, name, variable, key): key = self.replace_scalar(key) try: return variable[key] except KeyError: raise VariableError("Dictionary '%s' has no key '%s'." % (name, key)) except TypeError as err: raise VariableError("Dictionary '%s' used with invalid key: %s" % (name, err))
def _validate_end_state(self, state): if state == self.variable_state: incomplete = ''.join(self.variable_chars) raise VariableError("Variable '%s' was not closed properly." % incomplete) if state == self.item_state: variable = ''.join(self.variable_chars) items = ''.join('[%s]' % i for i in self.items) incomplete = ''.join(self.item_chars) raise VariableError("Variable item '%s%s[%s' was not closed " "properly." % (variable, items, incomplete))
def _get_dict_variable_item(self, splitter): name = splitter.get_replaced_variable(self) variable = self._variables[name] key = self.replace_scalar(splitter.index) try: return variable[key] except KeyError: raise VariableError("Dictionary variable '%s' has no key '%s'." % (name, key)) except TypeError as err: raise VariableError("Dictionary variable '%s' used with invalid key: %s" % (name, err))
def _validate_value(self, value, identifier, name): if identifier == '@': if not is_list_like(value): raise VariableError("Value of variable '%s' is not list or " "list-like." % name) return list(value) if identifier == '&': if not is_dict_like(value): raise VariableError("Value of variable '%s' is not dictionary " "or dictionary-like." % name) return DotDict(value) return value
def _get_list_variable_item(self, name, variable, index): index = self.replace_string(index) try: index = self._parse_list_variable_index(index, name[0] == '$') except ValueError: raise VariableError("List '%s' used with invalid index '%s'." % (name, index)) try: return variable[index] except IndexError: raise VariableError("List '%s' has no item in index %d." % (name, index))
def _get_list_variable_item(self, splitter): name = splitter.get_replaced_variable(self) variable = self._variables[name] index = self.replace_string(splitter.index) try: index = int(index) except ValueError: raise VariableError("List variable '%s' used with invalid index '%s'." % (name, index)) try: return variable[index] except IndexError: raise VariableError("List variable '%s' has no item in index %d." % (name, index))
def _validate_value(self, value, identifier, name): if identifier == '@': if not is_list_like(value): raise VariableError("Value of variable '%s' is not list or " "list-like." % name) # TODO: Is converting to list needed or would checking be enough? # TODO: Check this and DotDict usage below in RF 3.1. return list(value) if identifier == '&': if not is_dict_like(value): raise VariableError("Value of variable '%s' is not dictionary " "or dictionary-like." % name) # TODO: Is converting to DotDict needed? Check in RF 3.1. return DotDict(value) return value
def find(self, name): match = self._match_extended(name[2:-1]) if match is None: raise ValueError base_name, extended = match.groups() try: variable = self._find_variable('${%s}' % base_name) except DataError as err: raise VariableError("Resolving variable '%s' failed: %s" % (name, err.message)) try: return eval('_BASE_VAR_' + extended, {'_BASE_VAR_': variable}) except: raise VariableError("Resolving variable '%s' failed: %s" % (name, get_error_message()))
def _get_sequence_variable_item(self, name, variable, index): index = self.replace_string(index) try: index = self._parse_sequence_variable_index(index) except ValueError: raise VariableError("%s '%s' used with invalid index '%s'. " "To use '[%s]' as a literal value, it needs " "to be escaped like '\\[%s]'." % (type_name(variable, capitalize=True), name, index, index, index)) try: return variable[index] except IndexError: raise VariableError("%s '%s' has no item in index %d." % (type_name(variable, capitalize=True), name, index))
def _get_variable_item(self, name, variable, item): if is_dict_like(variable): return self._get_dict_variable_item(name, variable, item) if is_list_like(variable): return self._get_list_variable_item(name, variable, item) raise VariableError("Variable '%s' is %s, not list or dictionary, " "and thus accessing item '%s' from it is not " "possible." % (name, type_name(variable), item))
def find(self, name): base = name[2:-1] if not base or base[0] != '{' or base[-1] != '}': raise ValueError try: return evaluate_expression(base[1:-1].strip(), self._variables) except DataError as err: raise VariableError("Resolving variable '%s' failed: %s" % (name, err))
def variable_not_found(name, candidates, message=None, deco_braces=True): """Raise DataError for missing variable name. Return recommendations for similar variable names if any are found. """ candidates = _decorate_candidates(name[0], candidates, deco_braces) normalizer = partial(normalize, ignore='$@&%{}_') message = RecommendationFinder(normalizer).find_and_format( name, candidates, message=message or "Variable '%s' not found." % name) raise VariableError(message)
def _get_nested_extended_var(self, var, base, attr): while '.' in attr: parent, attr = [token.strip() for token in attr.split('.', 1)] try: var = getattr(var, parent) except AttributeError: raise VariableError("Variable '${%s}' does not have attribute '%s'." % (base, parent)) base += '.' + parent return var, base, attr
def _get_return_value(self, variables, return_): ret = self._handler.return_value if not return_ else return_.return_value if not ret: return None contains_list_var = any(is_list_variable(item) for item in ret) try: ret = variables.replace_list(ret) except DataError as err: raise VariableError('Replacing variables from keyword return ' 'value failed: %s' % err.message) if len(ret) != 1 or contains_list_var: return ret return ret[0]
def _get_variable_item(self, match, value): name = match.name for item in match.items: if is_dict_like(value): value = self._get_dict_variable_item(name, value, item) elif hasattr(value, '__getitem__'): value = self._get_sequence_variable_item(name, value, item) else: raise VariableError( "Variable '%s' is %s, which is not subscriptable, and " "thus accessing item '%s' from it is not possible. To use " "'[%s]' as a literal value, it needs to be escaped like " "'\\[%s]'." % (name, type_name(value), item, item, item)) name = '%s[%s]' % (name, item) return value
def variable_not_found(name, candidates, msg=None, deco_braces=True): """Raise DataError for missing variable name. Return recommendations for similar variable names if any are found. """ if msg is None: msg = "Variable '%s' not found." % name candidates = _decorate_candidates(name[0], candidates, deco_braces) normalizer = partial(normalize, ignore='$@%&*{}_', caseless=True, spaceless=True) finder = RecommendationFinder(normalizer) recommendations = finder.find_recommendations(name, candidates) msg = finder.format_recommendations(msg, recommendations) raise VariableError(msg)
def find(self, name): validate_var(name, '$@&%') identifier = name[0] for finder in self._finders: if identifier in finder.identifiers: try: value = finder.find(name) except (KeyError, ValueError): continue try: return self._validate_value(value, identifier, name) except VariableError: raise except: raise VariableError("Resolving variable '%s' failed: %s" % (name, get_error_message())) variable_not_found(name, self._store.data)
def _extended_assign(self, name, value, variables): if name[0] != '$' or '.' not in name or name in variables: return False base, attr = self._split_extended_assign(name) try: var = variables[base] except DataError: return False if not (self._variable_supports_extended_assign(var) and self._is_valid_extended_attribute(attr)): return False try: setattr(var, attr, value) except: raise VariableError("Setting attribute '%s' to variable '%s' " "failed: %s" % (attr, base, get_error_message())) return True
def _get_variable_item(self, name, value, match): if match.identifier in '@&': var = '%s[%s]' % (name, match.items[0]) logger.warn("Accessing variable items using '%s' syntax " "is deprecated. Use '$%s' instead." % (var, var[1:])) for item in match.items: if is_dict_like(value): value = self._get_dict_variable_item(name, value, item) elif is_list_like(value): value = self._get_list_variable_item(name, value, item) else: raise VariableError( "Variable '%s' is %s, not list or dictionary, and thus " "accessing item '%s' from it is not possible." % (name, type_name(value), item)) name = '%s[%s]' % (name, item) return value
def _extended_assign(self, name, value, variables): if name[0] != '$' or '.' not in name or name in variables: return False base, attr = [token.strip() for token in name[2:-1].rsplit('.', 1)] try: var = variables.replace_scalar('${%s}' % base) except VariableError: return False if not (self._variable_supports_extended_assign(var) and self._is_valid_extended_attribute(attr)): return False try: setattr(var, attr, value) except: raise VariableError( "Setting attribute '%s' to variable '${%s}' failed: %s" % (attr, base, get_error_message())) return True
def _get_variable_item(self, match, value): name = match.name if match.identifier in '@&': var = '%s[%s]' % (name, match.items[0]) logger.warn("Accessing variable items using '%s' syntax " "is deprecated. Use '$%s' instead." % (var, var[1:])) for item in match.items: if is_dict_like(value): value = self._get_dict_variable_item(name, value, item) elif hasattr(value, '__getitem__'): value = self._get_sequence_variable_item(name, value, item) else: raise VariableError( "Variable '%s' is %s, which is not subscriptable, and " "thus accessing item '%s' from it is not possible. To use " "'[%s]' as a literal value, it needs to be escaped like " "'\\[%s]'." % (name, type_name(value), item, item, item)) name = '%s[%s]' % (name, item) return value
def _get_variable_value(self, match, ignore_errors): match.resolve_base(self, ignore_errors) # TODO: Do we anymore need to reserve `*{var}` syntax for anything? if match.identifier == '*': logger.warn(r"Syntax '%s' is reserved for future use. Please " r"escape it like '\%s'." % (match, match)) return unic(match) try: value = self._finder.find(match) if match.items: value = self._get_variable_item(match, value) try: value = self._validate_value(match, value) except VariableError: raise except: raise VariableError("Resolving variable '%s' failed: %s" % (match, get_error_message())) except DataError: if not ignore_errors: raise value = unescape(match.match) return value
def _undecorate(self, name): if not is_assign(name): raise VariableError("Invalid variable name '%s'." % name) return name[2:-1]
def _raise(self, error): raise VariableError('Cannot set variables: %s' % error)
def set_test(self, name, value): if self._test is None: raise VariableError('Cannot set test variable when no test is started.') for scope in self._scopes_until_test: name, value = self._set_global_suite_or_test(scope, name, value) self._variables_set.set_test(name, value)
def _raise_cannot_set_type(self, name, value, expected): raise VariableError("Cannot set variable '%s': Expected %s-like value, " "got %s." % (name, expected, type_name(value)))