Improved error message when index in __getitem__() is invalid.

This commit is contained in:
Jon Dufresne 2019-07-19 13:55:32 -07:00 committed by Mariusz Felisiak
parent 8323691de0
commit d89053585e
6 changed files with 28 additions and 4 deletions

View File

@ -151,7 +151,10 @@ class Page(collections.abc.Sequence):
def __getitem__(self, index): def __getitem__(self, index):
if not isinstance(index, (int, slice)): if not isinstance(index, (int, slice)):
raise TypeError raise TypeError(
'Page indices must be integers or slices, not %s.'
% type(index).__name__
)
# The object_list is converted to a list so that if it was a QuerySet # The object_list is converted to a list so that if it was a QuerySet
# it won't be a database hit per __getitem__. # it won't be a database hit per __getitem__.
if not isinstance(self.object_list, list): if not isinstance(self.object_list, list):

View File

@ -283,7 +283,10 @@ class QuerySet:
def __getitem__(self, k): def __getitem__(self, k):
"""Retrieve an item or slice from the set of results.""" """Retrieve an item or slice from the set of results."""
if not isinstance(k, (int, slice)): if not isinstance(k, (int, slice)):
raise TypeError raise TypeError(
'QuerySet indices must be integers or slices, not %s.'
% type(k).__name__
)
assert ((not isinstance(k, slice) and (k >= 0)) or assert ((not isinstance(k, slice) and (k >= 0)) or
(isinstance(k, slice) and (k.start is None or k.start >= 0) and (isinstance(k, slice) and (k.start is None or k.start >= 0) and
(k.stop is None or k.stop >= 0))), \ (k.stop is None or k.stop >= 0))), \

View File

@ -63,7 +63,10 @@ class BoundField:
# Prevent unnecessary reevaluation when accessing BoundField's attrs # Prevent unnecessary reevaluation when accessing BoundField's attrs
# from templates. # from templates.
if not isinstance(idx, (int, slice)): if not isinstance(idx, (int, slice)):
raise TypeError raise TypeError(
'BoundField indices must be integers or slices, not %s.'
% type(idx).__name__
)
return self.subwidgets[idx] return self.subwidgets[idx]
@property @property

View File

@ -746,6 +746,15 @@ Java</label></li>
[str(bf[1]), str(bf[2]), str(bf[3])], [str(bf[1]), str(bf[2]), str(bf[3])],
) )
def test_boundfield_invalid_index(self):
class TestForm(Form):
name = ChoiceField(choices=[])
field = TestForm()['name']
msg = 'BoundField indices must be integers or slices, not str.'
with self.assertRaisesMessage(TypeError, msg):
field['foo']
def test_boundfield_bool(self): def test_boundfield_bool(self):
"""BoundField without any choices (subwidgets) evaluates to True.""" """BoundField without any choices (subwidgets) evaluates to True."""
class TestForm(Form): class TestForm(Form):

View File

@ -366,7 +366,8 @@ class ModelPaginationTests(TestCase):
# Make sure object_list queryset is not evaluated by an invalid __getitem__ call. # Make sure object_list queryset is not evaluated by an invalid __getitem__ call.
# (this happens from the template engine when using eg: {% page_obj.has_previous %}) # (this happens from the template engine when using eg: {% page_obj.has_previous %})
self.assertIsNone(p.object_list._result_cache) self.assertIsNone(p.object_list._result_cache)
with self.assertRaises(TypeError): msg = 'Page indices must be integers or slices, not str.'
with self.assertRaisesMessage(TypeError, msg):
p['has_previous'] p['has_previous']
self.assertIsNone(p.object_list._result_cache) self.assertIsNone(p.object_list._result_cache)
self.assertNotIsInstance(p.object_list, list) self.assertNotIsInstance(p.object_list, list)

View File

@ -2436,6 +2436,11 @@ class QuerySetSupportsPythonIdioms(TestCase):
with self.assertRaisesMessage(AssertionError, "Negative indexing is not supported."): with self.assertRaisesMessage(AssertionError, "Negative indexing is not supported."):
Article.objects.all()[0:-5] Article.objects.all()[0:-5]
def test_invalid_index(self):
msg = 'QuerySet indices must be integers or slices, not str.'
with self.assertRaisesMessage(TypeError, msg):
Article.objects.all()['foo']
def test_can_get_number_of_items_in_queryset_using_standard_len(self): def test_can_get_number_of_items_in_queryset_using_standard_len(self):
self.assertEqual(len(Article.objects.filter(name__exact='Article 1')), 1) self.assertEqual(len(Article.objects.filter(name__exact='Article 1')), 1)