Merge pull request #2235 from mosra/paginator-pattern-url

Allow using page URL in pagination patterns
This commit is contained in:
Justin Mayer 2018-02-10 11:27:02 -08:00 committed by GitHub
commit 59fc1d02a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 89 additions and 25 deletions

View file

@ -464,14 +464,29 @@ respectively.
The location to save per-year archives of your posts.
.. data:: YEAR_ARCHIVE_URL = ''
The URL to use for per-year archives of your posts. Used only if you have
the ``{url}`` placeholder in ``PAGINATION_PATTERNS``.
.. data:: MONTH_ARCHIVE_SAVE_AS = ''
The location to save per-month archives of your posts.
.. data:: MONTH_ARCHIVE_URL = ''
The URL to use for per-month archives of your posts. Used only if you have
the ``{url}`` placeholder in ``PAGINATION_PATTERNS``.
.. data:: DAY_ARCHIVE_SAVE_AS = ''
The location to save per-day archives of your posts.
.. data:: DAY_ARCHIVE_URL = ''
The URL to use for per-day archives of your posts. Used only if you have the
``{url}`` placeholder in ``PAGINATION_PATTERNS``.
.. data:: SLUG_SUBSTITUTIONS = ()
Substitutions to make prior to stripping out non-alphanumerics when

View file

@ -262,7 +262,7 @@ class TemplatePagesGenerator(Generator):
template = self.env.get_template(source)
rurls = self.settings['RELATIVE_URLS']
writer.write_file(dest, template, self.context, rurls,
override_output=True)
override_output=True, url='')
finally:
del self.env.loader.loaders[0]
@ -376,7 +376,7 @@ class ArticlesGenerator(CachingGenerator):
write(article.save_as, self.get_template(article.template),
self.context, article=article, category=article.category,
override_output=hasattr(article, 'override_save_as'),
blog=True)
url=article.url, blog=True)
def generate_period_archives(self, write):
"""Generate per-year, per-month, and per-day archives."""
@ -391,13 +391,19 @@ class ArticlesGenerator(CachingGenerator):
'day': self.settings['DAY_ARCHIVE_SAVE_AS'],
}
period_url = {
'year': self.settings['YEAR_ARCHIVE_URL'],
'month': self.settings['MONTH_ARCHIVE_URL'],
'day': self.settings['DAY_ARCHIVE_URL'],
}
period_date_key = {
'year': attrgetter('date.year'),
'month': attrgetter('date.year', 'date.month'),
'day': attrgetter('date.year', 'date.month', 'date.day')
}
def _generate_period_archives(dates, key, save_as_fmt):
def _generate_period_archives(dates, key, save_as_fmt, url_fmt):
"""Generate period archives from `dates`, grouped by
`key` and written to `save_as`.
"""
@ -409,6 +415,7 @@ class ArticlesGenerator(CachingGenerator):
# period archive dates
date = archive[0].date
save_as = save_as_fmt.format(date=date)
url = url_fmt.format(date=date)
context = self.context.copy()
if key == period_date_key['year']:
@ -426,13 +433,14 @@ class ArticlesGenerator(CachingGenerator):
_period[2])
write(save_as, template, context,
dates=archive, blog=True)
dates=archive, blog=True, url=url)
for period in 'year', 'month', 'day':
save_as = period_save_as[period]
url = period_url[period]
if save_as:
key = period_date_key[period]
_generate_period_archives(self.dates, key, save_as)
_generate_period_archives(self.dates, key, save_as, url)
def generate_direct_templates(self, write):
"""Generate direct templates pages"""
@ -443,12 +451,14 @@ class ArticlesGenerator(CachingGenerator):
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(),
'%s.html' % template)
if not save_as:
continue
write(save_as, self.get_template(template),
self.context, blog=True, paginated=paginated,
page_name=os.path.splitext(save_as)[0])
page_name=os.path.splitext(save_as)[0], url=url)
def generate_tags(self, write):
"""Generate Tags pages."""
@ -457,7 +467,7 @@ class ArticlesGenerator(CachingGenerator):
articles.sort(key=attrgetter('date'), reverse=True)
dates = [article for article in self.dates if article in articles]
write(tag.save_as, tag_template, self.context, tag=tag,
articles=articles, dates=dates,
url=tag.url, articles=articles, dates=dates,
paginated={'articles': articles, 'dates': dates}, blog=True,
page_name=tag.page_name, all_articles=self.articles)
@ -468,7 +478,7 @@ class ArticlesGenerator(CachingGenerator):
articles.sort(key=attrgetter('date'), reverse=True)
dates = [article for article in self.dates if article in articles]
write(cat.save_as, category_template, self.context,
category=cat, articles=articles, dates=dates,
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)
@ -479,7 +489,7 @@ class ArticlesGenerator(CachingGenerator):
articles.sort(key=attrgetter('date'), reverse=True)
dates = [article for article in self.dates if article in articles]
write(aut.save_as, author_template, self.context,
author=aut, articles=articles, dates=dates,
url=aut.url, author=aut, articles=articles, dates=dates,
paginated={'articles': articles, 'dates': dates}, blog=True,
page_name=aut.page_name, all_articles=self.articles)
@ -489,7 +499,7 @@ class ArticlesGenerator(CachingGenerator):
write(draft.save_as, self.get_template(draft.template),
self.context, article=draft, category=draft.category,
override_output=hasattr(draft, 'override_save_as'),
blog=True, all_articles=self.articles)
blog=True, all_articles=self.articles, url=draft.url)
def generate_pages(self, writer):
"""Generate the pages on the disk"""
@ -662,7 +672,8 @@ class PagesGenerator(CachingGenerator):
page.save_as, self.get_template(page.template),
self.context, page=page,
relative_urls=self.settings['RELATIVE_URLS'],
override_output=hasattr(page, 'override_save_as'))
override_output=hasattr(page, 'override_save_as'),
url=page.url)
signals.page_writer_finalized.send(self, writer=writer)
def refresh_metadata_intersite_links(self):

