diff --git a/changelogs/fragments/Templar-remove-fail-on-errors.yml b/changelogs/fragments/Templar-remove-fail-on-errors.yml new file mode 100644 index 00000000000..6d7bd3036cc --- /dev/null +++ b/changelogs/fragments/Templar-remove-fail-on-errors.yml @@ -0,0 +1,2 @@ +minor_changes: + - Templar - remove ``_fail_on_lookup_errors`` and ``_fail_on_filter_errors`` instance variables that were never used. (https://github.com/ansible/ansible/pull/73785) diff --git a/lib/ansible/template/__init__.py b/lib/ansible/template/__init__.py index e90712a30d0..f2946456469 100644 --- a/lib/ansible/template/__init__.py +++ b/lib/ansible/template/__init__.py @@ -648,10 +648,6 @@ class Templar: self._cached_result = {} self._basedir = loader.get_basedir() if loader else './' - # flags to determine whether certain failures during templating - # should result in fatal errors being raised - self._fail_on_lookup_errors = True - self._fail_on_filter_errors = True self._fail_on_undefined_errors = C.DEFAULT_UNDEFINED_VAR_BEHAVIOR environment_class = AnsibleNativeEnvironment if USE_JINJA2_NATIVE else AnsibleEnvironment @@ -807,107 +803,99 @@ class Templar: if fail_on_undefined is None: fail_on_undefined = self._fail_on_undefined_errors - try: - if convert_bare: - variable = self._convert_bare_variable(variable) + if convert_bare: + variable = self._convert_bare_variable(variable) - if isinstance(variable, string_types): - result = variable - - if self.is_possibly_template(variable): - # Check to see if the string we are trying to render is just referencing a single - # var. In this case we don't want to accidentally change the type of the variable - # to a string by using the jinja template renderer. We just want to pass it. - only_one = self.SINGLE_VAR.match(variable) - if only_one: - var_name = only_one.group(1) - if var_name in self._available_variables: - resolved_val = self._available_variables[var_name] - if isinstance(resolved_val, NON_TEMPLATED_TYPES): - return resolved_val - elif resolved_val is None: - return C.DEFAULT_NULL_REPRESENTATION - - # Using a cache in order to prevent template calls with already templated variables - sha1_hash = None - if cache: - variable_hash = sha1(text_type(variable).encode('utf-8')) - options_hash = sha1( - ( - text_type(preserve_trailing_newlines) + - text_type(escape_backslashes) + - text_type(fail_on_undefined) + - text_type(overrides) - ).encode('utf-8') - ) - sha1_hash = variable_hash.hexdigest() + options_hash.hexdigest() - if cache and sha1_hash in self._cached_result: - result = self._cached_result[sha1_hash] - else: - result = self.do_template( - variable, - preserve_trailing_newlines=preserve_trailing_newlines, - escape_backslashes=escape_backslashes, - fail_on_undefined=fail_on_undefined, - overrides=overrides, - disable_lookups=disable_lookups, - ) - - if not self.jinja2_native: - unsafe = hasattr(result, '__UNSAFE__') - if convert_data and not self._no_type_regex.match(variable): - # if this looks like a dictionary or list, convert it to such using the safe_eval method - if (result.startswith("{") and not result.startswith(self.environment.variable_start_string)) or \ - result.startswith("[") or result in ("True", "False"): - eval_results = safe_eval(result, include_exceptions=True) - if eval_results[1] is None: - result = eval_results[0] - if unsafe: - result = wrap_var(result) - else: - # FIXME: if the safe_eval raised an error, should we do something with it? - pass - - # we only cache in the case where we have a single variable - # name, to make sure we're not putting things which may otherwise - # be dynamic in the cache (filters, lookups, etc.) - if cache and only_one: - self._cached_result[sha1_hash] = result - - return result - - elif is_sequence(variable): - return [self.template( - v, - preserve_trailing_newlines=preserve_trailing_newlines, - fail_on_undefined=fail_on_undefined, - overrides=overrides, - disable_lookups=disable_lookups, - ) for v in variable] - elif isinstance(variable, Mapping): - d = {} - # we don't use iteritems() here to avoid problems if the underlying dict - # changes sizes due to the templating, which can happen with hostvars - for k in variable.keys(): - if k not in static_vars: - d[k] = self.template( - variable[k], - preserve_trailing_newlines=preserve_trailing_newlines, - fail_on_undefined=fail_on_undefined, - overrides=overrides, - disable_lookups=disable_lookups, - ) - else: - d[k] = variable[k] - return d - else: + if isinstance(variable, string_types): + if not self.is_possibly_template(variable): return variable - except AnsibleFilterError: - if self._fail_on_filter_errors: - raise - else: - return variable + # Check to see if the string we are trying to render is just referencing a single + # var. In this case we don't want to accidentally change the type of the variable + # to a string by using the jinja template renderer. We just want to pass it. + only_one = self.SINGLE_VAR.match(variable) + if only_one: + var_name = only_one.group(1) + if var_name in self._available_variables: + resolved_val = self._available_variables[var_name] + if isinstance(resolved_val, NON_TEMPLATED_TYPES): + return resolved_val + elif resolved_val is None: + return C.DEFAULT_NULL_REPRESENTATION + + # Using a cache in order to prevent template calls with already templated variables + sha1_hash = None + if cache: + variable_hash = sha1(text_type(variable).encode('utf-8')) + options_hash = sha1( + ( + text_type(preserve_trailing_newlines) + + text_type(escape_backslashes) + + text_type(fail_on_undefined) + + text_type(overrides) + ).encode('utf-8') + ) + sha1_hash = variable_hash.hexdigest() + options_hash.hexdigest() + + if sha1_hash in self._cached_result: + return self._cached_result[sha1_hash] + + result = self.do_template( + variable, + preserve_trailing_newlines=preserve_trailing_newlines, + escape_backslashes=escape_backslashes, + fail_on_undefined=fail_on_undefined, + overrides=overrides, + disable_lookups=disable_lookups, + ) + + if not self.jinja2_native: + unsafe = hasattr(result, '__UNSAFE__') + if convert_data and not self._no_type_regex.match(variable): + # if this looks like a dictionary or list, convert it to such using the safe_eval method + if (result.startswith("{") and not result.startswith(self.environment.variable_start_string)) or \ + result.startswith("[") or result in ("True", "False"): + eval_results = safe_eval(result, include_exceptions=True) + if eval_results[1] is None: + result = eval_results[0] + if unsafe: + result = wrap_var(result) + # FIXME: if the safe_eval raised an error, should we do something with it? + + # we only cache in the case where we have a single variable + # name, to make sure we're not putting things which may otherwise + # be dynamic in the cache (filters, lookups, etc.) + if cache and only_one: + self._cached_result[sha1_hash] = result + + return result + + elif is_sequence(variable): + return [self.template( + v, + preserve_trailing_newlines=preserve_trailing_newlines, + fail_on_undefined=fail_on_undefined, + overrides=overrides, + disable_lookups=disable_lookups, + ) for v in variable] + elif isinstance(variable, Mapping): + d = {} + # we don't use iteritems() here to avoid problems if the underlying dict + # changes sizes due to the templating, which can happen with hostvars + for k in variable.keys(): + if k not in static_vars: + d[k] = self.template( + variable[k], + preserve_trailing_newlines=preserve_trailing_newlines, + fail_on_undefined=fail_on_undefined, + overrides=overrides, + disable_lookups=disable_lookups, + ) + else: + d[k] = variable[k] + return d + else: + return variable def is_template(self, data): '''lets us know if data has a template''' @@ -1022,27 +1010,25 @@ class Templar: raise e except AnsibleLookupError as e: # lookup handled error but still decided to bail - if self._fail_on_lookup_errors: - msg = 'Lookup failed but the error is being ignored: %s' % to_native(e) - if errors == 'warn': - display.warning(msg) - elif errors == 'ignore': - display.display(msg, log_only=True) - else: - raise e + msg = 'Lookup failed but the error is being ignored: %s' % to_native(e) + if errors == 'warn': + display.warning(msg) + elif errors == 'ignore': + display.display(msg, log_only=True) + else: + raise e return [] if wantlist else None except Exception as e: # errors not handled by lookup - if self._fail_on_lookup_errors: - msg = u"An unhandled exception occurred while running the lookup plugin '%s'. Error was a %s, original message: %s" % \ - (name, type(e), to_text(e)) - if errors == 'warn': - display.warning(msg) - elif errors == 'ignore': - display.display(msg, log_only=True) - else: - display.vvv('exception during Jinja2 execution: {0}'.format(format_exc())) - raise AnsibleError(to_native(msg), orig_exc=e) + msg = u"An unhandled exception occurred while running the lookup plugin '%s'. Error was a %s, original message: %s" % \ + (name, type(e), to_text(e)) + if errors == 'warn': + display.warning(msg) + elif errors == 'ignore': + display.display(msg, log_only=True) + else: + display.vvv('exception during Jinja2 execution: {0}'.format(format_exc())) + raise AnsibleError(to_native(msg), orig_exc=e) return [] if wantlist else None if ran and allow_unsafe is False: