Mercurial > piecrust2
changeset 67:563ce5dd02af
I don't care what the YAML spec says, ordered maps are the only sane way.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Fri, 29 Aug 2014 16:42:15 -0700 |
parents | e4a24512b814 |
children | d9e494df2a99 cb1ed436642c |
files | piecrust/app.py piecrust/configuration.py piecrust/environment.py piecrust/page.py tests/test_configuration.py |
diffstat | 5 files changed, 55 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/piecrust/app.py Fri Aug 29 16:41:16 2014 -0700 +++ b/piecrust/app.py Fri Aug 29 16:42:15 2014 -0700 @@ -4,6 +4,7 @@ import codecs import hashlib import logging +import collections import yaml from werkzeug.utils import cached_property from piecrust import (APP_VERSION, @@ -15,7 +16,8 @@ from piecrust.cache import ExtensibleCache, NullCache, NullExtensibleCache from piecrust.plugins.base import PluginLoader from piecrust.environment import StandardEnvironment -from piecrust.configuration import Configuration, ConfigurationError, merge_dicts +from piecrust.configuration import (Configuration, ConfigurationError, + OrderedDictYAMLLoader, merge_dicts) from piecrust.routing import Route from piecrust.sources.base import REALM_USER, REALM_THEME from piecrust.taxonomies import Taxonomy @@ -64,7 +66,8 @@ if self.cache.isValid('config.json', path_times): logger.debug("Loading configuration from cache...") config_text = self.cache.read('config.json') - self._values = json.loads(config_text) + self._values = json.loads(config_text, + object_pairs_hook=collections.OrderedDict) actual_cache_key = self._values.get('__cache_key') if actual_cache_key == cache_key: @@ -77,7 +80,8 @@ logger.debug("Loading configuration from: %s" % self.paths) for i, p in enumerate(self.paths): with codecs.open(p, 'r', 'utf-8') as fp: - loaded_values = yaml.load(fp.read()) + loaded_values = yaml.load(fp.read(), + Loader=OrderedDictYAMLLoader) if loaded_values is None: loaded_values = {} for fixup in self.fixups:
--- a/piecrust/configuration.py Fri Aug 29 16:41:16 2014 -0700 +++ b/piecrust/configuration.py Fri Aug 29 16:42:15 2014 -0700 @@ -1,6 +1,8 @@ import re import logging +import collections import yaml +from yaml.constructor import ConstructorError logger = logging.getLogger(__name__) @@ -114,10 +116,29 @@ m = header_regex.match(text) if m is not None: header = str(m.group('header')) - config = yaml.load(header, Loader=yaml.BaseLoader) + config = yaml.load(header, Loader=OrderedDictYAMLLoader) offset = m.end() else: config = {} offset = 0 return config, offset + +class OrderedDictYAMLLoader(yaml.BaseLoader): + """ A YAML loader that loads mappings into ordered dictionaries. + """ + def construct_mapping(self, node, deep=False): + if not isinstance(node, yaml.MappingNode): + raise ConstructorError(None, None, + "expected a mapping node, but found %s" % node.id, + node.start_mark) + mapping = collections.OrderedDict() + for key_node, value_node in node.value: + key = self.construct_object(key_node, deep=deep) + if not isinstance(key, collections.Hashable): + raise ConstructorError("while constructing a mapping", node.start_mark, + "found unhashable key", key_node.start_mark) + value = self.construct_object(value_node, deep=deep) + mapping[key] = value + return mapping +
--- a/piecrust/environment.py Fri Aug 29 16:41:16 2014 -0700 +++ b/piecrust/environment.py Fri Aug 29 16:42:15 2014 -0700 @@ -3,6 +3,7 @@ import json import logging import threading +import collections import repoze.lru @@ -40,7 +41,8 @@ logger.debug("'%s' found in file-system cache." % key) item_raw = self.fs_cache.read(fs_key) - item = json.loads(item_raw) + item = json.loads(item_raw, + object_pairs_hook=collections.OrderedDict) self.cache.put(key, item) return item
--- a/piecrust/page.py Fri Aug 29 16:41:16 2014 -0700 +++ b/piecrust/page.py Fri Aug 29 16:42:15 2014 -0700 @@ -7,6 +7,7 @@ import logging import datetime import dateutil.parser +import collections from werkzeug.utils import cached_property from piecrust.configuration import (Configuration, ConfigurationError, parse_config_header) @@ -184,7 +185,8 @@ page_time = path_mtime or os.path.getmtime(path) if cache.isValid(cache_path, page_time): exec_info.was_cache_valid = True - cache_data = json.loads(cache.read(cache_path)) + cache_data = json.loads(cache.read(cache_path), + object_pairs_hook=collections.OrderedDict) config = PageConfiguration(values=cache_data['config'], validate=False) content = json_load_segments(cache_data['content'])
--- a/tests/test_configuration.py Fri Aug 29 16:41:16 2014 -0700 +++ b/tests/test_configuration.py Fri Aug 29 16:42:15 2014 -0700 @@ -1,6 +1,9 @@ import copy +import yaml import pytest -from piecrust.configuration import Configuration, merge_dicts +from collections import OrderedDict +from piecrust.configuration import (Configuration, OrderedDictYAMLLoader, + merge_dicts) @pytest.mark.parametrize('values, expected', [ @@ -103,3 +106,19 @@ } assert config.get() == expected + +def test_ordered_loader(): + sample = """ +one: + two: fish + red: fish + blue: fish +two: + a: yes + b: no + c: null +""" + data = yaml.load(sample, Loader=OrderedDictYAMLLoader) + assert type(data) is OrderedDict + assert list(data['one'].keys()) == ['two', 'red', 'blue'] +