Fixed #29244 -- Prevented Paginator.count() from silencing TypeError and AttributeError.

This commit is contained in:
Josh Schneier 2018-08-06 23:13:07 -04:00 committed by Tim Graham
parent f1bf069ec1
commit 3767c7ff39
2 changed files with 24 additions and 10 deletions

View File

@ -1,8 +1,10 @@
import collections.abc import collections.abc
import inspect
import warnings import warnings
from math import ceil from math import ceil
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.inspect import method_has_no_args
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -83,13 +85,10 @@ class Paginator:
@cached_property @cached_property
def count(self): def count(self):
"""Return the total number of objects, across all pages.""" """Return the total number of objects, across all pages."""
try: c = getattr(self.object_list, 'count', None)
return self.object_list.count() if callable(c) and not inspect.isbuiltin(c) and method_has_no_args(c):
except (AttributeError, TypeError): return c()
# AttributeError if object_list has no count() method. return len(self.object_list)
# TypeError if object_list.count() requires arguments
# (i.e. is of type list).
return len(self.object_list)
@cached_property @cached_property
def num_pages(self): def num_pages(self):

View File

@ -1,4 +1,3 @@
import unittest
import warnings import warnings
from datetime import datetime from datetime import datetime
@ -6,13 +5,13 @@ from django.core.paginator import (
EmptyPage, InvalidPage, PageNotAnInteger, Paginator, EmptyPage, InvalidPage, PageNotAnInteger, Paginator,
UnorderedObjectListWarning, UnorderedObjectListWarning,
) )
from django.test import TestCase from django.test import SimpleTestCase, TestCase
from .custom import ValidAdjacentNumsPaginator from .custom import ValidAdjacentNumsPaginator
from .models import Article from .models import Article
class PaginationTests(unittest.TestCase): class PaginationTests(SimpleTestCase):
""" """
Tests for the Paginator and Page classes. Tests for the Paginator and Page classes.
""" """
@ -151,6 +150,22 @@ class PaginationTests(unittest.TestCase):
self.assertEqual(5, paginator.num_pages) self.assertEqual(5, paginator.num_pages)
self.assertEqual([1, 2, 3, 4, 5], list(paginator.page_range)) self.assertEqual([1, 2, 3, 4, 5], list(paginator.page_range))
def test_count_does_not_silence_attribute_error(self):
class AttributeErrorContainer:
def count(self):
raise AttributeError('abc')
with self.assertRaisesMessage(AttributeError, 'abc'):
Paginator(AttributeErrorContainer(), 10).count()
def test_count_does_not_silence_type_error(self):
class TypeErrorContainer:
def count(self):
raise TypeError('abc')
with self.assertRaisesMessage(TypeError, 'abc'):
Paginator(TypeErrorContainer(), 10).count()
def check_indexes(self, params, page_num, indexes): def check_indexes(self, params, page_num, indexes):
""" """
Helper method that instantiates a Paginator object from the passed Helper method that instantiates a Paginator object from the passed