def handle_extendsnode(extendsnode, block_context=None):
    """Create a copy of Node tree of a derived template replacing
    all blocks tags with the nodes of appropriate blocks.
    Also handles {{ block.super }} tags.
    """
    if block_context is None:
        block_context = BlockContext()
    blocks = dict((n.name, n) for n in
                  extendsnode.nodelist.get_nodes_by_type(BlockNode))
    block_context.add_blocks(blocks)

    context = Context(settings.COMPRESS_OFFLINE_CONTEXT)
    compiled_parent = extendsnode.get_parent(context)
    parent_nodelist = compiled_parent.nodelist
    # If the parent template has an ExtendsNode it is not the root.
    for node in parent_nodelist:
        # The ExtendsNode has to be the first non-text node.
        if not isinstance(node, TextNode):
            if isinstance(node, ExtendsNode):
                return handle_extendsnode(node, block_context)
            break
    # Add blocks of the root template to block context.
    blocks = dict((n.name, n) for n in
                  parent_nodelist.get_nodes_by_type(BlockNode))
    block_context.add_blocks(blocks)

    block_stack = []
    new_nodelist = remove_block_nodes(parent_nodelist, block_stack, block_context)
    return new_nodelist
예제 #2
0
def handle_extendsnode(extendsnode, block_context=None, original=None):
    """Create a copy of Node tree of a derived template replacing
    all blocks tags with the nodes of appropriate blocks.
    Also handles {{ block.super }} tags.
    """
    if block_context is None:
        block_context = BlockContext()
    blocks = dict((n.name, n) for n in
                  extendsnode.nodelist.get_nodes_by_type(BlockNode))
    block_context.add_blocks(blocks)

    # Note: we pass an empty context when we find the parent, this breaks
    # inheritance using variables ({% extends template_var %}) but a refactor
    # will be needed to support that use-case with multiple offline contexts.
    context = Context()
    if original is not None:
        context.template = original

    compiled_parent = extendsnode.get_parent(context)
    parent_nodelist = compiled_parent.nodelist
    # If the parent template has an ExtendsNode it is not the root.
    for node in parent_nodelist:
        # The ExtendsNode has to be the first non-text node.
        if not isinstance(node, TextNode):
            if isinstance(node, ExtendsNode):
                return handle_extendsnode(node, block_context, original)
            break
    # Add blocks of the root template to block context.
    blocks = dict((n.name, n) for n in
                  parent_nodelist.get_nodes_by_type(BlockNode))
    block_context.add_blocks(blocks)

    block_stack = []
    new_nodelist = remove_block_nodes(parent_nodelist, block_stack, block_context)
    return new_nodelist
예제 #3
0
def reuse(context, block_list, **kwargs):
    '''
    Allow reuse of a block within a template.

    {% reuse '_myblock' foo=bar %}

    If passed a list of block names, will use the first that matches:

    {% reuse list_of_block_names .... %}
    '''
    try:
        block_context = context.render_context[BLOCK_CONTEXT_KEY]
    except KeyError:
        block_context = BlockContext()

    if not isinstance(block_list, (list, tuple)):
        block_list = [block_list]

    for block in block_list:
        block = block_context.get_block(block)
        if block:
            break
    else:
        return ''

    context.update(kwargs)
    try:
        return block.render(context)
    finally:
        context.pop()
예제 #4
0
def resolve_blocks(template, context, blocks=None):
    '''Get all the blocks from this template, accounting for 'extends' tags'''
    if blocks is None:
        blocks = BlockContext()

    # If it's just the name, resolve into template
    if isinstance(template, str):
        template = get_template(template)

    # Add this templates blocks as the first
    local_blocks = dict(
        (block.name, block)
        for block in template.nodelist.get_nodes_by_type(BlockNode))
    blocks.add_blocks(local_blocks)

    # Do we extend a parent template?
    extends = template.nodelist.get_nodes_by_type(ExtendsNode)
    if extends:
        # Can only have one extends in a template
        extends_node = extends[0]

        # Get the parent, and recurse
        parent_template = extends_node.get_parent(context)
        resolve_blocks(parent_template, context, blocks)

    return blocks
