Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ValueError with 1.6 on some pages only. #706

Open
mrmachine opened this issue Dec 16, 2015 · 13 comments
Open

ValueError with 1.6 on some pages only. #706

mrmachine opened this issue Dec 16, 2015 · 13 comments
Labels

Comments

@mrmachine
Copy link
Contributor

Here's the template code and traceback:

Template error:
In template /path/to/myproject/templates/myproject/base.html, error at line 84
   dictionary update sequence element #0 has length 22; 2 is required
   74 :     {% endif %}
   75 : 
   76 :     {% block icons %}
   77 :         <link rel="shortcut icon" href="{% static "myproject/images/icons/favicon.ico" %}">
   78 :         <link rel="apple-touch-icon" href="{% static "myproject/images/icons/apple-touch-icon.png" %}">
   79 :         <link rel="apple-touch-icon-precomposed" href="{% static "myproject/images/icons/apple-touch-icon-precomposed.png" %}">
   80 :     {% endblock icons %}
   81 : {% endblock %}
   82 : 
   83 : {% block base_css %}
   84 :      {% compress css file %} 
   85 :         <link rel="stylesheet" href="{% static "bootstrap/dist/css/bootstrap.css" %}">
   86 :         <link rel="stylesheet" href="{% static "font-awesome/css/font-awesome.css" %}">
   87 :         <link rel="stylesheet" href="{% static "slick-carousel/slick/slick.css" %}">
   88 :         <link type="text/less" rel="stylesheet" href="{% static "myproject/less/main.less" %}">
   89 :     {% endcompress %}
   90 : {% endblock %}
   91 : 
   92 : {% block head_js %}
   93 :     {% compress js file %}
   94 :         <script src="{% static "modernizr/modernizr.js" %}"></script>

Traceback:
File "/path/to/venv/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  111.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/path/to/venv/lib/python2.7/site-packages/django/db/transaction.py" in inner
  394.                 return func(*args, **kwargs)
File "/path/to/venv/src/django-multiurl/multiurl.py" in multiview
  72.                     response = match.func(request, *match.args, **match.kwargs)
File "/path/to/venv/src/django-multiurl/multiurl.py" in multiview
  72.                     response = match.func(request, *match.args, **match.kwargs)
File "/path/to/venv/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
  21.                 return view_func(request, *args, **kwargs)
File "/path/to/myproject/research_projects/views.py" in document
  38.         return render_to_response(material.layout.template_name, c)
File "/path/to/venv/lib/python2.7/site-packages/django/shortcuts.py" in render_to_response
  25.     return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
