template_parser - Django-Components" > template_parser - Django-Components" >
Skip to content

template_parser ¤

Overrides for the Django Template system to allow finer control over template parsing.

Based on Django Slippers v0.6.2 - https://github.com/mixxorz/slippers/blob/main/slippers/template.py

parse_bits ¤

parse_bits(
    parser: Parser, bits: List[str], params: List[str], name: str
) -> Tuple[List[FilterExpression], List[Tuple[str, FilterExpression]]]

Parse bits for template tag helpers simple_tag and inclusion_tag, in particular by detecting syntax errors and by extracting positional and keyword arguments.

This is a simplified version of django.template.library.parse_bits where we use custom regex to handle special characters in keyword names.

Furthermore, our version allows duplicate keys, and instead of return kwargs as a dict, we return it as a list of key-value pairs. So it is up to the user of this function to decide whether they support duplicate keys or not.

Source code in src/django_components/template_parser.py
def parse_bits(
    parser: Parser,
    bits: List[str],
    params: List[str],
    name: str,
) -> Tuple[List[FilterExpression], List[Tuple[str, FilterExpression]]]:
    """
    Parse bits for template tag helpers simple_tag and inclusion_tag, in
    particular by detecting syntax errors and by extracting positional and
    keyword arguments.

    This is a simplified version of `django.template.library.parse_bits`
    where we use custom regex to handle special characters in keyword names.

    Furthermore, our version allows duplicate keys, and instead of return kwargs
    as a dict, we return it as a list of key-value pairs. So it is up to the
    user of this function to decide whether they support duplicate keys or not.
    """
    args: List[FilterExpression] = []
    kwargs: List[Tuple[str, FilterExpression]] = []
    unhandled_params = list(params)
    for bit in bits:
        # First we try to extract a potential kwarg from the bit
        kwarg = token_kwargs([bit], parser)
        if kwarg:
            # The kwarg was successfully extracted
            param, value = kwarg.popitem()
            # All good, record the keyword argument
            kwargs.append((str(param), value))
            if param in unhandled_params:
                # If using the keyword syntax for a positional arg, then
                # consume it.
                unhandled_params.remove(param)
        else:
            if kwargs:
                raise TemplateSyntaxError(
                    "'%s' received some positional argument(s) after some " "keyword argument(s)" % name
                )
            else:
                # Record the positional argument
                args.append(parser.compile_filter(bit))
                try:
                    # Consume from the list of expected positional arguments
                    unhandled_params.pop(0)
                except IndexError:
                    pass
    if unhandled_params:
        # Some positional arguments were not supplied
        raise TemplateSyntaxError(
            "'%s' did not receive value(s) for the argument(s): %s"
            % (name, ", ".join("'%s'" % p for p in unhandled_params))
        )
    return args, kwargs

token_kwargs ¤

token_kwargs(bits: List[str], parser: Parser) -> Dict[str, FilterExpression]

Parse token keyword arguments and return a dictionary of the arguments retrieved from the bits token list.

bits is a list containing the remainder of the token (split by spaces) that is to be checked for arguments. Valid arguments are removed from this list.

There is no requirement for all remaining token bits to be keyword arguments, so return the dictionary as soon as an invalid argument format is reached.

Source code in src/django_components/template_parser.py
def token_kwargs(bits: List[str], parser: Parser) -> Dict[str, FilterExpression]:
    """
    Parse token keyword arguments and return a dictionary of the arguments
    retrieved from the ``bits`` token list.

    `bits` is a list containing the remainder of the token (split by spaces)
    that is to be checked for arguments. Valid arguments are removed from this
    list.

    There is no requirement for all remaining token ``bits`` to be keyword
    arguments, so return the dictionary as soon as an invalid argument format
    is reached.
    """
    if not bits:
        return {}
    match = kwarg_re.match(bits[0])
    kwarg_format = match and match[1]
    if not kwarg_format:
        return {}

    kwargs: Dict[str, FilterExpression] = {}
    while bits:
        if kwarg_format:
            match = kwarg_re.match(bits[0])
            if not match or not match[1]:
                return kwargs
            key, value = match.groups()
            del bits[:1]
        else:
            if len(bits) < 3 or bits[1] != "as":
                return kwargs
            key, value = bits[2], bits[0]
            del bits[:3]

        # This is the only difference from the original token_kwargs. We use
        # the ComponentsFilterExpression instead of the original FilterExpression.
        kwargs[key] = ComponentsFilterExpression(value, parser)
        if bits and not kwarg_format:
            if bits[0] != "and":
                return kwargs
            del bits[:1]
    return kwargs