예제 #5
0
def reuse(context, block_list, **kwargs):
    '''
    Allow reuse of a block within a template.

    {% reuse '_myblock' foo=bar %}

    If passed a list of block names, will use the first that matches:

    {% reuse list_of_block_names .... %}
    '''
    try:
        block_context = context.render_context[BLOCK_CONTEXT_KEY]
    except KeyError:
        block_context = BlockContext()

    if not isinstance(block_list, (list, tuple)):
        block_list = [block_list]

    for block in block_list:
        block = block_context.get_block(block)
        if block:
            break
    else:
        return ''

    context.update(kwargs)
    try:
        return block.render(context)
    finally:
        context.pop()
예제 #6
0
def resolve_blocks(template, context, blocks=None):
    '''Get all the blocks from this template, accounting for 'extends' tags'''
    if blocks is None:
        blocks = BlockContext()

    # If it's just the name, resolve into template
    if isinstance(template, str):
        template = get_template(template)

    # Add this templates blocks as the first
    local_blocks = dict(
        (block.name, block)
        for block in template.nodelist.get_nodes_by_type(BlockNode)
    )
    blocks.add_blocks(local_blocks)

    # Do we extend a parent template?
    extends = template.nodelist.get_nodes_by_type(ExtendsNode)
    if extends:
        # Can only have one extends in a template
        extends_node = extends[0]

        # Get the parent, and recurse
        parent_template = extends_node.get_parent(context)
        resolve_blocks(parent_template, context, blocks)

    return blocks
예제 #7
0
 def test_repr(self):
     block_context = BlockContext()
     block_context.add_blocks({"content": BlockNode("content", [])})
     self.assertEqual(
         repr(block_context),
         "<BlockContext: blocks=defaultdict(<class 'list'>, "
         "{'content': [<Block Node: content. Contents: []>]})>",
     )
예제 #8
0
def resolve_blocks(template, context):
    '''Get all the blocks from this template, accounting for 'extends' tags'''
    try:
        blocks = context.render_context[BLOCK_CONTEXT_KEY]
    except KeyError:
        blocks = context.render_context[BLOCK_CONTEXT_KEY] = BlockContext()

    # If it's just the name, resolve into template
    if isinstance(template, six.string_types):
        template = get_template(template)

    # Add this templates blocks as the first
    local_blocks = dict(
        (block.name, block)
        for block in template.nodelist.get_nodes_by_type(BlockNode))
    blocks.add_blocks(local_blocks)

    # Do we extend a parent template?
    extends = template.nodelist.get_nodes_by_type(ExtendsNode)
    if extends:
        # Can only have one extends in a template
        extends_node = extends[0]

        # Get the parent, and recurse
        parent_template = extends_node.get_parent(context)
        resolve_blocks(parent_template, context)

    return blocks
예제 #9
0
def handle_extendsnode(extendsnode, context):
    """Create a copy of Node tree of a derived template replacing
    all blocks tags with the nodes of appropriate blocks.
    Also handles {{ block.super }} tags.
    """
    if BLOCK_CONTEXT_KEY not in context.render_context:
        context.render_context[BLOCK_CONTEXT_KEY] = BlockContext()
    block_context = context.render_context[BLOCK_CONTEXT_KEY]
    blocks = dict(
        (n.name, n) for n in extendsnode.nodelist.get_nodes_by_type(BlockNode))
    block_context.add_blocks(blocks)

    compiled_parent = extendsnode.get_parent(context)
    parent_nodelist = compiled_parent.nodelist
    # If the parent template has an ExtendsNode it is not the root.
    for node in parent_nodelist:
        # The ExtendsNode has to be the first non-text node.
        if not isinstance(node, TextNode):
            if isinstance(node, ExtendsNode):
                return handle_extendsnode(node, context)
            break
    # Add blocks of the root template to block context.
    blocks = dict(
        (n.name, n) for n in parent_nodelist.get_nodes_by_type(BlockNode))
    block_context.add_blocks(blocks)

    block_stack = []
    new_nodelist = remove_block_nodes(parent_nodelist, block_stack,
                                      block_context)
    return new_nodelist