View file

@ -17,8 +17,9 @@ PaginationRule = namedtuple(
class Paginator(object):
def __init__(self, name, object_list, settings):
def __init__(self, name, url, object_list, settings):
self.name = name
self.url = url
self.object_list = object_list
self.settings = settings
@ -37,8 +38,8 @@ class Paginator(object):
top = bottom + self.per_page
if top + self.orphans >= self.count:
top = self.count
return Page(self.name, self.object_list[bottom:top], number, self,
self.settings)
return Page(self.name, self.url, self.object_list[bottom:top], number,
self, self.settings)
def _get_count(self):
"Returns the total number of objects, across all pages."
@ -65,8 +66,9 @@ class Paginator(object):
class Page(object):
def __init__(self, name, object_list, number, paginator, settings):
def __init__(self, name, url, object_list, number, paginator, settings):
self.name, self.extension = os.path.splitext(name)
self.base_url = url
self.object_list = object_list
self.number = number
self.paginator = paginator
@ -134,6 +136,7 @@ class Page(object):
# URL or SAVE_AS is a string, format it with a controlled context
context = {
'name': self.name.replace(os.sep, '/'),
'url': self.base_url,
'object_list': self.object_list,
'number': self.number,
'paginator': self.paginator,

View file

@ -93,8 +93,11 @@ DEFAULT_CONFIG = {
'PAGINATION_PATTERNS': [
(0, '{name}{number}{extension}', '{name}{number}{extension}'),
],
'YEAR_ARCHIVE_URL': '',
'YEAR_ARCHIVE_SAVE_AS': '',
'MONTH_ARCHIVE_URL': '',
'MONTH_ARCHIVE_SAVE_AS': '',
'DAY_ARCHIVE_URL': '',
'DAY_ARCHIVE_SAVE_AS': '',
'RELATIVE_URLS': False,
'DEFAULT_LANG': 'en',

View file

@ -254,7 +254,7 @@ class TestArticlesGenerator(unittest.TestCase):
self.assertEqual(sorted(categories), sorted(categories_expected))
@unittest.skipUnless(MagicMock, 'Needs Mock module')
def test_direct_templates_save_as_default(self):
def test_direct_templates_save_as_url_default(self):
settings = get_settings(filenames={})
settings['CACHE_PATH'] = self.temp_cache
@ -265,14 +265,16 @@ 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')
blog=True, paginated={}, page_name='archives',
url="archives.html")
@unittest.skipUnless(MagicMock, 'Needs Mock module')
def test_direct_templates_save_as_modified(self):
def test_direct_templates_save_as_url_modified(self):
settings = get_settings()
settings['DIRECT_TEMPLATES'] = ['archives']
settings['ARCHIVES_SAVE_AS'] = 'archives/index.html'
settings['ARCHIVES_URL'] = 'archives/'
settings['CACHE_PATH'] = self.temp_cache
generator = ArticlesGenerator(
context=settings, settings=settings,
@ -282,7 +284,8 @@ class TestArticlesGenerator(unittest.TestCase):
write.assert_called_with("archives/index.html",
generator.get_template("archives"), settings,
blog=True, paginated={},
page_name='archives/index')
page_name='archives/index',
url="archives/")
@unittest.skipUnless(MagicMock, 'Needs Mock module')
def test_direct_templates_save_as_false(self):
@ -320,6 +323,7 @@ class TestArticlesGenerator(unittest.TestCase):
settings = get_settings(filenames={})
settings['YEAR_ARCHIVE_SAVE_AS'] = 'posts/{date:%Y}/index.html'
settings['YEAR_ARCHIVE_URL'] = 'posts/{date:%Y}/'
settings['CACHE_PATH'] = self.temp_cache
generator = ArticlesGenerator(
context=settings, settings=settings,
@ -334,11 +338,13 @@ class TestArticlesGenerator(unittest.TestCase):
write.assert_called_with("posts/1970/index.html",
generator.get_template("period_archives"),
settings,
blog=True, dates=dates)
blog=True, dates=dates, url="posts/1970/")
del settings["period"]
settings['MONTH_ARCHIVE_SAVE_AS'] = \
'posts/{date:%Y}/{date:%b}/index.html'
settings['MONTH_ARCHIVE_URL'] = \
'posts/{date:%Y}/{date:%b}/'
generator = ArticlesGenerator(
context=settings, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
@ -353,11 +359,13 @@ class TestArticlesGenerator(unittest.TestCase):
write.assert_called_with("posts/1970/Jan/index.html",
generator.get_template("period_archives"),
settings,
blog=True, dates=dates)
blog=True, dates=dates, url="posts/1970/Jan/")
del settings["period"]
settings['DAY_ARCHIVE_SAVE_AS'] = \
'posts/{date:%Y}/{date:%b}/{date:%d}/index.html'
settings['DAY_ARCHIVE_URL'] = \
'posts/{date:%Y}/{date:%b}/{date:%d}/'
generator = ArticlesGenerator(
context=settings, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
@ -376,7 +384,8 @@ class TestArticlesGenerator(unittest.TestCase):
write.assert_called_with("posts/1970/Jan/01/index.html",
generator.get_template("period_archives"),
settings,
blog=True, dates=dates)
blog=True, dates=dates,
url="posts/1970/Jan/01/")
locale.setlocale(locale.LC_ALL, old_locale)
def test_nonexistent_template(self):

View file

@ -54,6 +54,28 @@ class TestPage(unittest.TestCase):
self.page_kwargs['metadata']['author'] = Author('Blogger', settings)
object_list = [Article(**self.page_kwargs),
Article(**self.page_kwargs)]
paginator = Paginator('foobar.foo', object_list, settings)
paginator = Paginator('foobar.foo', 'foobar/foo', object_list,
settings)
page = paginator.page(1)
self.assertEqual(page.save_as, 'foobar.foo')
def test_custom_pagination_pattern(self):
from pelican.paginator import PaginationRule
settings = get_settings()
settings['PAGINATION_PATTERNS'] = [PaginationRule(*r) for r in [
(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)
page1 = paginator.page(1)
self.assertEqual(page1.save_as, 'blog/index.html')
self.assertEqual(page1.url, '//blog.my.site/')
page2 = paginator.page(2)
self.assertEqual(page2.save_as, 'blog/2/index.html')
self.assertEqual(page2.url, '//blog.my.site/2/')

View file

@ -141,7 +141,7 @@ class Writer(object):
return feed
def write_file(self, name, template, context, relative_urls=False,
paginated=None, override_output=False, **kwargs):
paginated=None, override_output=False, url=None, **kwargs):
"""Render the template and write the file.
:param name: name of the file to output
@ -153,6 +153,7 @@ class Writer(object):
: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)
:param url: url of the file (needed by the paginator)
:param **kwargs: additional variables to pass to the templates
"""
@ -202,7 +203,7 @@ class Writer(object):
if paginated:
# pagination needed, init paginators
paginators = {key: Paginator(name, val, self.settings)
paginators = {key: Paginator(name, url, val, self.settings)
for key, val in paginated.items()}
# generated pages, and write