Opened 11 years ago

Last modified 11 years ago

#19616 closed Bug

QuerySet.__contains__ tries to check the length of a None — at Version 3

Reported by: kalugny@… Owned by: nobody
Component: Database layer (models, ORM) Version: 1.4
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description (last modified by Luke Plant)

This is the code from QuerySet (version 1.42).
As you can see by the lines I've bolded, although _result_cache might be None, it is still being checked for len()

def __contains__(self, val):
        # The 'in' operator works without this method, due to __iter__. This
        # implementation exists only to shortcut the creation of Model
        # instances, by bailing out early if we find a matching element.
        pos = 0
        if self._result_cache is not None:
            if val in self._result_cache:
                return True
            elif self._iter is None:
                # iterator is exhausted, so we have our answer
                return False
            # remember not to check these again:
            pos = len(self._result_cache)
        else:
            # We need to start filling the result cache out. The following
            # ensures that self._iter is not None and self._result_cache is not
            # None
            it = iter(self)

        # Carry on, one result at a time.
        while True:
           if len(self._result_cache) <= pos:
                self._fill_cache(num=1)

Change History (3)

comment:1 by Alex Gaynor, 11 years ago

Can you actually reproduce this in any way? Calling iter(self) should cause _result_cache to start being a list.

in reply to:  1 comment:2 by anonymous, 11 years ago

Replying to Alex:

Can you actually reproduce this in any way? Calling iter(self) should cause _result_cache to start being a list.

Yes, I noticed this because it happened to me.
The reproduction is a bit complex, though.

I used this snippet:
http://djangosnippets.org/snippets/1034/

And it happened when trying to iterate an empty QuerySet.
I naturally thought that this is a bug with me or the snippet, but looking at the code it is pretty obvious that although the function expects that _result_cache might be None it still tries to len() it.

comment:3 by Luke Plant, 11 years ago

Description: modified (diff)

Looking at the code and the comments in the else branch, it actually seems very obvious that the function has covered it's bases about whether self._result_cache is None or not. We need either some further analysis as to why it is wrong, or a simple test case that ought to work.

Note: See TracTickets for help on using tickets.
Back to Top