Loading django/db/models/fields/__init__.py +2 −2 Original line number Diff line number Diff line from __future__ import unicode_literals import collections import copy import datetime import decimal Loading @@ -18,6 +17,7 @@ from django.core import exceptions, validators from django.utils.datastructures import DictWrapper from django.utils.dateparse import parse_date, parse_datetime, parse_time from django.utils.functional import curry, total_ordering from django.utils.itercompat import is_iterator from django.utils.text import capfirst from django.utils import timezone from django.utils.translation import ugettext_lazy as _ Loading Loading @@ -488,7 +488,7 @@ class Field(object): return bound_field_class(self, fieldmapping, original) def _get_choices(self): if isinstance(self._choices, collections.Iterator): if is_iterator(self._choices): choices, self._choices = tee(self._choices) return choices else: Loading django/db/models/sql/where.py +2 −2 Original line number Diff line number Diff line Loading @@ -4,7 +4,6 @@ Code to manage the creation and SQL rendering of 'where' constraints. from __future__ import absolute_import import collections import datetime from itertools import repeat Loading @@ -12,6 +11,7 @@ from django.conf import settings from django.db.models.fields import DateTimeField, Field from django.db.models.sql.datastructures import EmptyResultSet, Empty from django.db.models.sql.aggregates import Aggregate from django.utils.itercompat import is_iterator from django.utils.six.moves import xrange from django.utils import timezone from django.utils import tree Loading Loading @@ -58,7 +58,7 @@ class WhereNode(tree.Node): if not isinstance(data, (list, tuple)): return data obj, lookup_type, value = data if isinstance(value, collections.Iterator): if is_iterator(value): # Consume any generators immediately, so that we can determine # emptiness and transform any non-empty values correctly. value = list(value) Loading django/utils/itercompat.py +14 −1 Original line number Diff line number Diff line Loading @@ -4,10 +4,12 @@ Where possible, we try to use the system-native version and only fall back to these implementations if necessary. """ from django.utils.six.moves import builtins import collections import itertools import sys import warnings def is_iterable(x): "A implementation independent way of checking for iterables" try: Loading @@ -17,6 +19,17 @@ def is_iterable(x): else: return True def is_iterator(x): """An implementation independent way of checking for iterators Python 2.6 has a different implementation of collections.Iterator which accepts anything with a `next` method. 2.7+ requires and `__iter__` method as well. """ if sys.version_info >= (2, 7): return isinstance(x, collections.Iterator) return isinstance(x, collections.Iterator) and hasattr(x, '__iter__') def product(*args, **kwds): warnings.warn("django.utils.itercompat.product is deprecated; use the native version instead", DeprecationWarning, stacklevel=2) Loading tests/utils_tests/itercompat.py 0 → 100644 +11 −0 Original line number Diff line number Diff line from django.test import TestCase from .models import Category, Thing class TestIsIterator(TestCase): def test_regression(self): """This failed on Django 1.5/Py2.6 because category has a next method.""" category = Category.objects.create(name='category') Thing.objects.create(category=category) Thing.objects.filter(category=category) tests/utils_tests/models.py +13 −1 Original line number Diff line number Diff line # Test runner needs a models.py file. from django.db import models class Category(models.Model): name = models.CharField(max_length=100) def next(self): return self class Thing(models.Model): name = models.CharField(max_length=100) category = models.ForeignKey(Category) Loading
django/db/models/fields/__init__.py +2 −2 Original line number Diff line number Diff line from __future__ import unicode_literals import collections import copy import datetime import decimal Loading @@ -18,6 +17,7 @@ from django.core import exceptions, validators from django.utils.datastructures import DictWrapper from django.utils.dateparse import parse_date, parse_datetime, parse_time from django.utils.functional import curry, total_ordering from django.utils.itercompat import is_iterator from django.utils.text import capfirst from django.utils import timezone from django.utils.translation import ugettext_lazy as _ Loading Loading @@ -488,7 +488,7 @@ class Field(object): return bound_field_class(self, fieldmapping, original) def _get_choices(self): if isinstance(self._choices, collections.Iterator): if is_iterator(self._choices): choices, self._choices = tee(self._choices) return choices else: Loading
django/db/models/sql/where.py +2 −2 Original line number Diff line number Diff line Loading @@ -4,7 +4,6 @@ Code to manage the creation and SQL rendering of 'where' constraints. from __future__ import absolute_import import collections import datetime from itertools import repeat Loading @@ -12,6 +11,7 @@ from django.conf import settings from django.db.models.fields import DateTimeField, Field from django.db.models.sql.datastructures import EmptyResultSet, Empty from django.db.models.sql.aggregates import Aggregate from django.utils.itercompat import is_iterator from django.utils.six.moves import xrange from django.utils import timezone from django.utils import tree Loading Loading @@ -58,7 +58,7 @@ class WhereNode(tree.Node): if not isinstance(data, (list, tuple)): return data obj, lookup_type, value = data if isinstance(value, collections.Iterator): if is_iterator(value): # Consume any generators immediately, so that we can determine # emptiness and transform any non-empty values correctly. value = list(value) Loading
django/utils/itercompat.py +14 −1 Original line number Diff line number Diff line Loading @@ -4,10 +4,12 @@ Where possible, we try to use the system-native version and only fall back to these implementations if necessary. """ from django.utils.six.moves import builtins import collections import itertools import sys import warnings def is_iterable(x): "A implementation independent way of checking for iterables" try: Loading @@ -17,6 +19,17 @@ def is_iterable(x): else: return True def is_iterator(x): """An implementation independent way of checking for iterators Python 2.6 has a different implementation of collections.Iterator which accepts anything with a `next` method. 2.7+ requires and `__iter__` method as well. """ if sys.version_info >= (2, 7): return isinstance(x, collections.Iterator) return isinstance(x, collections.Iterator) and hasattr(x, '__iter__') def product(*args, **kwds): warnings.warn("django.utils.itercompat.product is deprecated; use the native version instead", DeprecationWarning, stacklevel=2) Loading
tests/utils_tests/itercompat.py 0 → 100644 +11 −0 Original line number Diff line number Diff line from django.test import TestCase from .models import Category, Thing class TestIsIterator(TestCase): def test_regression(self): """This failed on Django 1.5/Py2.6 because category has a next method.""" category = Category.objects.create(name='category') Thing.objects.create(category=category) Thing.objects.filter(category=category)
tests/utils_tests/models.py +13 −1 Original line number Diff line number Diff line # Test runner needs a models.py file. from django.db import models class Category(models.Model): name = models.CharField(max_length=100) def next(self): return self class Thing(models.Model): name = models.CharField(max_length=100) category = models.ForeignKey(Category)