From 62128fb948b0e868f513e150f5de2197c5c46b68 Mon Sep 17 00:00:00 2001 From: Oliver Urs Lenz Date: Thu, 12 Jul 2018 13:41:05 +0200 Subject: [PATCH] control pagination per template --- docs/settings.rst | 9 +++++---- pelican/generators.py | 29 ++++++++++++++-------------- pelican/paginator.py | 9 ++++----- pelican/settings.py | 13 ++++++++++++- pelican/tests/test_generators.py | 33 +++++++++++++++++++++++--------- pelican/tests/test_paginator.py | 3 +-- pelican/tests/test_settings.py | 9 +++++++++ pelican/writers.py | 20 ++++++++++++++----- 8 files changed, 84 insertions(+), 41 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index a4fc0ba5..e09a90dc 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -755,10 +755,6 @@ Template pages ``DIRECT_TEMPLATES`` are searched for over paths maintained in ``THEME_TEMPLATES_OVERRIDES``. -.. data:: PAGINATED_DIRECT_TEMPLATES = ['index'] - - Provides the direct templates that should be paginated. - Metadata ======== @@ -1000,6 +996,11 @@ You can use the following settings to configure the pagination. The maximum number of articles to include on a page, not including orphans. False to disable pagination. +.. data:: PAGINATED_TEMPLATES = {'index': None, 'tag': None, 'category': None, 'author': None} + + The templates to use pagination with, and the number of articles to include + on a page. If this value is ``None``, it defaults to ``DEFAULT_PAGINATION``. + .. data:: PAGINATION_PATTERNS A set of patterns that are used to determine advanced pagination output. diff --git a/pelican/generators.py b/pelican/generators.py index d176e4ee..c7fc4a9e 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -456,6 +456,7 @@ class ArticlesGenerator(CachingGenerator): # `dates` is already sorted by date for _period, group in groupby(dates, key=key): archive = list(group) + articles = [a for a in self.articles if a in archive] # arbitrarily grab the first date so that the usual # format string syntax can be used for specifying the # period archive dates @@ -478,8 +479,9 @@ class ArticlesGenerator(CachingGenerator): month_name, _period[2]) - write(save_as, template, context, - dates=archive, blog=True, url=url) + write(save_as, template, context, articles=articles, + dates=archive, template_name='period_archives', + blog=True, url=url) for period in 'year', 'month', 'day': save_as = period_save_as[period] @@ -490,11 +492,7 @@ class ArticlesGenerator(CachingGenerator): def generate_direct_templates(self, write): """Generate direct templates pages""" - PAGINATED_TEMPLATES = self.settings['PAGINATED_DIRECT_TEMPLATES'] for template in self.settings['DIRECT_TEMPLATES']: - paginated = {} - if template in PAGINATED_TEMPLATES: - paginated = {'articles': self.articles, 'dates': self.dates} save_as = self.settings.get("%s_SAVE_AS" % template.upper(), '%s.html' % template) url = self.settings.get("%s_URL" % template.upper(), @@ -502,8 +500,9 @@ class ArticlesGenerator(CachingGenerator): if not save_as: continue - write(save_as, self.get_template(template), - self.context, blog=True, paginated=paginated, + write(save_as, self.get_template(template), self.context, + articles=self.articles, dates=self.dates, blog=True, + template_name=template, page_name=os.path.splitext(save_as)[0], url=url) def generate_tags(self, write): @@ -513,18 +512,18 @@ class ArticlesGenerator(CachingGenerator): dates = [article for article in self.dates if article in articles] write(tag.save_as, tag_template, self.context, tag=tag, url=tag.url, articles=articles, dates=dates, - paginated={'articles': articles, 'dates': dates}, blog=True, - page_name=tag.page_name, all_articles=self.articles) + template_name='tag', blog=True, page_name=tag.page_name, + all_articles=self.articles) def generate_categories(self, write): """Generate category pages.""" category_template = self.get_template('category') for cat, articles in self.categories: dates = [article for article in self.dates if article in articles] - write(cat.save_as, category_template, self.context, - url=cat.url, category=cat, articles=articles, dates=dates, - paginated={'articles': articles, 'dates': dates}, blog=True, - page_name=cat.page_name, all_articles=self.articles) + write(cat.save_as, category_template, self.context, url=cat.url, + category=cat, articles=articles, dates=dates, + template_name='category', blog=True, page_name=cat.page_name, + all_articles=self.articles) def generate_authors(self, write): """Generate Author pages.""" @@ -533,7 +532,7 @@ class ArticlesGenerator(CachingGenerator): dates = [article for article in self.dates if article in articles] write(aut.save_as, author_template, self.context, url=aut.url, author=aut, articles=articles, dates=dates, - paginated={'articles': articles, 'dates': dates}, blog=True, + template_name='author', blog=True, page_name=aut.page_name, all_articles=self.articles) def generate_drafts(self, write): diff --git a/pelican/paginator.py b/pelican/paginator.py index 6996cae9..a0ce7c95 100644 --- a/pelican/paginator.py +++ b/pelican/paginator.py @@ -17,15 +17,14 @@ PaginationRule = namedtuple( class Paginator(object): - def __init__(self, name, url, object_list, settings): + def __init__(self, name, url, object_list, settings, per_page=None): self.name = name self.url = url self.object_list = object_list self.settings = settings - - if settings.get('DEFAULT_PAGINATION'): - self.per_page = settings.get('DEFAULT_PAGINATION') - self.orphans = settings.get('DEFAULT_ORPHANS') + if per_page: + self.per_page = per_page + self.orphans = settings['DEFAULT_ORPHANS'] else: self.per_page = len(object_list) self.orphans = 0 diff --git a/pelican/settings.py b/pelican/settings.py index b6f481d2..9845dd18 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -108,7 +108,8 @@ DEFAULT_CONFIG = { 'DEFAULT_LANG': 'en', 'DIRECT_TEMPLATES': ['index', 'tags', 'categories', 'authors', 'archives'], 'THEME_TEMPLATES_OVERRIDES': [], - 'PAGINATED_DIRECT_TEMPLATES': ['index'], + 'PAGINATED_TEMPLATES': {'index': None, 'tag': None, 'category': None, + 'author': None}, 'PELICAN_CLASS': 'pelican.Pelican', 'DEFAULT_DATE_FORMAT': '%a %d %B %Y', 'DATE_FORMATS': {}, @@ -455,4 +456,14 @@ def configure_settings(settings): message += ', see {} for details'.format(doc) logger.warning(message) + if 'PAGINATED_DIRECT_TEMPLATES' in settings: + message = 'The {} setting has been removed in favor of {}'.format( + 'PAGINATED_DIRECT_TEMPLATES', 'PAGINATED_TEMPLATES') + logger.warning(message) + + for t in settings['PAGINATED_DIRECT_TEMPLATES']: + if t not in settings['PAGINATED_TEMPLATES']: + settings['PAGINATED_TEMPLATES'][t] = None + del settings['PAGINATED_DIRECT_TEMPLATES'] + return settings diff --git a/pelican/tests/test_generators.py b/pelican/tests/test_generators.py index 5f673d00..11ae144a 100644 --- a/pelican/tests/test_generators.py +++ b/pelican/tests/test_generators.py @@ -337,8 +337,10 @@ class TestArticlesGenerator(unittest.TestCase): generator.generate_direct_templates(write) write.assert_called_with("archives.html", generator.get_template("archives"), settings, - blog=True, paginated={}, page_name='archives', - url="archives.html") + articles=generator.articles, + dates=generator.dates, blog=True, + template_name='archives', + page_name='archives', url="archives.html") @unittest.skipUnless(MagicMock, 'Needs Mock module') def test_direct_templates_save_as_url_modified(self): @@ -355,7 +357,9 @@ class TestArticlesGenerator(unittest.TestCase): generator.generate_direct_templates(write) write.assert_called_with("archives/index.html", generator.get_template("archives"), settings, - blog=True, paginated={}, + articles=generator.articles, + dates=generator.dates, blog=True, + template_name='archives', page_name='archives/index', url="archives/") @@ -404,13 +408,15 @@ class TestArticlesGenerator(unittest.TestCase): write = MagicMock() generator.generate_period_archives(write) dates = [d for d in generator.dates if d.date.year == 1970] + articles = [d for d in generator.articles if d.date.year == 1970] self.assertEqual(len(dates), 1) # among other things it must have at least been called with this settings["period"] = (1970,) write.assert_called_with("posts/1970/index.html", generator.get_template("period_archives"), - settings, - blog=True, dates=dates, url="posts/1970/") + settings, blog=True, articles=articles, + dates=dates, template_name='period_archives', + url="posts/1970/") del settings["period"] settings['MONTH_ARCHIVE_SAVE_AS'] = \ @@ -425,13 +431,16 @@ class TestArticlesGenerator(unittest.TestCase): generator.generate_period_archives(write) dates = [d for d in generator.dates if d.date.year == 1970 and d.date.month == 1] + articles = [d for d in generator.articles + if d.date.year == 1970 and d.date.month == 1] self.assertEqual(len(dates), 1) settings["period"] = (1970, "January") # among other things it must have at least been called with this write.assert_called_with("posts/1970/Jan/index.html", generator.get_template("period_archives"), - settings, - blog=True, dates=dates, url="posts/1970/Jan/") + settings, blog=True, articles=articles, + dates=dates, template_name='period_archives', + url="posts/1970/Jan/") del settings["period"] settings['DAY_ARCHIVE_SAVE_AS'] = \ @@ -450,13 +459,19 @@ class TestArticlesGenerator(unittest.TestCase): d.date.month == 1 and d.date.day == 1 ] + articles = [ + d for d in generator.articles if + d.date.year == 1970 and + d.date.month == 1 and + d.date.day == 1 + ] self.assertEqual(len(dates), 1) settings["period"] = (1970, "January", 1) # among other things it must have at least been called with this write.assert_called_with("posts/1970/Jan/01/index.html", generator.get_template("period_archives"), - settings, - blog=True, dates=dates, + settings, blog=True, articles=articles, + dates=dates, template_name='period_archives', url="posts/1970/Jan/01/") locale.setlocale(locale.LC_ALL, old_locale) diff --git a/pelican/tests/test_paginator.py b/pelican/tests/test_paginator.py index 12403410..6174dca1 100644 --- a/pelican/tests/test_paginator.py +++ b/pelican/tests/test_paginator.py @@ -66,13 +66,12 @@ class TestPage(unittest.TestCase): (1, '/{url}', '{base_name}/index.html'), (2, '/{url}{number}/', '{base_name}/{number}/index.html') ]] - settings['DEFAULT_PAGINATION'] = 1 self.page_kwargs['metadata']['author'] = Author('Blogger', settings) object_list = [Article(**self.page_kwargs), Article(**self.page_kwargs)] paginator = Paginator('blog/index.html', '//blog.my.site/', - object_list, settings) + object_list, settings, 1) page1 = paginator.page(1) self.assertEqual(page1.save_as, 'blog/index.html') self.assertEqual(page1.url, '//blog.my.site/') diff --git a/pelican/tests/test_settings.py b/pelican/tests/test_settings.py index 4ec16c0f..393c4337 100644 --- a/pelican/tests/test_settings.py +++ b/pelican/tests/test_settings.py @@ -177,6 +177,15 @@ class TestSettingsConfiguration(unittest.TestCase): ['/foo/bar', '/ha']) self.assertNotIn('EXTRA_TEMPLATES_PATHS', settings) + def test_deprecated_paginated_direct_templates(self): + settings = self.settings + settings['PAGINATED_DIRECT_TEMPLATES'] = ['index', 'archives'] + settings['PAGINATED_TEMPLATES'] = {'index': 10, 'category': None} + settings = configure_settings(settings) + self.assertEqual(settings['PAGINATED_TEMPLATES'], + {'index': 10, 'category': None, 'archives': None}) + self.assertNotIn('PAGINATED_DIRECT_TEMPLATES', settings) + def test_theme_and_extra_templates_exception(self): settings = self.settings settings['EXTRA_TEMPLATES_PATHS'] = ['/ha'] diff --git a/pelican/writers.py b/pelican/writers.py index 523af0d0..9311aa10 100644 --- a/pelican/writers.py +++ b/pelican/writers.py @@ -151,7 +151,8 @@ class Writer(object): return feed def write_file(self, name, template, context, relative_urls=False, - paginated=None, override_output=False, url=None, **kwargs): + paginated=None, template_name=None, override_output=False, + url=None, **kwargs): """Render the template and write the file. :param name: name of the file to output @@ -160,6 +161,7 @@ class Writer(object): :param relative_urls: use relative urls or absolutes ones :param paginated: dict of article list to paginate - must have the same length (same list in different orders) + :param template_name: the template name, for pagination :param override_output: boolean telling if we can override previous output with the same name (and if next files written with the same name should be skipped to keep that one) @@ -209,11 +211,19 @@ class Writer(object): localcontext.update(kwargs) return localcontext - # pagination - if paginated: + if paginated is None: + paginated = {key: val for key, val in kwargs.items() + if key in {'articles', 'dates'}} - # pagination needed, init paginators - paginators = {key: Paginator(name, url, val, self.settings) + # pagination + if paginated and template_name in self.settings['PAGINATED_TEMPLATES']: + # pagination needed + per_page = self.settings['PAGINATED_TEMPLATES'][template_name] \ + or self.settings['DEFAULT_PAGINATION'] + + # init paginators + paginators = {key: Paginator(name, url, val, self.settings, + per_page) for key, val in paginated.items()} # generated pages, and write