﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
12049	New LazyObject-wrapped User breaks queries in template tags	Christian Hammond	nobody	"I spent a couple days tracking this down since the last fix (ticket #12037) for the new lazy-wrapped User. Basically, if you have a template tag that grabs the User from the context and performs a complex query with two or more {{{Q()}}}'s chained together, it will fail. The failure case on Python 2.4 is fatal, while on 2.5/2.6 it seems to not fail but does log internally caught exception spew.

Basically, when a deepcopy() is performed on the node list, it sees a {{{function()}}} for the wrapped User and just fails.

Imagine you have a template tag that takes in the context and starts to build a query, like so:

{{{
query = Q(user=context['user']) & Q(someflag=True)
}}}

The process of using a Q() on a wrapped User and chaining with another Q() will break. On Python 2.4, we see:

{{{
  File ""/usr/lib/python2.4/site-packages/django/db/models/query_utils.py"", line 162, in __and__
    return self._combine(other, self.AND)
  File ""/usr/lib/python2.4/site-packages/django/db/models/query_utils.py"", line 154, in _combine
    obj = deepcopy(self)
  File ""/usr/lib/python2.4/copy.py"", line 185, in deepcopy
    y = copier(x, memo)
  File ""/usr/lib/python2.4/site-packages/django/utils/tree.py"", line 61, in __deepcopy__
    obj.children = deepcopy(self.children, memodict)
  File ""/usr/lib/python2.4/copy.py"", line 174, in deepcopy
    y = copier(x, memo)
  File ""/usr/lib/python2.4/copy.py"", line 241, in _deepcopy_list
    y.append(deepcopy(a, memo))
  File ""/usr/lib/python2.4/copy.py"", line 174, in deepcopy
    y = copier(x, memo)
  File ""/usr/lib/python2.4/copy.py"", line 248, in _deepcopy_tuple
    y.append(deepcopy(a, memo))
  File ""/usr/lib/python2.4/copy.py"", line 204, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File ""/usr/lib/python2.4/copy.py"", line 351, in _reconstruct
    state = deepcopy(state, memo)
  File ""/usr/lib/python2.4/copy.py"", line 174, in deepcopy
    y = copier(x, memo)
  File ""/usr/lib/python2.4/copy.py"", line 268, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File ""/usr/lib/python2.4/copy.py"", line 204, in deepcopy
    y = _reconstruct(x, rv, 1, memo)
  File ""/usr/lib/python2.4/copy.py"", line 336, in _reconstruct
    y = callable(*args)
  File ""/usr/lib/python2.4/copy_reg.py"", line 92, in __newobj__
    return cls.__new__(cls, *args)
TypeError: function() takes at least 2 arguments (0 given)
}}}

On Python 2.5 and 2.6, the call succeeds (or at least doesn't throw a fatal exception, but I don't know if there are internal side effects here), but does log the following:

{{{
Exception RuntimeError: 'maximum recursion depth exceeded while calling a Python object' in <type 'exceptions.AttributeError'> ignored
}}}

I'm attaching a diff that simply amends the test_user_attrs testcase to simulate this. After the other checks, it pulls out the User and then builds a dummy query."		closed	contrib.auth	dev		fixed		chipx86@…	Unreviewed	1	0	0	0	0	0