예제 #10
0
def _build_block_context(template, context):
    """Populate the block context with BlockNodes from parent templates."""

    # Ensure there's a BlockContext before rendering. This allows blocks in
    # ExtendsNodes to be found by sub-templates (allowing {{ block.super }} and
    # overriding sub-blocks to work).
    if BLOCK_CONTEXT_KEY not in context.render_context:
        context.render_context[BLOCK_CONTEXT_KEY] = BlockContext()
    block_context = context.render_context[BLOCK_CONTEXT_KEY]

    for node in template.nodelist:
        if isinstance(node, ExtendsNode):
            compiled_parent = node.get_parent(context)

            # Add the parent node's blocks to the context. (This ends up being
            # similar logic to ExtendsNode.render(), where we're adding the
            # parent's blocks to the context so a child can find them.)
            block_context.add_blocks({
                n.name: n
                for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)
            })

            _build_block_context(compiled_parent, context)
            return compiled_parent

        # The ExtendsNode has to be the first non-text node.
        if not isinstance(node, TextNode):
            break
예제 #11
0
    def render(self, context):
        compiled_parent = self.get_parent(context)

        if BLOCK_CONTEXT_KEY not in context.render_context:
            context.render_context[BLOCK_CONTEXT_KEY] = BlockContext()
        block_context = context.render_context[BLOCK_CONTEXT_KEY]

        # Add the block nodes from this node to the block context
        block_context.add_blocks(self.blocks)

        # If this block's parent doesn't have an extends node it is the root,
        # and its block nodes also need to be added to the block context.
        for node in compiled_parent.nodelist:
            # The ExtendsNode has to be the first non-text node.
            if not isinstance(node, TextNode):
                if not isinstance(node, ExtendsNode):
                    nodelist = compiled_parent.nodelist
                    blocks = {
                        n.name: n
                        for n in nodelist.get_nodes_by_type(BlockNode)
                    }
                    block_context.add_blocks(blocks)
                break

        # Call Template._render explicitly so the parser context stays
        # the same.
        return compiled_parent._render(context)
예제 #12
0
def resolve_blocks(template, context):
    '''
    Return a BlockContext instance of all the {% block %} tags in the template.

    If template is a string, it will be resolved through get_template
    '''
    try:
        blocks = context.render_context[BLOCK_CONTEXT_KEY]
    except KeyError:
        blocks = context.render_context[BLOCK_CONTEXT_KEY] = BlockContext()

    # If it's just the name, resolve into template
    if isinstance(template, six.string_types):
        template = get_template(template)

    # For Django 1.8 compatibility
    template = getattr(template, 'template', template)

    # Add this templates blocks as the first
    local_blocks = dict(
        (block.name, block)
        for block in template.nodelist.get_nodes_by_type(BlockNode))
    blocks.add_blocks(local_blocks)

    # Do we extend a parent template?
    extends = template.nodelist.get_nodes_by_type(ExtendsNode)
    if extends:
        # Can only have one extends in a template
        extends_node = extends[0]

        # Get the parent, and recurse
        parent_template = extends_node.get_parent(context)
        resolve_blocks(parent_template, context)

    return blocks
예제 #13
0
def load_widgets(context, **kwargs):
    '''
    Load a series of widget libraries.
    '''
    _soft = kwargs.pop('_soft', False)

    try:
        widgets = context.render_context[WIDGET_CONTEXT_KEY]
    except KeyError:
        widgets = context.render_context[WIDGET_CONTEXT_KEY] = {}

    for alias, template_name in kwargs.items():
        if _soft and alias in widgets:
            continue

        context.render_context.push()
        context.render_context[BLOCK_CONTEXT_KEY] = BlockContext()

        try:
            blocks = resolve_blocks(template_name, context)
            widgets[alias] = blocks
        finally:
            context.render_context.pop()

    return ''
