# HG changeset patch # User Ludovic Chabant # Date 1457336981 28800 # Node ID 3df808b133f866ee1271ceb7778ed059c560b090 # Parent f987b29d6fabe2ca0e97e9710e935156c2e3bcdf internal: Improve how theme configuration is validated and merged. * Add default theme config up-front so it benefits from the usual validation. * Add an explicit `use_default_theme_content` setting. * Add/fix unit tests. diff -r f987b29d6fab -r 3df808b133f8 piecrust/app.py --- a/piecrust/app.py Sun Mar 06 23:48:01 2016 -0800 +++ b/piecrust/app.py Sun Mar 06 23:49:41 2016 -0800 @@ -12,7 +12,7 @@ from piecrust.cache import ExtensibleCache, NullExtensibleCache from piecrust.plugins.base import PluginLoader from piecrust.environment import StandardEnvironment -from piecrust.configuration import ConfigurationError +from piecrust.configuration import ConfigurationError, merge_dicts from piecrust.routing import Route from piecrust.sources.base import REALM_THEME from piecrust.taxonomies import Taxonomy @@ -66,23 +66,10 @@ paths.append(preview_path) config_cache = self.cache.getCache('app') - config = PieCrustConfiguration(paths, config_cache, - theme_config=self.theme_site) - if self.theme_dir: - # We'll need to flag all page sources as coming from - # the theme. - def _fixupThemeSources(index, config): - if index != 0: - return - sitec = config.get('site') - if sitec is None: - sitec = {} - config['site'] = sitec - srcc = sitec.get('sources') - if srcc is not None: - for sn, sc in srcc.items(): - sc['realm'] = REALM_THEME - config.addFixup(_fixupThemeSources) + config = PieCrustConfiguration( + paths, config_cache, theme_config=self.theme_site) + if not self.theme_site and self.theme_dir: + config.addFixup(_fixup_theme_config) self.env.stepTimer('SiteConfigLoad', time.perf_counter() - start_time) return config @@ -216,6 +203,51 @@ return dirs +def _fixup_theme_config(index, config): + if index != 0: + # We only want to affect the theme config, which is first. + return + + # See if we want to generate the default theme content model. + sitec = config.setdefault('site', {}) + gen_default_model = sitec.setdefault('use_default_theme_content', True) + if gen_default_model: + # Create a default `theme_pages` source. + srcc = sitec.setdefault('sources', {}) + if not isinstance(srcc, dict): + raise Exception("Theme configuration has invalid `site/sources`. " + "Must be a dictionary.") + default_theme_sources = { + 'theme_pages': { + 'type': 'default', + 'ignore_missing_dir': True, + 'fs_endpoint': 'pages', + 'data_endpoint': 'site.pages', + 'default_layout': 'default', + 'item_name': 'page' + } + } + sitec['sources'] = merge_dicts(default_theme_sources, srcc) + + sitec.setdefault('theme_tag_page', 'theme_pages:_tag.%ext%') + sitec.setdefault('theme_category_page', 'theme_pages:_category.%ext%') + + # Create a default route for `theme_pages`. + rtc = sitec.setdefault('routes', []) + if not isinstance(rtc, list): + raise Exception("Theme configuration has invalid `site/routes`. " + "Must be a list.") + rtc.append({ + 'url': '/%path:slug%', + 'source': 'theme_pages', + 'func': 'pcurl(slug)'}) + + # Make all sources belong to the "theme" realm. + srcc = sitec.get('sources') + if srcc and isinstance(srcc, dict): + for sn, sc in srcc.items(): + sc['realm'] = REALM_THEME + def apply_variant_and_values(app, config_variant=None, config_values=None): if config_variant is not None: diff -r f987b29d6fab -r 3df808b133f8 piecrust/appconfig.py --- a/piecrust/appconfig.py Sun Mar 06 23:48:01 2016 -0800 +++ b/piecrust/appconfig.py Sun Mar 06 23:49:41 2016 -0800 @@ -170,11 +170,8 @@ # Figure out if we need to generate the configuration for the # default content model. sitec = values.setdefault('site', {}) - if ( - ('sources' not in sitec and - 'routes' not in sitec and - 'taxonomies' not in sitec) or - sitec.get('use_default_content')): + gen_default_model = bool(sitec.get('use_default_content')) + if gen_default_model: logger.debug("Generating default content model...") values = self._generateDefaultContentModel(values) @@ -269,7 +266,6 @@ default_content_model_base = collections.OrderedDict({ 'site': collections.OrderedDict({ 'posts_fs': DEFAULT_POSTS_FS, - 'date_format': DEFAULT_DATE_FORMAT, 'default_page_layout': 'default', 'default_post_layout': 'post', 'post_url': '%year%/%month%/%day%/%slug%', @@ -324,6 +320,12 @@ fs_endpoint = 'posts' data_endpoint = 'blog' item_name = 'post' + + if theme_site: + # If this is a theme site, show posts from a `sample` directory + # so it's clearer that those won't show up when the theme is + # actually applied to a normal site. + fs_endpoint = 'sample/posts' else: url_prefix = blog_name + '/' tax_page_prefix = blog_name + '/' @@ -351,8 +353,12 @@ tags_taxonomy = 'pages:%s_tag.%%ext%%' % tax_page_prefix category_taxonomy = 'pages:%s_category.%%ext%%' % tax_page_prefix if not theme_site: - tags_taxonomy += ';theme_pages:_tag.%ext%' - category_taxonomy += ';theme_pages:_category.%ext%' + theme_tag_page = values['site'].get('theme_tag_page') + if theme_tag_page: + tags_taxonomy += ';' + theme_tag_page + theme_category_page = values['site'].get('theme_category_page') + if theme_category_page: + category_taxonomy += ';' + theme_category_page return collections.OrderedDict({ 'site': collections.OrderedDict({ @@ -476,28 +482,6 @@ raise ConfigurationError("The 'site/sources' setting must be a " "dictionary.") - theme_site = values['site']['theme_site'] - if not theme_site: - # Add the theme page source if no sources were defined in the theme - # configuration itself. - has_any_theme_source = False - for sn, sc in v.items(): - if sc.get('realm') == REALM_THEME: - has_any_theme_source = True - break - if not has_any_theme_source: - v['theme_pages'] = { - 'theme_source': True, - 'fs_endpoint': 'pages', - 'ignore_missing_dir': True, - 'data_endpoint': 'site/pages', - 'item_name': 'page', - 'realm': REALM_THEME} - values['site']['routes'].append({ - 'url': '/%path:slug%', - 'source': 'theme_pages', - 'func': 'pcurl(slug)'}) - # Sources have the `default` scanner by default, duh. Also, a bunch # of other default values for other configuration stuff. reserved_endpoints = set(['piecrust', 'site', 'page', 'route', diff -r f987b29d6fab -r 3df808b133f8 tests/bakes/test_theme.yaml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/bakes/test_theme.yaml Sun Mar 06 23:49:41 2016 -0800 @@ -0,0 +1,32 @@ +--- +config: + site: + title: "Some Test" + default_page_layout: 'none' + foo: bar +in: + pages/foo.md: "This is: {{foo}}, with no template" + theme/theme_config.yml: "name: testtheme" + theme/pages/_index.md: "This is {{site.title}} by {{name}}, with theme template" + theme/templates/default.html: "THEME: {{content}}" +out: + index.html: "THEME: This is Some Test by testtheme, with theme template" + foo.html: "This is: bar, with no template" +--- +config: + site: + default_page_layout: 'custom' +in: + pages/foo.md: "FOO" + pages/bar.md: "---\nlayout: blah\n---\nBAR" + templates/custom.html: "CUSTOM: {{content}}" + theme/theme_config.yml: "site: {sources: {theme_pages: {default_layout: blah}}}" + theme/pages/_index.md: "theme index" + theme/pages/about.md: "about" + theme/templates/blah.html: "THEME: {{content}}" +out: + index.html: "THEME: theme index" + about.html: "THEME: about" + foo.html: "CUSTOM: FOO" + bar.html: "THEME: BAR" + diff -r f987b29d6fab -r 3df808b133f8 tests/bakes/test_theme_site.yaml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/bakes/test_theme_site.yaml Sun Mar 06 23:49:41 2016 -0800 @@ -0,0 +1,18 @@ +--- +theme_config: + site: + title: "Some Test Theme" +in: + pages/foo.md: "This is: {{site.title}}" +outfiles: + foo.html: "This is: Some Test Theme" +--- +theme_config: + site: + title: "Some Test Theme" +in: + pages/foo.md: "This is: {{foo}}" + configs/theme_preview.yml: "foo: bar" +outfiles: + foo.html: "This is: bar" + diff -r f987b29d6fab -r 3df808b133f8 tests/servings/test_theme.yaml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/servings/test_theme.yaml Sun Mar 06 23:49:41 2016 -0800 @@ -0,0 +1,21 @@ +--- +url: / +config: + site: + title: "Some Test" +in: + theme/theme_config.yml: "name: testtheme" + theme/pages/_index.md: "This is {{site.title}} by {{name}}" + theme/templates/default.html: "THEME: {{content}}" +out: "THEME: This is Some Test by testtheme" +--- +url: /foo.html +config: + site: + title: "Some Test" + foo: bar +in: + pages/foo.md: "This is: {{foo}} by {{name}}" + theme/theme_config.yml: "name: testtheme" +out: "This is: bar by testtheme" + diff -r f987b29d6fab -r 3df808b133f8 tests/servings/test_theme_site.yaml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/servings/test_theme_site.yaml Sun Mar 06 23:49:41 2016 -0800 @@ -0,0 +1,18 @@ +--- +url: /foo.html +theme_config: + site: + title: "Some Test Theme" +in: + pages/foo.md: "This is: {{site.title}}" +out: "This is: Some Test Theme" +--- +url: /foo.html +theme_config: + site: + title: "Some Test Theme" +in: + pages/foo.md: "This is: {{foo}}" + configs/theme_preview.yml: "foo: bar" +out: "This is: bar" + diff -r f987b29d6fab -r 3df808b133f8 tests/test_appconfig.py --- a/tests/test_appconfig.py Sun Mar 06 23:48:01 2016 -0800 +++ b/tests/test_appconfig.py Sun Mar 06 23:49:41 2016 -0800 @@ -5,13 +5,13 @@ values = {} config = PieCrustConfiguration(values=values) assert config.get('site/root') == '/' - assert len(config.get('site/sources')) == 3 # pages, posts, theme_pages + assert len(config.get('site/sources')) == 2 # pages, posts def test_config_default2(): config = PieCrustConfiguration() assert config.get('site/root') == '/' - assert len(config.get('site/sources')) == 3 # pages, posts, theme_pages + assert len(config.get('site/sources')) == 2 # pages, posts def test_config_site_override_title(): @@ -29,7 +29,7 @@ config = PieCrustConfiguration(values=values) # The order of routes is important. Sources, not so much. assert list(map(lambda v: v['source'], config.get('site/routes'))) == [ - 'notes', 'posts', 'posts', 'posts', 'pages', 'theme_pages'] + 'notes', 'posts', 'posts', 'posts', 'pages'] assert list(config.get('site/sources').keys()) == [ - 'pages', 'posts', 'notes', 'theme_pages'] + 'pages', 'posts', 'notes']