Mercurial > piecrust2
comparison piecrust/configuration.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 | fd694f1297c7 |
children | f070a4fc033c |
comparison
equal
deleted
inserted
replaced
851:2c7e57d80bba | 852:4850f8c21b6e |
---|---|
71 other_values = other | 71 other_values = other |
72 elif isinstance(other, Configuration): | 72 elif isinstance(other, Configuration): |
73 other_values = other._values | 73 other_values = other._values |
74 else: | 74 else: |
75 raise Exception( | 75 raise Exception( |
76 "Unsupported value type to merge: %s" % type(other)) | 76 "Unsupported value type to merge: %s" % type(other)) |
77 | 77 |
78 merge_dicts(self._values, other_values, | 78 merge_dicts(self._values, other_values, |
79 validator=self._validateValue) | 79 validator=self._validateValue) |
80 | 80 |
81 def validateTypes(self, allowed_types=default_allowed_types): | 81 def validateTypes(self, allowed_types=default_allowed_types): |
94 def _validateTypeRecursive(self, v, allowed_types): | 94 def _validateTypeRecursive(self, v, allowed_types): |
95 if v is None: | 95 if v is None: |
96 return | 96 return |
97 if not isinstance(v, allowed_types): | 97 if not isinstance(v, allowed_types): |
98 raise ConfigurationError( | 98 raise ConfigurationError( |
99 "Value '%s' is of forbidden type: %s" % (v, type(v))) | 99 "Value '%s' is of forbidden type: %s" % (v, type(v))) |
100 if isinstance(v, dict): | 100 if isinstance(v, dict): |
101 self._validateDictTypesRecursive(v, allowed_types) | 101 self._validateDictTypesRecursive(v, allowed_types) |
102 elif isinstance(v, list): | 102 elif isinstance(v, list): |
103 self._validateListTypesRecursive(v, allowed_types) | 103 self._validateListTypesRecursive(v, allowed_types) |
104 | 104 |
221 if isinstance(v, dict): | 221 if isinstance(v, dict): |
222 _recurse_visit_dict(v, key_path, visitor) | 222 _recurse_visit_dict(v, key_path, visitor) |
223 | 223 |
224 | 224 |
225 header_regex = re.compile( | 225 header_regex = re.compile( |
226 r'(---\s*\n)(?P<header>(.*\n)*?)^(---\s*\n)', re.MULTILINE) | 226 r'(---\s*\n)(?P<header>(.*\n)*?)^(---\s*\n)', re.MULTILINE) |
227 | 227 |
228 | 228 |
229 def parse_config_header(text): | 229 def parse_config_header(text): |
230 m = header_regex.match(text) | 230 m = header_regex.match(text) |
231 if m is not None: | 231 if m is not None: |
237 offset = 0 | 237 offset = 0 |
238 return config, offset | 238 return config, offset |
239 | 239 |
240 | 240 |
241 class ConfigurationLoader(SafeLoader): | 241 class ConfigurationLoader(SafeLoader): |
242 """ A YAML loader that loads mappings into ordered dictionaries. | 242 """ A YAML loader that loads mappings into ordered dictionaries, |
243 and supports sexagesimal notations for timestamps. | |
243 """ | 244 """ |
244 def __init__(self, *args, **kwargs): | 245 def __init__(self, *args, **kwargs): |
245 super(ConfigurationLoader, self).__init__(*args, **kwargs) | 246 super(ConfigurationLoader, self).__init__(*args, **kwargs) |
246 | 247 |
247 self.add_constructor('tag:yaml.org,2002:map', | 248 self.add_constructor('tag:yaml.org,2002:map', |
248 type(self).construct_yaml_map) | 249 type(self).construct_yaml_map) |
249 self.add_constructor('tag:yaml.org,2002:omap', | 250 self.add_constructor('tag:yaml.org,2002:omap', |
250 type(self).construct_yaml_map) | 251 type(self).construct_yaml_map) |
251 self.add_constructor('tag:yaml.org,2002:sexagesimal', | 252 self.add_constructor('tag:yaml.org,2002:sexagesimal', |
252 type(self).construct_yaml_time) | 253 type(self).construct_yaml_time) |
253 | 254 |
254 def construct_yaml_map(self, node): | 255 def construct_yaml_map(self, node): |
255 data = collections.OrderedDict() | 256 data = collections.OrderedDict() |
256 yield data | 257 yield data |
257 value = self.construct_mapping(node) | 258 value = self.construct_mapping(node) |
258 data.update(value) | 259 data.update(value) |
259 | 260 |
260 def construct_mapping(self, node, deep=False): | 261 def construct_mapping(self, node, deep=False): |
261 if not isinstance(node, yaml.MappingNode): | 262 if not isinstance(node, yaml.MappingNode): |
262 raise ConstructorError(None, None, | 263 raise ConstructorError( |
263 "expected a mapping node, but found %s" % node.id, | 264 None, None, |
264 node.start_mark) | 265 "expected a mapping node, but found %s" % node.id, |
266 node.start_mark) | |
265 mapping = collections.OrderedDict() | 267 mapping = collections.OrderedDict() |
266 for key_node, value_node in node.value: | 268 for key_node, value_node in node.value: |
267 key = self.construct_object(key_node, deep=deep) | 269 key = self.construct_object(key_node, deep=deep) |
268 if not isinstance(key, collections.Hashable): | 270 if not isinstance(key, collections.Hashable): |
269 raise ConstructorError("while constructing a mapping", node.start_mark, | 271 raise ConstructorError( |
270 "found unhashable key", key_node.start_mark) | 272 "while constructing a mapping", node.start_mark, |
273 "found unhashable key", key_node.start_mark) | |
271 value = self.construct_object(value_node, deep=deep) | 274 value = self.construct_object(value_node, deep=deep) |
272 mapping[key] = value | 275 mapping[key] = value |
273 return mapping | 276 return mapping |
274 | 277 |
275 time_regexp = re.compile( | 278 time_regexp = re.compile( |
276 r'''^(?P<hour>[0-9][0-9]?) | 279 r'''^(?P<hour>[0-9][0-9]?) |
277 :(?P<minute>[0-9][0-9]) | 280 :(?P<minute>[0-9][0-9]) |
278 (:(?P<second>[0-9][0-9]) | 281 (:(?P<second>[0-9][0-9]) |
279 (\.(?P<fraction>[0-9]+))?)?$''', re.X) | 282 (\.(?P<fraction>[0-9]+))?)?$''', re.X) |
280 | 283 |
281 def construct_yaml_time(self, node): | 284 def construct_yaml_time(self, node): |
292 usec = float('0.' + values['fraction']) | 295 usec = float('0.' + values['fraction']) |
293 return second + minute * 60 + hour * 60 * 60 + usec | 296 return second + minute * 60 + hour * 60 * 60 + usec |
294 | 297 |
295 | 298 |
296 ConfigurationLoader.add_implicit_resolver( | 299 ConfigurationLoader.add_implicit_resolver( |
297 'tag:yaml.org,2002:sexagesimal', | 300 'tag:yaml.org,2002:sexagesimal', |
298 re.compile(r'''^[0-9][0-9]?:[0-9][0-9] | 301 re.compile(r'''^[0-9][0-9]?:[0-9][0-9] |
299 (:[0-9][0-9](\.[0-9]+)?)?$''', re.X), | 302 (:[0-9][0-9](\.[0-9]+)?)?$''', re.X), |
300 list('0123456789')) | 303 list('0123456789')) |
301 | 304 |
302 | 305 |
303 # We need to add our `sexagesimal` resolver before the `int` one, which | 306 # We need to add our `sexagesimal` resolver before the `int` one, which |
304 # already supports sexagesimal notation in YAML 1.1 (but not 1.2). However, | 307 # already supports sexagesimal notation in YAML 1.1 (but not 1.2). However, |
305 # because we know we pretty much always want it for representing time, we | 308 # because we know we pretty much always want it for representing time, we |
317 # we always load maps into `OrderedDicts` anyway. | 320 # we always load maps into `OrderedDicts` anyway. |
318 return self.represent_mapping('tag:yaml.org,2002:map', data) | 321 return self.represent_mapping('tag:yaml.org,2002:map', data) |
319 | 322 |
320 | 323 |
321 ConfigurationDumper.add_representer(collections.OrderedDict, | 324 ConfigurationDumper.add_representer(collections.OrderedDict, |
322 ConfigurationDumper.represent_ordered_dict) | 325 ConfigurationDumper.represent_ordered_dict) |
323 | 326 |