예제 #14
0
def _render_template_block_nodelist(nodelist, block_name, context):
    """Recursively iterate over a node to find the wanted block."""

    # The result, if found via an ExtendsNode.
    rendered_extends_block = None

    # Attempt to find the wanted block in the current template.
    for node in nodelist:
        # ExtendsNode must be first, so this check is gratuitous after the first
        # iteration.
        if isinstance(node, ExtendsNode):
            # Attempt to render this block in the parent, save it in case the
            # only instance of this block is from the super-template. (We don't
            # know this until we traverse the rest of the nodelist,
            # unfortunately.)
            try:
                rendered_extends_block = _render_template_block(
                    node.get_parent(context), block_name, context)
            except BlockNotFound:
                pass

        # If the wanted block was found, return it.
        if isinstance(node, BlockNode) and node.name == block_name:
            # Ensure there's a BlockContext before rendinering. This allows
            # blocks in ExtendsNodes to be found by sub-templates (essentially,
            # allowing {{ block.super }} to work.
            if BLOCK_CONTEXT_KEY not in context.render_context:
                context.render_context[BLOCK_CONTEXT_KEY] = BlockContext()
            context.render_context[BLOCK_CONTEXT_KEY].push(block_name, node)

            return node.render(context)

        # If a node has children, recurse into them. Based on
        # django.template.base.Node.get_nodes_by_type.
        for attr in node.child_nodelists:
            try:
                new_nodelist = getattr(node, attr)
            except AttributeError:
                continue

            # Try to find the block recursively.
            try:
                return _render_template_block_nodelist(new_nodelist,
                                                       block_name, context)
            except BlockNotFound:
                continue

    # No better node was found besides the one from an ExtendsNode. Return it!
    if rendered_extends_block:
        return rendered_extends_block

    # The wanted block_name was not found.
    raise BlockNotFound("block with name '%s' does not exist" % block_name)
예제 #15
0
def handle_extendsnode(extendsnode, block_context=None, original=None):
    """Create a copy of Node tree of a derived template replacing
    all blocks tags with the nodes of appropriate blocks.
    Also handles {{ block.super }} tags.
    """
    if block_context is None:
        block_context = BlockContext()
    blocks = dict(
        (n.name, n) for n in extendsnode.nodelist.get_nodes_by_type(BlockNode))
    block_context.add_blocks(blocks)

    context = Context(settings.COMPRESS_OFFLINE_CONTEXT)
    if original is not None:
        context.template = original

    compiled_parent = extendsnode.get_parent(context)
    parent_nodelist = compiled_parent.nodelist
    # If the parent template has an ExtendsNode it is not the root.
    for node in parent_nodelist:
        # The ExtendsNode has to be the first non-text node.
        if not isinstance(node, TextNode):
            if isinstance(node, ExtendsNode):
                return handle_extendsnode(node, block_context, original)
            break
    # Add blocks of the root template to block context.
    blocks = dict(
        (n.name, n) for n in parent_nodelist.get_nodes_by_type(BlockNode))
    block_context.add_blocks(blocks)

    block_stack = []
    new_nodelist = remove_block_nodes(parent_nodelist, block_stack,
                                      block_context)
    return new_nodelist
예제 #16
0
def reuse(context, block_list, **kwargs):
    '''
    Allow reuse of a block within a template.

    {% reuse '_myblock' foo=bar %}

    If passed a list of block names, will use the first that matches:

    {% reuse list_of_block_names .... %}
    '''
    try:
        block_context = context.render_context[BLOCK_CONTEXT_KEY]
    except KeyError:
        block_context = BlockContext()
        blocks = {
            n.name: n
            for n in context.template.nodelist.get_nodes_by_type(BlockNode)
        }
        block_context.add_blocks(blocks)

    if not isinstance(block_list, (list, tuple)):
        block_list = [block_list]

    for name in block_list:
        block = block_context.get_block(name)
        if block is not None:
            break

    if block is None:
        return ''

    context.update(kwargs)
    try:
        return block.render(context)
    finally:
        context.pop()
예제 #17
0
def render_extends_node(self, context):
    compiled_parent = self.get_parent(context)
    embeds = get_embed_dict(self.embed_list, context)

    if BLOCK_CONTEXT_KEY not in context.render_context:
        context.render_context[BLOCK_CONTEXT_KEY] = BlockContext()
    block_context = context.render_context[BLOCK_CONTEXT_KEY]

    if EMBED_CONTEXT_KEY not in context.render_context:
        context.render_context[EMBED_CONTEXT_KEY] = EmbedContext()
    embed_context = context.render_context[EMBED_CONTEXT_KEY]

    # Add the block nodes from this node to the block context
    # Do the equivalent for embed nodes
    block_context.add_blocks(self.blocks)
    embed_context.add_embeds(embeds)

    # If this block's parent doesn't have an extends node it is the root,
    # and its block nodes also need to be added to the block context.
    for node in compiled_parent.nodelist:
        # The ExtendsNode has to be the first non-text node.
        if not isinstance(node, TextNode):
            if not isinstance(node, ExtendsNode):
                blocks = dict([
                    (n.name, n)
                    for n in compiled_parent.nodelist.get_nodes_by_type(
                        BlockNode)
                ])
                block_context.add_blocks(blocks)
                embeds = get_embed_dict(
                    compiled_parent.nodelist.get_nodes_by_type(
                        ConstantEmbedNode), context)
                embed_context.add_embeds(embeds)
            break

    # Explicitly render all direct embed children of this node.
    if self.embed_list:
        for node in self.nodelist:
            if isinstance(node, ConstantEmbedNode):
                node.render(context)

    # Call Template._render explicitly so the parser context stays
    # the same.
    return compiled_parent._render(context)
