1
# Python
2 3
from collections import OrderedDict
3 3
import json
4 3
import yaml
5

6
# Django
7 3
from django.conf import settings
8 3
from django.utils import six
9 3
from django.utils.translation import ugettext_lazy as _
10

11
# Django REST Framework
12 3
from rest_framework import parsers
13 3
from rest_framework.exceptions import ParseError
14

15

16 3
class OrderedDictLoader(yaml.SafeLoader):
17
    """
18
    This yaml loader is used to deal with current pyYAML (3.12) not supporting
19
    custom object pairs hook. Remove it when new version adds that support.
20
    """
21

22 3
    def construct_mapping(self, node, deep=False):
23 0
        if isinstance(node, yaml.nodes.MappingNode):
24 0
            self.flatten_mapping(node)
25
        else:
26 0
            raise yaml.constructor.ConstructorError(
27
                None, None,
28
                "expected a mapping node, but found %s" % node.id,
29
                node.start_mark
30
            )
31 0
        mapping = OrderedDict()
32 0
        for key_node, value_node in node.value:
33 0
            key = self.construct_object(key_node, deep=deep)
34 0
            try:
35 0
                hash(key)
36 0
            except TypeError as exc:
37 0
                raise yaml.constructor.ConstructorError(
38
                    "while constructing a mapping", node.start_mark,
39
                    "found unacceptable key (%s)" % exc, key_node.start_mark
40
                )
41 0
            value = self.construct_object(value_node, deep=deep)
42 0
            mapping[key] = value
43 0
        return mapping
44

45

46 3
class JSONParser(parsers.JSONParser):
47
    """
48
    Parses JSON-serialized data, preserving order of dictionary keys.
49
    """
50

51 3
    def parse(self, stream, media_type=None, parser_context=None):
52
        """
53
        Parses the incoming bytestream as JSON and returns the resulting data.
54
        """
55 3
        parser_context = parser_context or {}
56 3
        encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)
57 3
        try:
58 3
            data = stream.read().decode(encoding)
59 3
            if not data:
60 0
                return {}
61 3
            obj = json.loads(data, object_pairs_hook=OrderedDict)
62 3
            if not isinstance(obj, dict) and not isinstance(obj, list) and obj is not None:
63 0
                raise ParseError(_('JSON parse error - not a JSON object'))
64 3
            return obj
65 0
        except ValueError as exc:
66 0
            raise ParseError(_('JSON parse error - %s\nPossible cause: trailing comma.' % six.text_type(exc)))

Read our documentation on viewing source code .

Loading