@register.tag(name="macro_block")
def do_macro_block(parser, token):
    tag_name, macro_name, args, kwargs = parse_macro_params(token)
    # could add extra validation on the macro_name tag
    # here, but probably don't need to since we're checking
    # if there's a macro by that name anyway.
    try:
        # see if the macro is in the context.
        macro = parser._macros[macro_name]
    except (AttributeError, KeyError):
        raise template.TemplateSyntaxError(
            "Macro '{0}' is not defined ".format(macro_name) +
            "previously to the {0} tag".format(tag_name))
    # get the arg and kwarg nodes from the nodelist
    nodelist = parser.parse(('endmacro_block',))
    parser.delete_first_token()

    # Loop through nodes, sorting into args/kwargs
    # (we could do this more semantically, but we loop
    # only once like this as an optimization).
    for node in nodelist:
        if isinstance(node, MacroArgNode) and not isinstance(node, MacroKwargNode):
            # note that MacroKwargNode is also a MacroArgNode (via inheritance),
            # so we must check against this.
            args.append(node)
        elif isinstance(node, MacroKwargNode):
            if node.keyword in macro.kwargs:
                # check that the keyword is defined as an argument for
                # the macro.
                if node.keyword not in kwargs:
                    # add the keyword argument to the dict
                    # if it's not in there
                    kwargs[node.keyword] = node
                else:
                    # raise a template syntax error if the
                    # keyword is already in the dict (thus a keyword
                    # argument was passed twice.
                    raise template.TemplateSyntaxError(
                        "{0} template tag was supplied "
                        "the same keyword argument multiple times.".format(
                            tag_name))
            else:
                raise template.TemplateSyntaxError(
                    "{0} template tag was supplied with a "
                    "keyword argument not defined by the {1} macro.".format(
                        tag_name, macro_name))
        # The following is a check that only whitespace is inside the macro_block tag,
        # but it's currently removed for reasons of backwards compatibility/potential 
        # uses people might have to put extra stuff in te macro_block tag.
        # elif not isinstance(node, template.TextNode) or node.s.strip() != "":
        #     # whitespace is allowed, anything else is not
        #     raise template.TemplateSyntaxError(
        #         "{0} template tag received an argument that "
        #         "is neither a arg or a kwarg tag. Make sure there's "
        #         "text or template tags directly descending "
        #         "from the {0} tag.".format(tag_name))

    # check that there aren't more arg tags than args
    # in the macro.
    if len(args) > len(macro.args):
        raise template.TemplateSyntaxError(
            "{0} template tag was supplied too many arg block tags.".format(
                tag_name))

    macro.parser = parser
    return MacroBlockNode(macro, nodelist, args, kwargs)
Function taking parsed template tag
dataset/ETHPy150Open nalourie/django-macros/build/lib/macros/templatetags/macros.py/do_macro_block