예제 #18
0
    def get_block_context(self, form_template, blocks):
        block_context = BlockContext()

        # Add the block nodes from this node to the block context.
        block_context.add_blocks(blocks)

        # Add the template's nodes too if it is the root template.
        for node in form_template.nodelist:
            # The ExtendsNode has to be the first non-text node.
            if not isinstance(node, template.TextNode):
                if not isinstance(node, ExtendsNode):
                    blocks = dict([(n.name, n) for n in
                                   form_template.nodelist\
                                       .get_nodes_by_type(BlockNode)])
                    block_context.add_blocks(blocks)
                break
        return block_context
예제 #19
0
    def render(self, context):
        # Resolve our arguments
        tmpl_name = self.tmpl_name.resolve(context)

        form = self.form
        if form is not None:
            form = form.resolve(context)

        safe_context = copy(context)
        # Since render_context is derived from BaseContext, a simple copy will
        # wind up with the same stack of dicts.
        safe_context.render_context = safe_context.render_context.new({
            BLOCK_CONTEXT_KEY: BlockContext(),
        })

        extra = {
            'formulation': resolve_blocks(tmpl_name, safe_context),
            'formulation-form': form,
        }

        # Render our children
        with extra_context(safe_context, extra):
            return self.nodelist.render(safe_context)
예제 #20
0
def load_widgets(context, **kwargs):
    '''
    Load a series of widget libraries.
    '''
    _soft = kwargs.pop('_soft', False)

    try:
        widgets = context.render_context[WIDGET_CONTEXT_KEY]
    except KeyError:
        widgets = context.render_context[WIDGET_CONTEXT_KEY] = {}

    for alias, template_name in kwargs.items():
        if _soft and alias in widgets:
            continue
        # Build an isolated render context each time
        safe_context = copy(context)
        safe_context.render_context = safe_context.render_context.new({
            BLOCK_CONTEXT_KEY:
            BlockContext(),
        })
        blocks = resolve_blocks(template_name, safe_context)
        widgets[alias] = blocks

    return ''
def handle_extendsnode(extendsnode, block_context=None, original=None):
    """Create a copy of Node tree of a derived template replacing
    all blocks tags with the nodes of appropriate blocks.
    Also handles {{ block.super }} tags.
    """
    if block_context is None:
        block_context = BlockContext()
    blocks = dict(
        (n.name, n) for n in extendsnode.nodelist.get_nodes_by_type(BlockNode))
    block_context.add_blocks(blocks)

    # Note: we pass an empty context when we find the parent, this breaks
    # inheritance using variables ({% extends template_var %}) but a refactor
    # will be needed to support that use-case with multiple offline contexts.
    context = Context()
    if original is not None:
        context.template = original

    compiled_parent = extendsnode.get_parent(context)
    parent_nodelist = compiled_parent.nodelist
    # If the parent template has an ExtendsNode it is not the root.
    for node in parent_nodelist:
        # The ExtendsNode has to be the first non-text node.
        if not isinstance(node, TextNode):
            if isinstance(node, ExtendsNode):
                return handle_extendsnode(node, block_context, original)
            break
    # Add blocks of the root template to block context.
    blocks = dict(
        (n.name, n) for n in parent_nodelist.get_nodes_by_type(BlockNode))
    block_context.add_blocks(blocks)

    block_stack = []
    new_nodelist = remove_block_nodes(parent_nodelist, block_stack,
                                      block_context)
    return new_nodelist