comparison piecrust/data/builder.py @ 852:4850f8c21b6e

core: Start of the big refactor for PieCrust 3.0. * Everything is a `ContentSource`, including assets directories. * Most content sources are subclasses of the base file-system source. * A source is processed by a "pipeline", and there are 2 built-in pipelines, one for assets and one for pages. The asset pipeline is vaguely functional, but the page pipeline is completely broken right now. * Rewrite the baking process as just running appropriate pipelines on each content item. This should allow for better parallelization.
author Ludovic Chabant <ludovic@chabant.com>
date Wed, 17 May 2017 00:11:48 -0700
parents 71c4f43d8fc1
children f070a4fc033c
comparison
equal deleted inserted replaced
851:2c7e57d80bba 852:4850f8c21b6e
1 import logging 1 import logging
2 from werkzeug.utils import cached_property
3 from piecrust.data.base import MergedMapping 2 from piecrust.data.base import MergedMapping
4 from piecrust.data.linker import PageLinkerData 3 from piecrust.data.linker import PageLinkerData
5 from piecrust.data.pagedata import PageData 4 from piecrust.data.pagedata import PageData
6 from piecrust.data.paginator import Paginator 5 from piecrust.data.paginator import Paginator
7 from piecrust.data.piecrustdata import PieCrustData 6 from piecrust.data.piecrustdata import PieCrustData
8 from piecrust.data.providersdata import DataProvidersData 7 from piecrust.data.providersdata import DataProvidersData
9 from piecrust.routing import CompositeRouteFunction 8 from piecrust.routing import RouteFunction
10 9
11 10
12 logger = logging.getLogger(__name__) 11 logger = logging.getLogger(__name__)
13 12
14 13
15 class DataBuildingContext(object): 14 class DataBuildingContext(object):
16 def __init__(self, qualified_page, page_num=1): 15 def __init__(self, qualified_page):
17 self.page = qualified_page 16 self.qualified_page = qualified_page
18 self.page_num = page_num
19 self.pagination_source = None 17 self.pagination_source = None
20 self.pagination_filter = None 18 self.pagination_filter = None
21 19
22 @property
23 def app(self):
24 return self.page.app
25
26 @cached_property
27 def uri(self):
28 return self.page.getUri(self.page_num)
29
30 20
31 def build_page_data(ctx): 21 def build_page_data(ctx):
32 app = ctx.app 22 qpage = ctx.qualified_page
33 page = ctx.page 23 page = qpage.page
24 app = page.app
34 pgn_source = ctx.pagination_source or get_default_pagination_source(page) 25 pgn_source = ctx.pagination_source or get_default_pagination_source(page)
35 first_uri = ctx.page.getUri(1) 26 first_uri = ctx.page.getUri(1)
36 27
37 pc_data = PieCrustData() 28 pc_data = PieCrustData()
38 config_data = PageData(page, ctx) 29 config_data = PageData(page, ctx)
39 paginator = Paginator(page, pgn_source, 30 paginator = Paginator(qpage, pgn_source,
40 page_num=ctx.page_num,
41 pgn_filter=ctx.pagination_filter) 31 pgn_filter=ctx.pagination_filter)
42 assetor = page.source.buildAssetor(page, first_uri) 32 assetor = page.source.buildAssetor(page, first_uri)
43 linker = PageLinkerData(page.source, page.rel_path) 33 linker = PageLinkerData(page.source, page.rel_path)
44 data = { 34 data = {
45 'piecrust': pc_data, 35 'piecrust': pc_data,
46 'page': config_data, 36 'page': config_data,
47 'assets': assetor, 37 'assets': assetor,
48 'pagination': paginator, 38 'pagination': paginator,
49 'family': linker 39 'family': linker
50 } 40 }
51 41
52 for route in app.routes: 42 for route in app.routes:
53 name = route.func_name 43 name = route.func_name
54 if not name: 44 if not name:
55 continue 45 continue
56 46
57 func = data.get(name) 47 func = data.get(name)
58 if func is None: 48 if func is None:
59 func = CompositeRouteFunction() 49 data[name] = RouteFunction(route)
60 func.addFunc(route)
61 data[name] = func
62 elif isinstance(func, CompositeRouteFunction):
63 func.addFunc(route)
64 else: 50 else:
65 raise Exception("Route function '%s' collides with an " 51 raise Exception("Route function '%s' collides with an "
66 "existing function or template data." % 52 "existing function or template data." %
67 name) 53 name)
68 54
69 #TODO: handle slugified taxonomy terms. 55 # TODO: handle slugified taxonomy terms.
70 56
71 site_data = app.config.getAll() 57 site_data = app.config.getAll()
72 providers_data = DataProvidersData(page) 58 providers_data = DataProvidersData(page)
73 data = MergedMapping([data, providers_data, site_data]) 59 data = MergedMapping([data, providers_data, site_data])
74 60
79 pc_data.enableDebugInfo(page) 65 pc_data.enableDebugInfo(page)
80 66
81 return data 67 return data
82 68
83 69
84 def build_layout_data(page, page_data, contents): 70 def add_layout_data(page_data, contents):
85 for name, txt in contents.items(): 71 for name, txt in contents.items():
86 if name in page_data: 72 if name in page_data:
87 logger.warning("Content segment '%s' will hide existing data." % 73 logger.warning("Content segment '%s' will hide existing data." %
88 name) 74 name)
89 page_data._prependMapping(contents) 75 page_data._prependMapping(contents)