Skip to content

Commit

Permalink
Merge pull request #1320 from benfitzpatrick/1176.metadata-check-fail…
Browse files Browse the repository at this point in the history
…-if-ids

#1176: check id usage in fail-if, warn-if
  • Loading branch information
arjclark committed Jul 4, 2014
2 parents f696083 + eb5a271 commit ff3f10b
Show file tree
Hide file tree
Showing 4 changed files with 483 additions and 317 deletions.
36 changes: 30 additions & 6 deletions lib/python/rose/macros/rule.py
Expand Up @@ -176,24 +176,39 @@ class RuleEvaluator(rose.macro.MacroBase):
REC_VALUE = re.compile(r'("[^"]*")')

def evaluate_rule(self, rule, setting_id, config):
"""Evaluate the logic in the provided rule based on config values."""
rule_template_str, rule_id_values = self._process_rule(
rule, setting_id, config)
template = jinja2.Template(rule_template_str)
return_string = template.render(rule_id_values)
return ast.literal_eval(return_string)

def _process_rule(self, rule, setting_id, config):
def evaluate_rule_id_usage(self, rule, setting_id):
"""Return a set of setting ids referenced in the provided rule."""
log_ids = set([])
self._process_rule(rule, setting_id, None,
log_ids=log_ids)
return log_ids

def _process_rule(self, rule, setting_id, config, log_ids=None):
"""Pre-process the provided rule into valid jinja2."""
if log_ids is None:
get_value_from_id = self._get_value_from_id
else:
get_value_from_id = (
lambda id_, conf: self._log_id_usage(id_, conf, log_ids)
)
if not (rule.startswith('{%') or rule.startswith('{-%')):
rule = "{% if " + rule + " %}True{% else %}False{% endif %}"
local_map = {"this": self._get_value_from_id(setting_id, config)}
local_map = {"this": get_value_from_id(setting_id, config)}
value_id_count = -1
sci_num_count = -1
for array_func_key, rec_regex in self.REC_ARRAY.items():
for search_result in rec_regex.findall(rule):
start, var_id, operator, value, end = search_result
if var_id == "this":
var_id = setting_id
setting_value = self._get_value_from_id(var_id, config)
setting_value = get_value_from_id(var_id, config)
array_value = rose.variable.array_split(str(setting_value))
new_string = start + "("
for elem_num in range(1, len(array_value) + 1):
Expand All @@ -207,7 +222,7 @@ def _process_rule(self, rule, setting_id, config):
start, var_id, end = search_result
if var_id == "this":
var_id = setting_id
setting_value = self._get_value_from_id(var_id, config)
setting_value = get_value_from_id(var_id, config)
array_value = rose.variable.array_split(str(setting_value))
new_string = start + str(len(array_value)) + end
rule = self.REC_LEN_FUNC.sub(new_string, rule, count=1)
Expand All @@ -228,7 +243,7 @@ def _process_rule(self, rule, setting_id, config):
rule = rule.replace(search_result, key, 1)
for search_result in self.REC_THIS_ELEMENT_ID.findall(rule):
proper_id = search_result.replace("this", setting_id)
value_string = self._get_value_from_id(proper_id, config)
value_string = get_value_from_id(proper_id, config)
for key, value in local_map.items():
if value == value_string:
break
Expand All @@ -239,7 +254,7 @@ def _process_rule(self, rule, setting_id, config):
rule = rule.replace(search_result, key, 1)
config_id_count = -1
for search_result in self.REC_CONFIG_ID.findall(rule):
value_string = self._get_value_from_id(search_result, config)
value_string = get_value_from_id(search_result, config)
for key, value in local_map.items():
if value == value_string:
break
Expand All @@ -250,7 +265,15 @@ def _process_rule(self, rule, setting_id, config):
rule = rule.replace(search_result, key, 1)
return rule, local_map

def _log_id_usage(self, variable_id, config, id_set):
"""Wrap _get_value_from_id, storing variable_id in id_set."""
id_set.add(variable_id)
if config is None:
return "None"
return self._get_value_from_id(variable_id, config)

def _get_value_from_id(self, variable_id, config):
"""Extract a value for variable_id from config, or fail."""
section, option = self._get_section_option_from_id(variable_id)
value = None
opt_node = config.get([section, option], no_ignore=True)
Expand Down Expand Up @@ -281,6 +304,7 @@ def _get_value_from_id(self, variable_id, config):
return self._evaluate(value)

def _evaluate(self, string):
"""Try to return string as a number, if possible."""
try:
return_value = float(string)
except (TypeError, ValueError):
Expand Down
26 changes: 17 additions & 9 deletions lib/python/rose/metadata_check.py
Expand Up @@ -68,8 +68,17 @@ def _check_duplicate(value):
return INVALID_SYNTAX.format(value)


def _check_fail_if(value):
pass
def _check_rule(value, setting_id, meta_config):
evaluator = rose.macros.rule.RuleEvaluator()
ids_used = evaluator.evaluate_rule_id_usage(value, setting_id)
ids_not_found = []
for id_ in sorted(ids_used):
id_to_find = rose.macro.REC_ID_STRIP.sub("", id_)
node = meta_config.get([id_to_find], no_ignore=True)
if node is None:
ids_not_found.append(id_to_find)
if ids_not_found:
return INVALID_OBJECT.format(", ".join(sorted(ids_not_found)))


def _check_length(value):
Expand Down Expand Up @@ -177,10 +186,6 @@ def _check_values(value):
return INVALID_SYNTAX.format(value)


def _check_warn_if(value):
return _check_fail_if(value)


def _check_widget(value, module_files=None, meta_dir=None):
if module_files is None:
module_files = _get_module_files(meta_dir)
Expand Down Expand Up @@ -265,13 +270,16 @@ def metadata_check(meta_config, meta_dir=None,
value, info))
if option.startswith(rose.META_PROP_WIDGET):
check_func = lambda v: _check_widget(
v, module_files)
v, module_files)
elif option == rose.META_PROP_MACRO:
check_func = lambda v: _check_macro(
v, module_files)
v, module_files)
elif option == rose.META_PROP_VALUE_TITLES:
check_func = lambda v: _check_value_titles(
v, node.get_value([rose.META_PROP_VALUES]))
v, node.get_value([rose.META_PROP_VALUES]))
elif option in [rose.META_PROP_FAIL_IF, rose.META_PROP_WARN_IF]:
check_func = lambda v: _check_rule(
v, section, meta_config)
else:
func_name = "_check_" + option.replace("-", "_")
check_func = globals().get(func_name, lambda v: None)
Expand Down

0 comments on commit ff3f10b

Please sign in to comment.