comparison piecrust/appconfig.py @ 585:25df894f9ab9

internal: Some fixes to the new app configuration. * Tweak order of source registration. * Add some missing default settings. * Fix some validation code. * Add better error handling to validation.
author Ludovic Chabant <ludovic@chabant.com>
date Sat, 02 Jan 2016 16:39:26 -0800
parents 9ccc933ac2c7
children 3ceeca7bb71c
comparison
equal deleted inserted replaced
584:9ccc933ac2c7 585:25df894f9ab9
76 logger.debug("Outdated cache key '%s' (expected '%s')." % ( 76 logger.debug("Outdated cache key '%s' (expected '%s')." % (
77 actual_cache_key, cache_key)) 77 actual_cache_key, cache_key))
78 78
79 logger.debug("Loading configuration from: %s" % self.paths) 79 logger.debug("Loading configuration from: %s" % self.paths)
80 values = {} 80 values = {}
81 for i, p in enumerate(self.paths): 81 try:
82 with open(p, 'r', encoding='utf-8') as fp: 82 for i, p in enumerate(self.paths):
83 loaded_values = yaml.load( 83 with open(p, 'r', encoding='utf-8') as fp:
84 fp.read(), 84 loaded_values = yaml.load(
85 Loader=ConfigurationLoader) 85 fp.read(),
86 if loaded_values is None: 86 Loader=ConfigurationLoader)
87 loaded_values = {} 87 if loaded_values is None:
88 loaded_values = {}
89 for fixup in self.fixups:
90 fixup(i, loaded_values)
91 merge_dicts(values, loaded_values)
92
88 for fixup in self.fixups: 93 for fixup in self.fixups:
89 fixup(i, loaded_values) 94 fixup(len(self.paths), values)
90 merge_dicts(values, loaded_values) 95
91 96 self._values = self._validateAll(values)
92 for fixup in self.fixups: 97 except Exception as ex:
93 fixup(len(self.paths), values) 98 raise Exception("Error loading configuration from: %s" %
94 99 ', '.join(self.paths)) from ex
95 self._values = self._validateAll(values)
96 100
97 logger.debug("Caching configuration...") 101 logger.debug("Caching configuration...")
98 self._values['__cache_key'] = cache_key 102 self._values['__cache_key'] = cache_key
99 config_text = json.dumps(self._values) 103 config_text = json.dumps(self._values)
100 self.cache.write('config.json', config_text) 104 self.cache.write('config.json', config_text)
127 131
128 def _visitor(path, val, parent_val, parent_key): 132 def _visitor(path, val, parent_val, parent_key):
129 callback_name = '_validate_' + path.replace('/', '_') 133 callback_name = '_validate_' + path.replace('/', '_')
130 callback = globs.get(callback_name) 134 callback = globs.get(callback_name)
131 if callback: 135 if callback:
132 val2 = callback(val, values, cache_writer) 136 try:
137 val2 = callback(val, values, cache_writer)
138 except Exception as ex:
139 raise Exception("Error raised in validator '%s'." %
140 callback_name) from ex
133 if val2 is None: 141 if val2 is None:
134 raise Exception("Validator '%s' isn't returning a " 142 raise Exception("Validator '%s' isn't returning a "
135 "coerced value." % callback_name) 143 "coerced value." % callback_name)
136 parent_val[parent_key] = val2 144 parent_val[parent_key] = val2
137 145
140 return values 148 return values
141 149
142 def _generateDefaultContentModel(self, values): 150 def _generateDefaultContentModel(self, values):
143 dcmcopy = copy.deepcopy(default_content_model_base) 151 dcmcopy = copy.deepcopy(default_content_model_base)
144 values = merge_dicts(dcmcopy, values) 152 values = merge_dicts(dcmcopy, values)
145
146 dcm = get_default_content_model(values)
147 values = merge_dicts(dcm, values)
148 153
149 blogsc = values['site'].get('blogs') 154 blogsc = values['site'].get('blogs')
150 if blogsc is None: 155 if blogsc is None:
151 blogsc = ['posts'] 156 blogsc = ['posts']
152 values['site']['blogs'] = blogsc 157 values['site']['blogs'] = blogsc
154 is_only_blog = (len(blogsc) == 1) 159 is_only_blog = (len(blogsc) == 1)
155 for blog_name in blogsc: 160 for blog_name in blogsc:
156 blog_cfg = get_default_content_model_for_blog( 161 blog_cfg = get_default_content_model_for_blog(
157 blog_name, is_only_blog, values) 162 blog_name, is_only_blog, values)
158 values = merge_dicts(blog_cfg, values) 163 values = merge_dicts(blog_cfg, values)
164
165 dcm = get_default_content_model(values)
166 values = merge_dicts(dcm, values)
159 167
160 return values 168 return values
161 169
162 170
163 class _ConfigCacheWriter(object): 171 class _ConfigCacheWriter(object):
182 'auto_formats': collections.OrderedDict([ 190 'auto_formats': collections.OrderedDict([
183 ('html', ''), 191 ('html', ''),
184 ('md', 'markdown'), 192 ('md', 'markdown'),
185 ('textile', 'textile')]), 193 ('textile', 'textile')]),
186 'default_auto_format': 'md', 194 'default_auto_format': 'md',
195 'default_pagination_source': None,
187 'pagination_suffix': '/%num%', 196 'pagination_suffix': '/%num%',
188 'slugify_mode': 'encode', 197 'slugify_mode': 'encode',
189 'themes_sources': [DEFAULT_THEME_SOURCE], 198 'themes_sources': [DEFAULT_THEME_SOURCE],
190 'cache_time': 28800, 199 'cache_time': 28800,
191 'enable_debug_info': True, 200 'enable_debug_info': True,
192 'show_debug_info': False, 201 'show_debug_info': False,
193 'use_default_content': True 202 'use_default_content': True
194 }), 203 }),
195 'baker': collections.OrderedDict({ 204 'baker': collections.OrderedDict({
196 'no_bake_setting': 'draft' 205 'no_bake_setting': 'draft',
206 'workers': None,
207 'batch_size': None
197 }) 208 })
198 }) 209 })
199 210
200 211
201 default_content_model_base = collections.OrderedDict({ 212 default_content_model_base = collections.OrderedDict({
424 'source': 'theme_pages', 435 'source': 'theme_pages',
425 'func': 'pcurl(slug)'}) 436 'func': 'pcurl(slug)'})
426 437
427 # Sources have the `default` scanner by default, duh. Also, a bunch 438 # Sources have the `default` scanner by default, duh. Also, a bunch
428 # of other default values for other configuration stuff. 439 # of other default values for other configuration stuff.
440 reserved_endpoints = set(['piecrust', 'site', 'page', 'route',
441 'assets', 'pagination', 'siblings',
442 'family'])
429 for sn, sc in v.items(): 443 for sn, sc in v.items():
430 if not isinstance(sc, dict): 444 if not isinstance(sc, dict):
431 raise ConfigurationError("All sources in 'site/sources' must " 445 raise ConfigurationError("All sources in 'site/sources' must "
432 "be dictionaries.") 446 "be dictionaries.")
433 sc.setdefault('type', 'default') 447 sc.setdefault('type', 'default')
437 sc.setdefault('data_type', 'iterator') 451 sc.setdefault('data_type', 'iterator')
438 sc.setdefault('item_name', sn) 452 sc.setdefault('item_name', sn)
439 sc.setdefault('items_per_page', 5) 453 sc.setdefault('items_per_page', 5)
440 sc.setdefault('date_format', DEFAULT_DATE_FORMAT) 454 sc.setdefault('date_format', DEFAULT_DATE_FORMAT)
441 sc.setdefault('realm', REALM_USER) 455 sc.setdefault('realm', REALM_USER)
456
457 # Validate endpoints.
458 endpoint = sc['data_endpoint']
459 if endpoint in reserved_endpoints:
460 raise ConfigurationError(
461 "Source '%s' is using a reserved endpoint name: %s" %
462 (sn, endpoint))
442 463
443 return v 464 return v
444 465
445 466
446 def _validate_site_routes(v, values, cache): 467 def _validate_site_routes(v, values, cache):
477 for tn, tc in v.items(): 498 for tn, tc in v.items():
478 tc.setdefault('multiple', False) 499 tc.setdefault('multiple', False)
479 tc.setdefault('term', tn) 500 tc.setdefault('term', tn)
480 tc.setdefault('page', '_%s.%%ext%%' % tc['term']) 501 tc.setdefault('page', '_%s.%%ext%%' % tc['term'])
481 502
482 # Validate endpoints, and make sure the theme has a default source.
483 reserved_endpoints = set(['piecrust', 'site', 'page', 'route',
484 'assets', 'pagination', 'siblings',
485 'family'])
486 for name, src in values['site']['sources'].items():
487 endpoint = src['data_endpoint']
488 if endpoint in reserved_endpoints:
489 raise ConfigurationError(
490 "Source '%s' is using a reserved endpoint name: %s" %
491 (name, endpoint))
492
493 return v 503 return v
494 504
495 505
496 def _validate_site_plugins(v, values, cache): 506 def _validate_site_plugins(v, values, cache):
497 if isinstance(v, str): 507 if isinstance(v, str):