Hi, > On 12/02/2010 03:43 PM, Dan Fairs wrote: >> My gut feeling is that this boils down to this vastly simplified >> demonstration of how list() works: >> >>>>> class Foo(object): >> ... def __len__(self): >> ... print 'len called' >> ... raise ValueError >> ... def __iter__(self): >> ... return iter([1,2,3]) >> ... >>>>> a = Foo() >>>>> list(a) >> len called >> [1, 2, 3] >> >> Here, you can see that when converting to a list, Python calls __len__, and >> if that raises an exception, discards it and goes on to call __iter__. >> >> So - my hypothesis (unproved, as I could benefit from someone with deeper >> ORM knowledge) is that the call to list() in my original test case calls >> QuerySet.__len__(), which ends up raising a DatabaseError (caused by an >> underlying database lock, the behaviour I'm actually testing for). Python's >> subsequent call to QuerySet.__iter__() succeeds, but ends up returning an >> empty iterator due to some pre-existing state *handwaving here*. >> >> It's the handwaving bit I'm not sure about :). Does that hypothesis sound >> plausible? It seems to be borne out by the snippet below, where I've removed >> the underlying table: > > I ran into this issue, too. My workaround was to place a > > if hasattr(self._iter, '__len__'): > len(self._iter) > > and the same for self.generator in QuerySet.__len__. > > Btw, there's a bug report for this from 2009: > http://bugs.python.org/issue1242657 >
Right - I remember that regression actually. > I was wondering whether the bug still exists in Python 2.x because I take it > only AttributeError and TypeError should be ignored while calling __len__ in > list() -- if that's the case, the bug is definitely still present. True - I'll give it a try in 2.7 when I have a moment to grab and build it. That doesn't help us that much though, as 2.6 (which I'm running on, 2.6.1 to be precise) is a supported version. > > Anyway, I propose to call len() on those iterators, if possible, before > calling list() because otherwise all bugs in backends will be swallowed. That makes sense. I'd considered proposing storing any exception raised in __len__ on an instance variable to be re-raised later; but your solution is better, as you'd get better tracebacks. Should I raise a bug for this behaviour? Working up a test and patch should be straightforward for this one, if we agree it's a bug that needs fixing (even if it's a workaround for the underlying Python issue). Cheers, Dan -- Dan Fairs | [email protected] | www.fezconsulting.com -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
