Commit d905d1cb by Tom Christie

Fix yaml rendering

parent 5c7f3e23
...@@ -18,7 +18,7 @@ from rest_framework.utils import encoders ...@@ -18,7 +18,7 @@ from rest_framework.utils import encoders
from rest_framework.utils.breadcrumbs import get_breadcrumbs from rest_framework.utils.breadcrumbs import get_breadcrumbs
from rest_framework.utils.mediatypes import get_media_type_params from rest_framework.utils.mediatypes import get_media_type_params
from rest_framework import VERSION from rest_framework import VERSION
from rest_framework import serializers from rest_framework import serializers, parsers
class BaseRenderer(object): class BaseRenderer(object):
...@@ -125,6 +125,7 @@ class YAMLRenderer(BaseRenderer): ...@@ -125,6 +125,7 @@ class YAMLRenderer(BaseRenderer):
media_type = 'application/yaml' media_type = 'application/yaml'
format = 'yaml' format = 'yaml'
encoder = encoders.SafeDumper
def render(self, data, accepted_media_type=None, renderer_context=None): def render(self, data, accepted_media_type=None, renderer_context=None):
""" """
...@@ -133,7 +134,7 @@ class YAMLRenderer(BaseRenderer): ...@@ -133,7 +134,7 @@ class YAMLRenderer(BaseRenderer):
if data is None: if data is None:
return '' return ''
return yaml.safe_dump(data) return yaml.dump(data, stream=None, Dumper=self.encoder)
class HTMLRenderer(BaseRenderer): class HTMLRenderer(BaseRenderer):
...@@ -240,7 +241,8 @@ class BrowsableAPIRenderer(BaseRenderer): ...@@ -240,7 +241,8 @@ class BrowsableAPIRenderer(BaseRenderer):
if method == 'DELETE' or method == 'OPTIONS': if method == 'DELETE' or method == 'OPTIONS':
return True # Don't actually need to return a form return True # Don't actually need to return a form
if not getattr(view, 'get_serializer', None): if (not getattr(view, 'get_serializer', None) or
not parsers.FormParser in getattr(view, 'parser_classes')):
media_types = [parser.media_type for parser in view.parser_classes] media_types = [parser.media_type for parser in view.parser_classes]
return self.get_generic_content_form(media_types) return self.get_generic_content_form(media_types)
......
...@@ -3,8 +3,11 @@ Helper classes for parsers. ...@@ -3,8 +3,11 @@ Helper classes for parsers.
""" """
import datetime import datetime
import decimal import decimal
import types
from django.utils import simplejson as json from django.utils import simplejson as json
from django.utils.datastructures import SortedDict
from rest_framework.compat import timezone from rest_framework.compat import timezone
from rest_framework.serializers import DictWithMetadata, SortedDictWithMetadata
class JSONEncoder(json.JSONEncoder): class JSONEncoder(json.JSONEncoder):
...@@ -36,3 +39,53 @@ class JSONEncoder(json.JSONEncoder): ...@@ -36,3 +39,53 @@ class JSONEncoder(json.JSONEncoder):
elif hasattr(o, '__iter__'): elif hasattr(o, '__iter__'):
return [i for i in o] return [i for i in o]
return super(JSONEncoder, self).default(o) return super(JSONEncoder, self).default(o)
try:
import yaml
except ImportError:
SafeDumper = None
else:
# Adapted from http://pyyaml.org/attachment/ticket/161/use_ordered_dict.py
class SafeDumper(yaml.SafeDumper):
"""
Handles decimals as strings.
Handles SortedDicts as usual dicts, but preserves field order, rather
than the usual behaviour of sorting the keys.
"""
def represent_decimal(self, data):
return self.represent_scalar('tag:yaml.org,2002:str', str(data))
def represent_mapping(self, tag, mapping, flow_style=None):
value = []
node = yaml.MappingNode(tag, value, flow_style=flow_style)
if self.alias_key is not None:
self.represented_objects[self.alias_key] = node
best_style = True
if hasattr(mapping, 'items'):
mapping = list(mapping.items())
if not isinstance(mapping, SortedDict):
mapping.sort()
for item_key, item_value in mapping:
node_key = self.represent_data(item_key)
node_value = self.represent_data(item_value)
if not (isinstance(node_key, yaml.ScalarNode) and not node_key.style):
best_style = False
if not (isinstance(node_value, yaml.ScalarNode) and not node_value.style):
best_style = False
value.append((node_key, node_value))
if flow_style is None:
if self.default_flow_style is not None:
node.flow_style = self.default_flow_style
else:
node.flow_style = best_style
return node
SafeDumper.add_representer(SortedDict,
yaml.representer.SafeRepresenter.represent_dict)
SafeDumper.add_representer(DictWithMetadata,
yaml.representer.SafeRepresenter.represent_dict)
SafeDumper.add_representer(SortedDictWithMetadata,
yaml.representer.SafeRepresenter.represent_dict)
SafeDumper.add_representer(types.GeneratorType,
yaml.representer.SafeRepresenter.represent_list)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment