//  [python]
def do_template(self, data, preserve_trailing_newlines=True, escape_backslashes=True, fail_on_undefined=None, overrides=None, disable_lookups=False):
    # For preserving the number of input newlines in the output (used
    # later in this method)
    data_newlines = _count_newlines_from_end(data)

    if fail_on_undefined is None:
        fail_on_undefined = self._fail_on_undefined_errors

    try:
        # allows template header overrides to change jinja2 options.
        if overrides is None:
            myenv = self.environment.overlay()
        else:
            myenv = self.environment.overlay(overrides)

        # Get jinja env overrides from template
        if data.startswith(JINJA2_OVERRIDE):
            eol = data.find('\n')
            line = data[len(JINJA2_OVERRIDE):eol]
            data = data[eol+1:]
            for pair in line.split(','):
                (key,val) = pair.split(':')
                key = key.strip()
                setattr(myenv, key, ast.literal_eval(val.strip()))

        # Adds Ansible custom filters and tests
        myenv.filters.update(self._get_filters())
        myenv.tests.update(self._get_tests())

        if escape_backslashes:
            # Allow users to specify backslashes in playbooks as "\\" instead of as "\\\\".
            data = _escape_backslashes(data, myenv)

        try:
            t = myenv.from_string(data)
        except TemplateSyntaxError as e:
            raise AnsibleError("template error while templating string: %s. String: %s" % (to_native(e), to_native(data)))
        except Exception as e:
            if 'recursion' in to_native(e):
                raise AnsibleError("recursive loop detected in template string: %s" % to_native(data))
            else:
                return data

        if disable_lookups:
            t.globals['lookup'] = self._fail_lookup
        else:
            t.globals['lookup'] = self._lookup

        t.globals['finalize'] = self._finalize

        jvars = AnsibleJ2Vars(self, t.globals)

        self.cur_context = new_context = t.new_context(jvars, shared=True)
        rf = t.root_render_func(new_context)

        try:
            res = j2_concat(rf)
            if new_context.unsafe:
                res = wrap_var(res)
        except TypeError as te:
            if 'StrictUndefined' in to_native(te):
                errmsg  = "Unable to look up a name or access an attribute in template string (%s).\n" % to_native(data)
                errmsg += "Make sure your variable name does not contain invalid characters like '-': %s" % to_native(te)
                raise AnsibleUndefinedVariable(errmsg)
            else:
                display.debug("failing because of a type error, template data is: %s" % to_native(data))
                raise AnsibleError("Unexpected templating type error occurred on (%s): %s" % (to_native(data),to_native(te)))

        if preserve_trailing_newlines:
            # The low level calls above do not preserve the newline
            # characters at the end of the input data, so we use the
            # calculate the difference in newlines and append them
            # to the resulting output for parity
            #
            # jinja2 added a keep_trailing_newline option in 2.7 when
            # creating an Environment.  That would let us make this code
            # better (remove a single newline if
            # preserve_trailing_newlines is False).  Once we can depend on
            # that version being present, modify our code to set that when
            # initializing self.environment and remove a single trailing
            # newline here if preserve_newlines is False.
            res_newlines = _count_newlines_from_end(res)
            if data_newlines > res_newlines:
                res += self.environment.newline_sequence * (data_newlines - res_newlines)
        return res
    except (UndefinedError, AnsibleUndefinedVariable) as e:
        if fail_on_undefined:
            raise AnsibleUndefinedVariable(e)
        else:
            #TODO: return warning about undefined var
            return data