Repository: django-compressor/django-compressor

Issue:
error with django.template.loaders.cached.Loader
## settings.py

``` py
TEMPLATE_LOADERS = (
    ('django.template.loaders.cached.Loader', (
        'django.template.loaders.filesystem.Loader',
        'django.template.loaders.app_directories.Loader',
    )),
)
```
## Traceback

``` py
Traceback (most recent call last):
  File "/home/ubuntu/my_site/manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 443, in execute_from_command_line
    utility.execute()
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 382, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/django/core/management/base.py", line 196, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/django/core/management/base.py", line 232, in execute
    output = self.handle(*args, **options)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/django/core/management/base.py", line 371, in handle
    return self.handle_noargs(**options)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/management/commands/compress.py", line 274, in handle_noargs
    self.compress(sys.stdout, **options)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/management/commands/compress.py", line 183, in compress
    nodes = list(parser.walk_nodes(template))
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 142, in walk_nodes
    for node in self.walk_nodes(node):
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 138, in walk_nodes
    for node in self.get_nodelist(node):
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 122, in get_nodelist
    return handle_extendsnode(node)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 37, in handle_extendsnode
    return handle_extendsnode(node, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 37, in handle_extendsnode
    return handle_extendsnode(node, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 37, in handle_extendsnode
    return handle_extendsnode(node, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 45, in handle_extendsnode
    new_nodelist = remove_block_nodes(parent_nodelist, block_stack, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 59, in remove_block_nodes
    expanded_block = expand_blocknode(node, block_stack, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 84, in expand_blocknode
    expanded_nodelist = remove_block_nodes(block.nodelist, block_stack, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 59, in remove_block_nodes
    expanded_block = expand_blocknode(node, block_stack, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 84, in expand_blocknode
    expanded_nodelist = remove_block_nodes(block.nodelist, block_stack, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 59, in remove_block_nodes
    expanded_block = expand_blocknode(node, block_stack, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 84, in expand_blocknode
    expanded_nodelist = remove_block_nodes(block.nodelist, block_stack, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 59, in remove_block_nodes
    expanded_block = expand_blocknode(node, block_stack, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 84, in expand_blocknode
    expanded_nodelist = remove_block_nodes(block.nodelist, block_stack, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 66, in remove_block_nodes
    sub_nodelist = remove_block_nodes(sub_nodelist, block_stack, block_context)
  File "/home/ubuntu/.virtualenvs/my_site/local/lib/python2.7/site-packages/compressor/offline/django.py", line 69, in remove_block_nodes
    for attr in node.child_nodelists:
AttributeError: 'NoneType' object has no attribute 'child_nodelists'
```

only happens in django-compressor==1.4 with `django.template.loaders.cached.Loader` setting



Discussion:
Can you add some code to reproduce this bug?

I have the same bug. It looks like compressor/offline/django.py line 56 (`node = block_context.get_block(block_stack[-1].name)`) returns None.

This seems to be due to a template that calls `{{ block.super }}` when not using `{% extends %}`

P.S. I looked into creating a PR but can't get the tests running. Maybe a update to docs/contributing.txt would help?

@boekkooi thanks, that does seem to be the problem.

But I am not sure if this needs to be 'fixed' since Django doesn't like this as well and fails to render if there is a `{{ block.super }}` tag in a template that does not extend another template.

It looks like this also occurs if you use `{{ block.super }}` in a block that doesn't have a parent (but is inside one that does).  In this case Django doesn't raise an error (and `{{ block.super }}` renders as the empty string, _not_ the containing block's `super`), but django-compressor breaks:

```
# base.template
{% block foo %}
    ...
{% endblock %}

# derived.template
{% extends 'base.template' %}
{% block foo %}
    ...
    {% block bar %}
        {{ block.super }}
     {% endblock %}
{% endblock %}
```

Obviously it's a bug in the template, but it might be nice to do something nicer than raising `AttributeError`, if only for convenience (perhaps raise `TemplateError` or something).


Resolving patch:
diff --git a/compressor/offline/django.py b/compressor/offline/django.py
--- a/compressor/offline/django.py
+++ b/compressor/offline/django.py
@@ -54,6 +54,8 @@ def remove_block_nodes(nodelist, block_stack, block_context):
                 if not block_stack:
                     continue
                 node = block_context.get_block(block_stack[-1].name)
+                if not node:
+                    continue
         if isinstance(node, BlockNode):
             expanded_block = expand_blocknode(node, block_stack, block_context)
             new_nodelist.extend(expanded_block)


Test patch:
diff --git a/compressor/tests/test_templates/test_block_super_base_compressed/test_compressor_offline.html b/compressor/tests/test_templates/test_block_super_base_compressed/test_compressor_offline.html
--- a/compressor/tests/test_templates/test_block_super_base_compressed/test_compressor_offline.html
+++ b/compressor/tests/test_templates/test_block_super_base_compressed/test_compressor_offline.html
@@ -5,4 +5,9 @@
     <script type="text/javascript">
         alert("this alert shouldn't be alone!");
     </script>
+    {% block orphan %}
+        {{ block.super }}
+        An 'orphan' block that refers to a non-existent super block.
+        Contents of this block are ignored.
+    {% endblock %}
 {% endspaceless %}{% endblock %}