Mercurial > piecrust2
changeset 369:4b1019bb2533
serve: Giant refactor to change how we handle data when serving pages.
* We need a distinction between source metadata and route metadata. In most
cases they're the same, but in cases like taxonomy pages, route metadata
contains more things that can't be in source metadata if we want to re-use
cached pages.
* Create a new `QualifiedPage` type which is a page with a specific route
and route metadata. Pass this around in many places.
* Instead of passing an URL around, use the route in the `QualifiedPage` to
generate URLs. This is better since it removes the guess-work from trying
to generate URLs for sub-pages.
* Deep-copy app and page configurations before passing them around to things
that could modify them, like data builders and such.
* Exclude taxonomy pages from iterator data providers.
* Properly nest iterator data providers for when the theme and user page
sources are merged inside `site.pages`.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 03 May 2015 18:47:10 -0700 |
parents | 2408eb6f4da8 |
children | a1bbe66cba03 |
files | piecrust/app.py piecrust/baking/baker.py piecrust/baking/single.py piecrust/data/base.py piecrust/data/builder.py piecrust/data/paginator.py piecrust/data/provider.py piecrust/rendering.py piecrust/routing.py piecrust/serving.py piecrust/sources/base.py piecrust/sources/mixins.py piecrust/sources/pageref.py piecrust/sources/prose.py tests/bakes/test_data_provider.bake tests/bakes/test_pagination.bake tests/bakes/test_simple.bake tests/mockutil.py tests/test_data_paginator.py tests/test_data_provider.py tests/test_routing.py tests/test_serving.py tests/test_templating_jinjaengine.py tests/test_templating_pystacheengine.py |
diffstat | 24 files changed, 286 insertions(+), 136 deletions(-) [+] |
line wrap: on
line diff
--- a/piecrust/app.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/app.py Sun May 03 18:47:10 2015 -0700 @@ -537,11 +537,11 @@ if not skip_taxonomies or route.taxonomy_name is None: yield route - def getRoute(self, source_name, source_metadata, *, skip_taxonomies=False): + def getRoute(self, source_name, route_metadata, *, skip_taxonomies=False): for route in self.getRoutes(source_name, skip_taxonomies=skip_taxonomies): - if (source_metadata is None or - route.matchesMetadata(source_metadata)): + if (route_metadata is None or + route.matchesMetadata(route_metadata)): return route return None
--- a/piecrust/baking/baker.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/baking/baker.py Sun May 03 18:47:10 2015 -0700 @@ -277,18 +277,13 @@ tax.page_ref) continue - tax_page_source = tax_page_ref.source - tax_page_rel_path = tax_page_ref.rel_path logger.debug( "Using taxonomy page: %s:%s" % - (tax_page_source.name, tax_page_rel_path)) - + (tax_page_ref.source_name, tax_page_ref.rel_path)) for term in terms: - fac = PageFactory( - tax_page_source, tax_page_rel_path, - {tax.term_name: term}) + fac = tax_page_ref.getFactory() logger.debug( - "Queuing: %s [%s, %s]" % + "Queuing: %s [%s=%s]" % (fac.ref_spec, tax_name, term)) entry = BakeRecordPageEntry( fac.source.name, fac.rel_path, fac.path,
--- a/piecrust/baking/single.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/baking/single.py Sun May 03 18:47:10 2015 -0700 @@ -1,4 +1,5 @@ import os.path +import copy import shutil import codecs import logging @@ -10,7 +11,7 @@ IsFilterClause, AndBooleanClause, page_value_accessor) from piecrust.rendering import ( - PageRenderingContext, render_page, + QualifiedPage, PageRenderingContext, render_page, PASS_FORMATTING, PASS_RENDERING) from piecrust.sources.base import ( PageFactory, @@ -22,7 +23,7 @@ def copy_public_page_config(config): - res = config.get().copy() + res = config.getDeepcopy() for k in list(res.keys()): if k.startswith('__'): del res[k] @@ -60,10 +61,12 @@ return os.path.normpath(os.path.join(*bake_path)) def bake(self, factory, route, record_entry): + # Get the page. + page = factory.buildPage() + route_metadata = copy.deepcopy(factory.metadata) + + # Add taxonomy info in the template data and route metadata if needed. bake_taxonomy_info = None - route_metadata = dict(factory.metadata) - - # Add taxonomy metadata for generating the URL if needed. if record_entry.taxonomy_info: tax_name, tax_term, tax_source_name = record_entry.taxonomy_info taxonomy = self.app.getTaxonomy(tax_name) @@ -71,8 +74,7 @@ route_metadata[taxonomy.term_name] = slugified_term bake_taxonomy_info = (taxonomy, tax_term) - # Generate the URL using the route. - page = factory.buildPage() + # Generate the URI. uri = route.getUri(route_metadata, provider=page) # See if this URL has been overriden by a previously baked page. @@ -209,7 +211,8 @@ BakeRecordSubPageEntry.FLAG_FORMATTING_INVALIDATED logger.debug(" p%d -> %s" % (cur_sub, out_path)) - ctx, rp = self._bakeSingle(page, sub_uri, cur_sub, out_path, + qp = QualifiedPage(page, route, route_metadata) + ctx, rp = self._bakeSingle(qp, cur_sub, out_path, bake_taxonomy_info) except Exception as ex: if self.app.debug: @@ -257,10 +260,8 @@ cur_sub += 1 has_more_subs = True - def _bakeSingle(self, page, sub_uri, num, out_path, - taxonomy_info=None): - ctx = PageRenderingContext(page, sub_uri) - ctx.page_num = num + def _bakeSingle(self, qualified_page, num, out_path, taxonomy_info=None): + ctx = PageRenderingContext(qualified_page, page_num=num) if taxonomy_info: ctx.setTaxonomyFilter(taxonomy_info[0], taxonomy_info[1])
--- a/piecrust/data/base.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/data/base.py Sun May 03 18:47:10 2015 -0700 @@ -1,3 +1,4 @@ +import copy import time import logging from piecrust.data.assetor import Assetor @@ -97,7 +98,7 @@ def _load(self): if self._values is not None: return - self._values = dict(self._page.config.get()) + self._values = self._page.config.getDeepcopy(self._page.app.debug) try: self._loadCustom() except Exception as ex: @@ -119,13 +120,20 @@ class PaginationData(LazyPageConfigData): def __init__(self, page): super(PaginationData, self).__init__(page) + self._route = None + self._route_metadata = None def _get_uri(self): page = self._page - route = page.app.getRoute(page.source.name, page.source_metadata) - if route is None: - raise Exception("Can't get route for page: %s" % page.path) - return route.getUri(page.source_metadata, provider=page) + if self._route is None: + # TODO: this is not quite correct, as we're missing parts of the + # route metadata if the current page is a taxonomy page. + self._route = page.app.getRoute(page.source.name, + page.source_metadata) + self._route_metadata = copy.deepcopy(page.source_metadata) + if self._route is None: + raise Exception("Can't get route for page: %s" % page.path) + return self._route.getUri(self._route_metadata, provider=page) def _loadCustom(self): page_url = self._get_uri() @@ -161,8 +169,11 @@ uri = self._get_uri() try: from piecrust.rendering import ( - PageRenderingContext, render_page_segments) - ctx = PageRenderingContext(self._page, uri) + QualifiedPage, PageRenderingContext, + render_page_segments) + qp = QualifiedPage(self._page, self._route, + self._route_metadata) + ctx = PageRenderingContext(qp) segs = render_page_segments(ctx) except Exception as e: raise Exception(
--- a/piecrust/data/builder.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/data/builder.py Sun May 03 18:47:10 2015 -0700 @@ -1,22 +1,23 @@ import re import time +import copy import logging +from werkzeug.utils import cached_property from piecrust import APP_VERSION from piecrust.configuration import merge_dicts from piecrust.data.assetor import Assetor from piecrust.data.debug import build_debug_info from piecrust.data.linker import PageLinkerData from piecrust.data.paginator import Paginator -from piecrust.uriutil import split_uri, split_sub_uri +from piecrust.uriutil import split_sub_uri logger = logging.getLogger(__name__) class DataBuildingContext(object): - def __init__(self, page, uri, page_num=1): - self.page = page - self.uri = uri + def __init__(self, qualified_page, page_num=1): + self.page = qualified_page self.page_num = page_num self.pagination_source = None self.pagination_filter = None @@ -25,29 +26,34 @@ def app(self): return self.page.app + @cached_property + def uri(self): + return self.page.getUri(self.page_num) + def build_page_data(ctx): + app = ctx.app page = ctx.page - app = page.app first_uri, _ = split_sub_uri(app, ctx.uri) - _, slug = split_uri(app, ctx.uri) pc_data = PieCrustData() pgn_source = ctx.pagination_source or get_default_pagination_source(page) - paginator = Paginator(page, pgn_source, ctx.page_num, - ctx.pagination_filter) + paginator = Paginator(page, pgn_source, + page_num=ctx.page_num, + pgn_filter=ctx.pagination_filter) assetor = Assetor(page, first_uri) linker = PageLinkerData(page.source, page.rel_path) data = { 'piecrust': pc_data, - 'page': dict(page.config.get()), + 'page': {}, 'assets': assetor, 'pagination': paginator, 'family': linker } page_data = data['page'] + page_data.update(copy.deepcopy(page.source_metadata)) + page_data.update(page.config.getDeepcopy(app.debug)) page_data['url'] = ctx.uri - page_data['slug'] = slug page_data['timestamp'] = time.mktime(page.datetime.timetuple()) date_format = app.config.get('site/date_format') if date_format: @@ -68,13 +74,11 @@ def build_layout_data(page, page_data, contents): - data = dict(page_data) for name, txt in contents.items(): - if name in data: + if name in page_data: logger.warning("Content segment '%s' will hide existing data." % - name) - data[name] = txt - return data + name) + page_data[name] = txt class PieCrustData(object): @@ -109,7 +113,7 @@ def build_site_data(page): app = page.app - data = dict(app.config.get()) + data = app.config.getDeepcopy(app.debug) for source in app.sources: endpoint_bits = re_endpoint_sep.split(source.data_endpoint) endpoint = data @@ -119,8 +123,6 @@ endpoint = endpoint[e] user_data = endpoint.get(endpoint_bits[-1]) provider = source.buildDataProvider(page, user_data) - if endpoint_bits[-1] in endpoint: - provider.user_data = endpoint[endpoint_bits[-1]] endpoint[endpoint_bits[-1]] = provider return data
--- a/piecrust/data/paginator.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/data/paginator.py Sun May 03 18:47:10 2015 -0700 @@ -23,12 +23,11 @@ 'total_item_count', 'total_page_count', 'next_item', 'prev_item'] - def __init__(self, page, source, page_num=1, pgn_filter=None, - items_per_page=-1): - self._parent_page = page + def __init__(self, qualified_page, source, *, + page_num=1, pgn_filter=None, items_per_page=-1): + self._parent_page = qualified_page self._source = source self._page_num = page_num - self._route = None self._iterator = None self._pgn_filter = pgn_filter self._items_per_page = items_per_page @@ -214,17 +213,7 @@ return f def _getPageUri(self, index): - if self._route is None: - app = self._source.app - self._route = app.getRoute(self._parent_page.source.name, - self._parent_page.source_metadata) - if self._route is None: - raise Exception("Can't get route for page: %s" % - self._parent_page.path) - - return self._route.getUri(self._parent_page.source_metadata, - provider=self._parent_page, - sub_num=index) + return self._parent_page.getUri(index) def _onIteration(self): if self._parent_page is not None and not self._pgn_set_on_ctx:
--- a/piecrust/data/provider.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/data/provider.py Sun May 03 18:47:10 2015 -0700 @@ -34,25 +34,20 @@ return [] -class CompositeDataProvider(object): - def __init__(self, providers): - self._providers = providers - - def __getattr__(self, name): - for p in self._providers: - try: - return getattr(p, name) - except AttributeError: - pass - raise AttributeError() - - class IteratorDataProvider(DataProvider): PROVIDER_NAME = 'iterator' debug_render_doc = """Provides a list of pages.""" def __init__(self, source, page, user_data): + self._innerIt = None + if isinstance(user_data, IteratorDataProvider): + # Iterator providers can be chained, like for instance with + # `site.pages` listing both the theme pages and the user site's + # pages. + self._innerIt = user_data + user_data = None + super(IteratorDataProvider, self).__init__(source, page, user_data) self._pages = PageIterator(source, current_page=page) self._pages._iter_event += self._onIteration @@ -65,7 +60,9 @@ return self._pages[key] def __iter__(self): - return iter(self._pages) + yield from iter(self._pages) + if self._innerIt: + yield from self._innerIt def _onIteration(self): if not self._ctx_set:
--- a/piecrust/rendering.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/rendering.py Sun May 03 18:47:10 2015 -0700 @@ -1,6 +1,7 @@ import re import os.path import logging +from werkzeug.utils import cached_property from piecrust.data.builder import (DataBuildingContext, build_page_data, build_layout_data) from piecrust.data.filters import ( @@ -25,6 +26,20 @@ pass +class QualifiedPage(object): + def __init__(self, page, route, route_metadata): + self.page = page + self.route = route + self.route_metadata = route_metadata + + def getUri(self, sub_num=1): + return self.route.getUri(self.route_metadata, provider=self.page, + sub_num=sub_num) + + def __getattr__(self, name): + return getattr(self.page, name) + + class RenderedPage(object): def __init__(self, page, uri, num=1): self.page = page @@ -53,9 +68,8 @@ class PageRenderingContext(object): - def __init__(self, page, uri, page_num=1, force_render=False): - self.page = page - self.uri = uri + def __init__(self, qualified_page, page_num=1, force_render=False): + self.page = qualified_page self.page_num = page_num self.force_render = force_render self.pagination_source = None @@ -75,6 +89,10 @@ def source_metadata(self): return self.page.source_metadata + @cached_property + def uri(self): + return self.page.getUri(self.page_num) + @property def current_pass_info(self): return self.render_passes.get(self._current_pass) @@ -129,7 +147,7 @@ page = ctx.page # Build the data for both segment and layout rendering. - data_ctx = DataBuildingContext(page, ctx.uri, ctx.page_num) + data_ctx = DataBuildingContext(page, page_num=ctx.page_num) data_ctx.pagination_source = ctx.pagination_source data_ctx.pagination_filter = ctx.pagination_filter page_data = build_page_data(data_ctx) @@ -156,8 +174,8 @@ layout_name = page.source.config.get('default_layout', 'default') null_names = ['', 'none', 'nil'] if layout_name not in null_names: - layout_data = build_layout_data(page, page_data, contents) - output = render_layout(layout_name, page, layout_data) + build_layout_data(page, page_data, contents) + output = render_layout(layout_name, page, page_data) else: output = contents['content'] @@ -173,8 +191,9 @@ def render_page_segments(ctx): repo = ctx.app.env.rendered_segments_repository if repo: - cache_key = '%s:%s' % (ctx.uri, ctx.page_num) - return repo.get(cache_key, + cache_key = ctx.uri + return repo.get( + cache_key, lambda: _do_render_page_segments_from_ctx(ctx), fs_cache_time=ctx.page.path_mtime) @@ -186,7 +205,7 @@ eis.pushPage(ctx.page, ctx) ctx.setCurrentPass(PASS_FORMATTING) try: - data_ctx = DataBuildingContext(ctx.page, ctx.uri, ctx.page_num) + data_ctx = DataBuildingContext(ctx.page, page_num=ctx.page_num) page_data = build_page_data(data_ctx) return _do_render_page_segments(ctx.page, page_data) finally:
--- a/piecrust/routing.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/routing.py Sun May 03 18:47:10 2015 -0700 @@ -1,5 +1,6 @@ import re import os.path +import copy import logging @@ -65,9 +66,9 @@ else: self.uri_re_no_path = None - self.required_source_metadata = set() + self.required_route_metadata = set() for m in route_re.finditer(self.uri_pattern): - self.required_source_metadata.add(m.group('name')) + self.required_route_metadata.add(m.group('name')) self.template_func = None self.template_func_name = None @@ -86,8 +87,8 @@ def source_realm(self): return self.source.realm - def matchesMetadata(self, source_metadata): - return self.required_source_metadata.issubset(source_metadata.keys()) + def matchesMetadata(self, route_metadata): + return self.required_route_metadata.issubset(route_metadata.keys()) def matchUri(self, uri): if not uri.startswith(self.uri_root): @@ -108,17 +109,17 @@ return m.groupdict() return None - def getUri(self, source_metadata, *, sub_num=1, provider=None): + def getUri(self, route_metadata, *, sub_num=1, provider=None): + route_metadata = copy.deepcopy(route_metadata) if provider: - source_metadata = dict(source_metadata) - source_metadata.update(provider.getRouteMetadata()) + route_metadata.update(provider.getRouteMetadata()) #TODO: fix this hard-coded shit for key in ['year', 'month', 'day']: - if key in source_metadata and isinstance(source_metadata[key], str): - source_metadata[key] = int(source_metadata[key]) + if key in route_metadata and isinstance(route_metadata[key], str): + route_metadata[key] = int(route_metadata[key]) - uri = self.uri_format % source_metadata + uri = self.uri_format % route_metadata suffix = None if sub_num > 1: # Note that we know the pagination suffix starts with a slash.
--- a/piecrust/serving.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/serving.py Sun May 03 18:47:10 2015 -0700 @@ -18,7 +18,7 @@ from piecrust.app import PieCrust from piecrust.environment import StandardEnvironment from piecrust.processing.base import ProcessorPipeline -from piecrust.rendering import PageRenderingContext, render_page +from piecrust.rendering import QualifiedPage, PageRenderingContext, render_page from piecrust.sources.base import PageFactory, MODE_PARSING from piecrust.uriutil import split_sub_uri @@ -252,7 +252,9 @@ page = factory.buildPage() # We force the rendering of the page because it could not have # changed, but include pages that did change. - render_ctx = PageRenderingContext(page, req_path, page_num, + qp = QualifiedPage(page, route, route_metadata) + render_ctx = PageRenderingContext(qp, + page_num=page_num, force_render=True) if taxonomy is not None: render_ctx.setTaxonomyFilter(taxonomy, tax_terms)
--- a/piecrust/sources/base.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/sources/base.py Sun May 03 18:47:10 2015 -0700 @@ -1,3 +1,4 @@ +import copy import logging from werkzeug.utils import cached_property from piecrust.configuration import ConfigurationError @@ -57,7 +58,7 @@ def _doBuildPage(self): logger.debug("Building page: %s" % self.path) - page = Page(self.source, self.metadata, self.rel_path) + page = Page(self.source, copy.deepcopy(self.metadata), self.rel_path) # Load it right away, especially when using the page repository, # because we'll be inside a critical scope. page._load()
--- a/piecrust/sources/mixins.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/sources/mixins.py Sun May 03 18:47:10 2015 -0700 @@ -5,6 +5,7 @@ from piecrust.data.filters import PaginationFilter, page_value_accessor from piecrust.sources.base import PageFactory from piecrust.sources.interfaces import IPaginationSource, IListableSource +from piecrust.sources.pageref import PageNotFoundError logger = logging.getLogger(__name__) @@ -22,6 +23,33 @@ return self.source.getPages() +class SourceFactoryWithoutTaxonomiesIterator(object): + def __init__(self, source): + self.source = source + self._taxonomy_pages = None + # See comment above. + self.it = None + + def __iter__(self): + self._cacheTaxonomyPages() + for p in self.source.getPages(): + if p.rel_path in self._taxonomy_pages: + continue + yield p + + def _cacheTaxonomyPages(self): + if self._taxonomy_pages is not None: + return + + self._taxonomy_pages = set() + for tax in self.source.app.taxonomies: + page_ref = tax.getPageRef(self.source.name) + try: + self._taxonomy_pages.add(page_ref.rel_path) + except PageNotFoundError: + pass + + class DateSortIterator(object): def __init__(self, it, reverse=True): self.it = it @@ -52,7 +80,9 @@ return self.config['items_per_page'] def getSourceIterator(self): - return SourceFactoryIterator(self) + if self.config.get('iteration_includes_taxonomies', False): + return SourceFactoryIterator(self) + return SourceFactoryWithoutTaxonomiesIterator(self) def getSorterIterator(self, it): return DateSortIterator(it)
--- a/piecrust/sources/pageref.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/sources/pageref.py Sun May 03 18:47:10 2015 -0700 @@ -1,5 +1,6 @@ import re import os.path +import copy from piecrust.sources.base import PageFactory @@ -74,7 +75,8 @@ return [h.path for h in self._hits] def getFactory(self): - return PageFactory(self.source, self.rel_path, self.metadata) + return PageFactory(self.source, self.rel_path, + copy.deepcopy(self.metadata)) @property def _first_valid_hit(self): @@ -95,15 +97,14 @@ if source is None: raise Exception("No such source: %s" % source_name) rel_path = m.group('path') - path, metadata = source.resolveRef(rel_path) if '%ext%' in rel_path: for e in self._exts: + cur_rel_path = rel_path.replace('%ext%', e) + path, metadata = source.resolveRef(cur_rel_path) self._hits.append(self._HitInfo( - source_name, - rel_path.replace('%ext%', e), - path.replace('%ext%', e), - metadata)) + source_name, cur_rel_path, path, metadata)) else: + path, metadata = source.resolveRef(rel_path) self._hits.append( self._HitInfo(source_name, rel_path, path, metadata))
--- a/piecrust/sources/prose.py Sun May 03 18:43:28 2015 -0700 +++ b/piecrust/sources/prose.py Sun May 03 18:47:10 2015 -0700 @@ -1,7 +1,8 @@ import os import os.path +import copy import logging -from piecrust.sources.base import MODE_CREATING +from piecrust.sources.base import MODE_CREATING, MODE_PARSING from piecrust.sources.default import DefaultPageSource @@ -19,10 +20,14 @@ metadata['config'] = self._makeConfig(rel_path, mode) def _makeConfig(self, rel_path, mode): - c = dict(self.config_recipe) + c = copy.deepcopy(self.config_recipe) if c.get('title') == '%first_line%' and mode != MODE_CREATING: path = os.path.join(self.fs_endpoint_path, rel_path) - c['title'] = get_first_line(path) + try: + c['title'] = get_first_line(path) + except OSError: + if mode == MODE_PARSING: + raise return c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/bakes/test_data_provider.bake Sun May 03 18:47:10 2015 -0700 @@ -0,0 +1,16 @@ +--- +in: + pages/foo.md: | + Foo! + pages/bar.md: | + Bar! + pages/allpages.md: | + {% for p in site.pages -%} + {{p.url}} + {% endfor %} +outfiles: + allpages.html: | + / + /allpages.html + /bar.html + /foo.html
--- a/tests/bakes/test_pagination.bake Sun May 03 18:43:28 2015 -0700 +++ b/tests/bakes/test_pagination.bake Sun May 03 18:47:10 2015 -0700 @@ -39,3 +39,52 @@ /foo/page2.html /foo/page3.html None +--- +config: + site: + posts_per_page: 3 +in: + posts/2015-03-01_post01.md: | + --- + title: Post 01 + tags: [foo] + --- + posts/2015-03-02_post02.md: | + --- + title: Post 02 + tags: [foo] + --- + posts/2015-03-03_post03.md: | + --- + title: Post 03 + tags: [foo] + --- + posts/2015-03-04_post04.md: | + --- + title: Post 04 + tags: [foo] + --- + posts/2015-03-05_post05.md: | + --- + title: Post 05 + tags: [foo] + --- + pages/_index.md: '' + pages/_tag.md: | + Posts with {{tag}} + {% for p in pagination.items -%} + {{p.url}} {{p.title}} + {% endfor -%} + {{pagination.prev_page}} + {{pagination.this_page}} + {{pagination.next_page}} +outfiles: + tag/foo.html: | + Posts with foo + /2015/03/05/post05.html Post 05 + /2015/03/04/post04.html Post 04 + /2015/03/03/post03.html Post 03 + None + /tag/foo.html + /tag/foo/2.html +
--- a/tests/bakes/test_simple.bake Sun May 03 18:43:28 2015 -0700 +++ b/tests/bakes/test_simple.bake Sun May 03 18:47:10 2015 -0700 @@ -25,4 +25,11 @@ post1.html: 'post one' about.html: 'URL: /whatever/about.html' index.html: 'something' +--- +in: + pages/foo.md: | + This page is {{page.url}} +outfiles: + foo.html: | + This page is /foo.html
--- a/tests/mockutil.py Sun May 03 18:43:28 2015 -0700 +++ b/tests/mockutil.py Sun May 03 18:47:10 2015 -0700 @@ -8,7 +8,7 @@ import yaml from piecrust.app import PieCrust, PieCrustConfiguration from piecrust.page import Page -from piecrust.rendering import PageRenderingContext, render_page +from piecrust.rendering import QualifiedPage, PageRenderingContext, render_page resources_path = os.path.abspath( @@ -25,12 +25,13 @@ def get_simple_page(app, rel_path): source = app.getSource('pages') - metadata = {'path': os.path.splitext(rel_path)[0]} + metadata = {'slug': os.path.splitext(rel_path)[0]} return Page(source, metadata, rel_path) -def render_simple_page(page, uri): - ctx = PageRenderingContext(page, uri) +def render_simple_page(page, route, route_metadata): + qp = QualifiedPage(page, route, route_metadata) + ctx = PageRenderingContext(qp) rp = render_page(ctx) return rp.content
--- a/tests/test_data_paginator.py Sun May 03 18:43:28 2015 -0700 +++ b/tests/test_data_paginator.py Sun May 03 18:47:10 2015 -0700 @@ -1,4 +1,5 @@ import math +import mock import pytest from piecrust.data.paginator import Paginator from piecrust.sources.interfaces import IPaginationSource @@ -44,17 +45,17 @@ ('blog', 3, 14) ]) def test_paginator(uri, page_num, count): - def _mock_get_uri(index): + def _get_mock_uri(sub_num): res = uri - if index > 1: + if sub_num > 1: if res != '' and not res.endswith('/'): res += '/' - res += '%d' % index + res += '%d' % sub_num return res source = MockSource(count) - p = Paginator(None, source, page_num) - p._getPageUri = _mock_get_uri + p = Paginator(None, source, page_num=page_num) + p._getPageUri = _get_mock_uri if count <= 5: # All posts fit on the page
--- a/tests/test_data_provider.py Sun May 03 18:43:28 2015 -0700 +++ b/tests/test_data_provider.py Sun May 03 18:47:10 2015 -0700 @@ -1,4 +1,4 @@ -from piecrust.rendering import PageRenderingContext, render_page +from piecrust.rendering import QualifiedPage, PageRenderingContext, render_page from .mockutil import mock_fs, mock_fs_scope @@ -18,7 +18,10 @@ with mock_fs_scope(fs): app = fs.getApp() page = app.getSource('pages').getPage({'slug': 'categories'}) - ctx = PageRenderingContext(page, '/categories') + route = app.getRoute('pages', None) + route_metadata = {'slug': 'categories'} + qp = QualifiedPage(page, route, route_metadata) + ctx = PageRenderingContext(qp) rp = render_page(ctx) expected = "\nBar (1)\n\nFoo (2)\n" assert rp.content == expected
--- a/tests/test_routing.py Sun May 03 18:43:28 2015 -0700 +++ b/tests/test_routing.py Sun May 03 18:47:10 2015 -0700 @@ -42,7 +42,7 @@ app.config.set('site/root', site_root.rstrip('/') + '/') config = {'url': route_pattern, 'source': 'blah'} route = Route(app, config) - assert route.required_source_metadata == expected_required_metadata + assert route.required_route_metadata == expected_required_metadata @pytest.mark.parametrize(
--- a/tests/test_serving.py Sun May 03 18:43:28 2015 -0700 +++ b/tests/test_serving.py Sun May 03 18:47:10 2015 -0700 @@ -4,7 +4,7 @@ from piecrust.data.filters import ( PaginationFilter, HasFilterClause, IsFilterClause, page_value_accessor) -from piecrust.rendering import PageRenderingContext, render_page +from piecrust.rendering import QualifiedPage, PageRenderingContext, render_page from piecrust.serving import find_routes from piecrust.sources.base import REALM_USER, REALM_THEME from .mockutil import mock_fs, mock_fs_scope @@ -74,10 +74,13 @@ "{%endfor%}")) with mock_fs_scope(fs): app = fs.getApp() - page = app.getSource('pages').getPage({'slug': '_tag'}) + page = app.getSource('pages').getPage({'slug': '_tag', 'tag': tag}) + route = app.getTaxonomyRoute('tags', 'posts') + route_metadata = {'slug': '_tag', 'tag': tag} taxonomy = app.getTaxonomy('tags') - ctx = PageRenderingContext(page, '/tag/' + tag) + qp = QualifiedPage(page, route, route_metadata) + ctx = PageRenderingContext(qp) ctx.setTaxonomyFilter(taxonomy, tag) rp = render_page(ctx) @@ -115,10 +118,14 @@ "{%endfor%}")) with mock_fs_scope(fs): app = fs.getApp() - page = app.getSource('pages').getPage({'slug': '_category'}) + page = app.getSource('pages').getPage({'slug': '_category', + 'category': category}) + route = app.getTaxonomyRoute('categories', 'posts') + route_metadata = {'slug': '_category', 'category': category} taxonomy = app.getTaxonomy('categories') - ctx = PageRenderingContext(page, '/' + category) + qp = QualifiedPage(page, route, route_metadata) + ctx = PageRenderingContext(qp) ctx.setTaxonomyFilter(taxonomy, category) rp = render_page(ctx)
--- a/tests/test_templating_jinjaengine.py Sun May 03 18:43:28 2015 -0700 +++ b/tests/test_templating_jinjaengine.py Sun May 03 18:47:10 2015 -0700 @@ -19,7 +19,7 @@ ("Raw text", "Raw text"), ("This is {{foo}}", "This is bar"), ("Info:\nMy URL: {{page.url}}\n", - "Info:\nMy URL: /foo") + "Info:\nMy URL: /foo.html") ]) def test_simple(contents, expected): fs = (mock_fs() @@ -28,7 +28,9 @@ with mock_fs_scope(fs, open_patches=open_patches): app = fs.getApp() page = get_simple_page(app, 'foo.md') - output = render_simple_page(page, '/foo') + route = app.getRoute('pages', None) + route_metadata = {'slug': 'foo'} + output = render_simple_page(page, route, route_metadata) assert output == expected @@ -44,14 +46,16 @@ with mock_fs_scope(fs, open_patches=open_patches): app = fs.getApp() page = get_simple_page(app, 'foo.md') - output = render_simple_page(page, '/foo') + route = app.getRoute('pages', None) + route_metadata = {'slug': 'foo'} + output = render_simple_page(page, route, route_metadata) assert output == expected def test_partial(): contents = "Info:\n{% include 'page_info.jinja' %}\n" partial = "- URL: {{page.url}}\n- SLUG: {{page.slug}}\n" - expected = "Info:\n- URL: /foo\n- SLUG: foo" + expected = "Info:\n- URL: /foo.html\n- SLUG: foo" fs = (mock_fs() .withConfig(app_config) .withAsset('templates/page_info.jinja', partial) @@ -59,6 +63,8 @@ with mock_fs_scope(fs, open_patches=open_patches): app = fs.getApp() page = get_simple_page(app, 'foo.md') - output = render_simple_page(page, '/foo') + route = app.getRoute('pages', None) + route_metadata = {'slug': 'foo'} + output = render_simple_page(page, route, route_metadata) assert output == expected
--- a/tests/test_templating_pystacheengine.py Sun May 03 18:43:28 2015 -0700 +++ b/tests/test_templating_pystacheengine.py Sun May 03 18:47:10 2015 -0700 @@ -19,7 +19,7 @@ ("Raw text", "Raw text"), ("This is {{foo}}", "This is bar"), ("Info:\n{{#page}}\nMy URL: {{url}}\n{{/page}}\n", - "Info:\nMy URL: /foo\n") + "Info:\nMy URL: /foo.html\n") ]) def test_simple(contents, expected): fs = (mock_fs() @@ -28,7 +28,9 @@ with mock_fs_scope(fs, open_patches=open_patches): app = fs.getApp() page = get_simple_page(app, 'foo.md') - output = render_simple_page(page, '/foo') + route = app.getRoute('pages', None) + route_metadata = {'slug': 'foo'} + output = render_simple_page(page, route, route_metadata) assert output == expected @@ -44,14 +46,16 @@ with mock_fs_scope(fs, open_patches=open_patches): app = fs.getApp() page = get_simple_page(app, 'foo.md') - output = render_simple_page(page, '/foo') + route = app.getRoute('pages', None) + route_metadata = {'slug': 'foo'} + output = render_simple_page(page, route, route_metadata) assert output == expected def test_partial(): contents = "Info:\n{{#page}}\n{{> page_info}}\n{{/page}}\n" partial = "- URL: {{url}}\n- SLUG: {{slug}}\n" - expected = "Info:\n- URL: /foo\n- SLUG: foo\n" + expected = "Info:\n- URL: /foo.html\n- SLUG: foo\n" fs = (mock_fs() .withConfig(app_config) .withAsset('templates/page_info.mustache', partial) @@ -59,6 +63,8 @@ with mock_fs_scope(fs, open_patches=open_patches): app = fs.getApp() page = get_simple_page(app, 'foo.md') - output = render_simple_page(page, '/foo') + route = app.getRoute('pages', None) + route_metadata = {'slug': 'foo'} + output = render_simple_page(page, route, route_metadata) assert output == expected