File "/path/to/venv/lib/python2.7/site-packages/django/template/loader.py" in render_to_string
  172.         return t.render(Context(dictionary))
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in render
  148.             return self._render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in _render
  142.         return self.nodelist.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in render
  844.                 bit = self.render_node(node, context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/debug.py" in render_node
  80.             return node.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/loader_tags.py" in render
  126.         return compiled_parent._render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in _render
  142.         return self.nodelist.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in render
  844.                 bit = self.render_node(node, context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/debug.py" in render_node
  80.             return node.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/loader_tags.py" in render
  126.         return compiled_parent._render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in _render
  142.         return self.nodelist.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in render
  844.                 bit = self.render_node(node, context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/debug.py" in render_node
  80.             return node.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/loader_tags.py" in render
  126.         return compiled_parent._render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in _render
  142.         return self.nodelist.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in render
  844.                 bit = self.render_node(node, context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/debug.py" in render_node
  80.             return node.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/loader_tags.py" in render
  126.         return compiled_parent._render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in _render
  142.         return self.nodelist.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in render
  844.                 bit = self.render_node(node, context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/debug.py" in render_node
  80.             return node.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/loader_tags.py" in render
  65.                 result = block.nodelist.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in render
  844.                 bit = self.render_node(node, context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/debug.py" in render_node
  80.             return node.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/loader_tags.py" in render
  65.                 result = block.nodelist.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in render
  844.                 bit = self.render_node(node, context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/debug.py" in render_node
  80.             return node.render(context)
File "/path/to/venv/lib/python2.7/site-packages/compressor/templatetags/compress.py" in render
  127.         return self.render_compressed(context, self.kind, self.mode, forced=forced)
File "/path/to/venv/lib/python2.7/site-packages/compressor/templatetags/compress.py" in render_compressed
  94.         compressor = self.get_compressor(context, kind)
File "/path/to/venv/lib/python2.7/site-packages/compressor/templatetags/compress.py" in get_compressor
  39.             content=self.get_original_content(context), context=context)
File "/path/to/venv/lib/python2.7/site-packages/compressor/templatetags/compress.py" in get_original_content
  119.         return self.nodelist.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in render
  844.                 bit = self.render_node(node, context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/debug.py" in render_node
  80.             return node.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/loader_tags.py" in render
  65.                 result = block.nodelist.render(context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/base.py" in render
  844.                 bit = self.render_node(node, context)
File "/path/to/venv/lib/python2.7/site-packages/django/template/debug.py" in render_node
  80.             return node.render(context)
File "/path/to/venv/lib/python2.7/site-packages/compressor/templatetags/compress.py" in render
  127.         return self.render_compressed(context, self.kind, self.mode, forced=forced)
File "/path/to/venv/lib/python2.7/site-packages/compressor/templatetags/compress.py" in render_compressed
  103.         rendered_output = compressor.output(mode, forced=forced)
File "/path/to/venv/lib/python2.7/site-packages/compressor/css.py" in output
  49.                     ret.append(subnode.output(*args, **kwargs))
File "/path/to/venv/lib/python2.7/site-packages/compressor/css.py" in output
  51.         return super(CssCompressor, self).output(*args, **kwargs)
File "/path/to/venv/lib/python2.7/site-packages/compressor/base.py" in output
  318.             return self.handle_output(mode, filtered_output, forced)
File "/path/to/venv/lib/python2.7/site-packages/compressor/base.py" in handle_output
  326.             return output_func(mode, content, forced, basename)
File "/path/to/venv/lib/python2.7/site-packages/compressor/base.py" in output_file
  340.         return self.render_output(mode, {"url": url})
File "/path/to/venv/lib/python2.7/site-packages/compressor/base.py" in render_output
  364.             final_context = self.context.flatten()
File "/path/to/venv/lib/python2.7/site-packages/django/template/context.py" in flatten
  106.             flat.update(d)

Exception Type: ValueError at /foo/
Exception Value: dictionary update sequence element #0 has length 22; 2 is required

The following code appears to be trying to target Django 1.8 by checking for Context.flatten(), even though that method was introduced in Django 1.7, which is what I am using.

if hasattr(self.context, 'flatten'):
# Django 1.8 complains about Context being passed to its
# Template.render function.
final_context = self.context.flatten()
else:
final_context = self.context

Changing it from:

        if hasattr(self.context, 'flatten'):
            # Django 1.8 complains about Context being passed to its
            # Template.render function.
            final_context = self.context.flatten()
        else:
            final_context = self.context

to:

        if django.VERSION < (1, 8):
            final_context = self.context
        else:
            # Django 1.8 complains about Context being passed to its
            # Template.render function.
            final_context = self.context.flatten()

seems to fix it for me.

@diox diox added the bug label Dec 16, 2015
@diox
Copy link
Member

diox commented Dec 16, 2015

Hi,

Thanks for the bug report. Weird that it fails, I suppose our tests don't cover a specific context use case.

I'll try to look into that if I have the time, but since support for Django 1.7 or below has been removed in the develop version (as Django dropped 1.7 support recently), it's unlikely we'll fix it.

@cyberstar
Copy link

Hi @mrmachine , @diox! I've met the same issue. The bug is in Django itself. It is fixed for Django >=1.9, here is the pr and a discussion in django-cms/django-classy-tags#33 PR.

Related Django issue #26041 (https://code.djangoproject.com/ticket/26041) (the latest, but it has links to previous (original) issue.

I hope this will help.

@diox diox removed the investigate label Jan 25, 2016
@AaronGhent
Copy link

im getting a very similar error with django 1.8.10 exact same problem

ValueError at /
dictionary update sequence element #1 has length 1; 2 is required

just using

final_context = self.context

seems to fix it

@dmarcelino
Copy link

dmarcelino commented Oct 20, 2016

I'm using django 1.10 with django-categories and after replacing css for sass I also hit the issue described here, namely:

Exception Type: ValueError
Exception Value: dictionary update sequence element #0 has length 1; 2 is required
Exception Location: /Users/dario/development/python/ptexport/.venv/lib/python3.5/site-packages/django/template/context.py in flatten, line 122

Expanding on @mrmachine's proposal, the following fix works for me (though I'm not sure if it's the most appropriate):

from django import VERSION
...
        if VERSION < (1, 8) or VERSION > (1, 9):
            final_context = self.context
        else:
            # Django 1.8 complains about Context being passed to its
            # Template.render function.
            final_context = self.context.flatten()

@dmarcelino
Copy link

BTW, in my case, the view code that causes the issue is in categories/views.py#L20-L44:

def category_detail(request, path, template_name='categories/category_detail.html', extra_context={}):
    path_items = path.strip('/').split('/')
    if len(path_items) >= 2:
        category = get_object_or_404(
            Category,
            slug__iexact=path_items[-1],
            level=len(path_items) - 1,
            parent__slug__iexact=path_items[-2])
    else:
        category = get_object_or_404(
            Category,
            slug__iexact=path_items[-1],
            level=len(path_items) - 1)

    templates = []
    while path_items:
        templates.append('categories/%s.html' % '_'.join(path_items))
        path_items.pop()
    templates.append(template_name)

    context = RequestContext(request)
    context.update({'category': category})
    if extra_context:
        context.update(extra_context)
    return HttpResponse(select_template(templates).render(context))

@dmarcelino
Copy link

dmarcelino commented Oct 23, 2016

In my project I ended up modifying the above view code due to another issue. Afterwards I tried re-installing django-compressor without any patch and this time it worked fine. The main changes were:

context = RequestContext(request)
...
return HttpResponse(select_template(templates).render(context))

was changed to:

context = {}
...
return HttpResponse(select_template(templates).render(context, request))

Not sure what are the ramifications of this but it inadvertently fixed my issue.

@trawick
Copy link

trawick commented Dec 30, 2016

Django 1.8.17, django-compressor-2.1 rcssmin-1.0.6 rjsmin-1.0.12

For one response I found, I'm getting ValueError: dictionary update sequence element #0 has length 8; 2 is required; just using final_context = self.context seems to fix it.

I also had the issue with django-compressor 1.6.

trawick added a commit to nasft/django-compressor that referenced this issue Jan 3, 2017
@cisarpavel
Copy link

cisarpavel commented Mar 13, 2017

Got same error with django 1.10.5. Fix using

    def render_output(self, mode, context=None):
        """
        Renders the compressor output with the appropriate template for
        the given mode and template context.
        """
        # Just in case someone renders the compressor outside
        # the usual template rendering cycle
        if 'compressed' not in self.context:
            self.context['compressed'] = {}
    
        self.context['compressed'].update(context or {})
        self.context['compressed'].update(self.extra_context)
        if VERSION < (1, 8) or VERSION > (1, 9):
            # Django 1.8 complains about Context being passed to its
            # Template.render function.
            final_context = self.context
        else:
            final_context = self.context.flatten()
    
        post_compress.send(sender=self.__class__, type=self.type,
                           mode=mode, context=final_context)
        template_name = self.get_template_name(mode)
        return render_to_string(template_name, context=final_context)

works for me.

@karyon
Copy link
Contributor

karyon commented Mar 13, 2017

hi, can you open a pull request?

cisarpavel added a commit to COEXCZ/django-compressor that referenced this issue Mar 13, 2017
Fixes error ValueError: dictionary update sequence element #0 has length 1; 2 is required from issue django-compressor#706
cisarpavel added a commit to COEXCZ/django-compressor that referenced this issue Mar 13, 2017
Fixes error ValueError: dictionary update sequence element #0 has length 1; 2 is required from issue django-compressor#706
@cisarpavel
Copy link

Unfortunatelly this solution seems to have problem with django 1.8. #836
Probably not totaly correct way.

@karyon
Copy link
Contributor

karyon commented May 11, 2017

I investigated this, here are my findings:

  • There is a bug in django 1.8 in the flatten method (see https://code.djangoproject.com/ticket/24765). It has been fixed in django 1.9. The solution is simply to not use the flatten method (Do not use flatten on django 1.8 #850) in django 1.8, since passing Contexts to the render method still works there.
  • For django 1.10, i don't know what the problem is that's observed by @dmarcelino and @cisarpavel and likely in https://code.djangoproject.com/ticket/26041. I haven't been able to reproduce it. Simply not calling flatten is likely not the correct solution since we would then pass a context into the render function, a feature that has been explicitly removed in django 1.10. i suspect that works by pure chance for very simple contexts.

so yeah, if anyone could help me reproducing this in django 1.10, that would help.

@nmashton
Copy link

Following up on @trawick's earlier comment, in my Django 1.11 project using django-compressor 2.2, I am still having this problem.

Whereas he found that just using final_context = self.context seemed to fix it, I'm finding that I need to do more work, specifically, flattening the inner contents of self.context.dicts before flattening self.context:

dicts = self.context.dicts
self.context.dicts = [
    d.flatten() for d in dicts
    if hasattr(d, 'flatten')
]
final_context = self.context.flatten()

@karyon
Copy link
Contributor

karyon commented Mar 24, 2018

if you could tell me how to reproduce this or even better, give me a repro case, that would be grand. or, actually, even better, create a failing test for this :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

9 participants