diff --git a/README.md b/README.md index 1abb17bfd..12c109069 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,5 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [docs]: http://www.django-rest-framework.org/ [urlobject]: https://github.com/zacharyvoase/urlobject [markdown]: http://pypi.python.org/pypi/Markdown/ -[pyyaml]: http://pypi.python.org/pypi/PyYAML [django-filter]: http://pypi.python.org/pypi/django-filter [security-mail]: mailto:rest-framework-security@googlegroups.com diff --git a/docs/api-guide/parsers.md b/docs/api-guide/parsers.md index 32819146e..9323d3822 100644 --- a/docs/api-guide/parsers.md +++ b/docs/api-guide/parsers.md @@ -26,26 +26,26 @@ As an example, if you are sending `json` encoded data using jQuery with the [.aj ## Setting the parsers -The default set of parsers may be set globally, using the `DEFAULT_PARSER_CLASSES` setting. For example, the following settings would allow requests with `YAML` content. +The default set of parsers may be set globally, using the `DEFAULT_PARSER_CLASSES` setting. For example, the following settings would allow requests with `JSON` content. REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': ( - 'rest_framework.parsers.YAMLParser', + 'rest_framework.parsers.JSONParser', ) } You can also set the parsers used for an individual view, or viewset, using the `APIView` class based views. - from rest_framework.parsers import YAMLParser + from rest_framework.parsers import JSONParser from rest_framework.response import Response from rest_framework.views import APIView class ExampleView(APIView): """ - A view that can accept POST requests with YAML content. + A view that can accept POST requests with JSON content. """ - parser_classes = (YAMLParser,) + parser_classes = (JSONParser,) def post(self, request, format=None): return Response({'received data': request.data}) @@ -53,10 +53,10 @@ using the `APIView` class based views. Or, if you're using the `@api_view` decorator with function based views. @api_view(['POST']) - @parser_classes((YAMLParser,)) + @parser_classes((JSONParser,)) def example_view(request, format=None): """ - A view that can accept POST requests with YAML content. + A view that can accept POST requests with JSON content. """ return Response({'received data': request.data}) @@ -70,14 +70,6 @@ Parses `JSON` request content. **.media_type**: `application/json` -## YAMLParser - -Parses `YAML` request content. - -Requires the `pyyaml` package to be installed. - -**.media_type**: `application/yaml` - ## FormParser Parses HTML form content. `request.data` will be populated with a `QueryDict` of data. diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index 1490eef61..69460dbc5 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -18,11 +18,11 @@ For more information see the documentation on [content negotiation][conneg]. ## Setting the renderers -The default set of renderers may be set globally, using the `DEFAULT_RENDERER_CLASSES` setting. For example, the following settings would use `YAML` as the main media type and also include the self describing API. +The default set of renderers may be set globally, using the `DEFAULT_RENDERER_CLASSES` setting. For example, the following settings would use `JSON` as the main media type and also include the self describing API. REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( - 'rest_framework.renderers.YAMLRenderer', + 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ) } @@ -31,15 +31,15 @@ You can also set the renderers used for an individual view, or viewset, using the `APIView` class based views. from django.contrib.auth.models import User - from rest_framework.renderers import JSONRenderer, YAMLRenderer + from rest_framework.renderers import JSONRenderer from rest_framework.response import Response from rest_framework.views import APIView class UserCountView(APIView): """ - A view that returns the count of active users, in JSON or YAML. + A view that returns the count of active users in JSON. """ - renderer_classes = (JSONRenderer, YAMLRenderer) + renderer_classes = (JSONRenderer, ) def get(self, request, format=None): user_count = User.objects.filter(active=True).count() @@ -93,38 +93,6 @@ The default JSON encoding style can be altered using the `UNICODE_JSON` and `COM **.charset**: `None` -## YAMLRenderer - -Renders the request data into `YAML`. - -Requires the `pyyaml` package to be installed. - -Note that non-ascii characters will be rendered using `\uXXXX` character escape. For example: - - unicode black star: "\u2605" - -**.media_type**: `application/yaml` - -**.format**: `'.yaml'` - -**.charset**: `utf-8` - -## UnicodeYAMLRenderer - -Renders the request data into `YAML`. - -Requires the `pyyaml` package to be installed. - -Note that non-ascii characters will not be character escaped. For example: - - unicode black star: ★ - -**.media_type**: `application/yaml` - -**.format**: `'.yaml'` - -**.charset**: `utf-8` - ## TemplateHTMLRenderer Renders data to HTML, using Django's standard template rendering. diff --git a/docs/api-guide/settings.md b/docs/api-guide/settings.md index 9005511b7..623d89fbc 100644 --- a/docs/api-guide/settings.md +++ b/docs/api-guide/settings.md @@ -12,10 +12,10 @@ For example your project's `settings.py` file might include something like this: REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( - 'rest_framework.renderers.YAMLRenderer', + 'rest_framework.renderers.JSONRenderer', ), 'DEFAULT_PARSER_CLASSES': ( - 'rest_framework.parsers.YAMLParser', + 'rest_framework.parsers.JSONParser', ) } diff --git a/docs/api-guide/testing.md b/docs/api-guide/testing.md index d059fdab5..cd8c7820a 100644 --- a/docs/api-guide/testing.md +++ b/docs/api-guide/testing.md @@ -255,14 +255,14 @@ The default format used to make test requests may be set using the `TEST_REQUEST If you need to test requests using something other than multipart or json requests, you can do so by setting the `TEST_REQUEST_RENDERER_CLASSES` setting. -For example, to add support for using `format='yaml'` in test requests, you might have something like this in your `settings.py` file. +For example, to add support for using `format='html'` in test requests, you might have something like this in your `settings.py` file. REST_FRAMEWORK = { ... 'TEST_REQUEST_RENDERER_CLASSES': ( 'rest_framework.renderers.MultiPartRenderer', 'rest_framework.renderers.JSONRenderer', - 'rest_framework.renderers.YAMLRenderer' + 'rest_framework.renderers.TemplateHTMLRenderer' ) } diff --git a/docs/index.md b/docs/index.md index ac5d5a016..136f344e6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -54,7 +54,6 @@ REST framework requires the following: The following packages are optional: * [Markdown][markdown] (2.1.0+) - Markdown support for the browsable API. -* [PyYAML][yaml] (3.10+) - YAML content-type support. * [django-filter][django-filter] (0.5.4+) - Filtering support. * [django-restframework-oauth][django-restframework-oauth] package for OAuth 1.0a and 2.0 support. * [django-guardian][django-guardian] (1.1.1+) - Object level permissions support. @@ -254,7 +253,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [mozilla]: http://www.mozilla.org/en-US/about/ [eventbrite]: https://www.eventbrite.co.uk/about/ [markdown]: http://pypi.python.org/pypi/Markdown/ -[yaml]: http://pypi.python.org/pypi/PyYAML [django-filter]: http://pypi.python.org/pypi/django-filter [django-restframework-oauth]: https://github.com/jlafon/django-rest-framework-oauth [django-guardian]: https://github.com/lukaszb/django-guardian diff --git a/docs/tutorial/2-requests-and-responses.md b/docs/tutorial/2-requests-and-responses.md index f377c7122..06a684b17 100644 --- a/docs/tutorial/2-requests-and-responses.md +++ b/docs/tutorial/2-requests-and-responses.md @@ -92,7 +92,7 @@ Here is the view for an individual snippet, in the `views.py` module. This should all feel very familiar - it is not a lot different from working with regular Django views. -Notice that we're no longer explicitly tying our requests or responses to a given content type. `request.data` can handle incoming `json` requests, but it can also handle `yaml` and other formats. Similarly we're returning response objects with data, but allowing REST framework to render the response into the correct content type for us. +Notice that we're no longer explicitly tying our requests or responses to a given content type. `request.data` can handle incoming `json` requests, but it can also handle other formats. Similarly we're returning response objects with data, but allowing REST framework to render the response into the correct content type for us. ## Adding optional format suffixes to our URLs diff --git a/requirements-test.txt b/requirements-test.txt index 2fb859da7..eae43ae20 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -6,7 +6,11 @@ flake8==2.2.2 # Optional packages markdown>=2.1.0 +<<<<<<< HEAD PyYAML>=3.10 +======= +defusedxml>=0.3 +>>>>>>> 731c8421afe3093a78cdabb9c3cc28fa52cd1c8e django-guardian==1.2.4 django-filter>=0.5.4 Pillow==2.3.0 diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 06da37701..08dd9df65 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -237,13 +237,6 @@ except ImportError: apply_markdown = None -# Yaml is optional -try: - import yaml -except ImportError: - yaml = None - - # `seperators` argument to `json.dumps()` differs between 2.x and 3.x # See: http://bugs.python.org/issue22767 if six.PY3: diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py index 6d0e932bd..1960e5a8c 100644 --- a/rest_framework/parsers.py +++ b/rest_framework/parsers.py @@ -12,7 +12,7 @@ from django.http import QueryDict from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser from django.http.multipartparser import MultiPartParserError, parse_header, ChunkIter from django.utils import six -from rest_framework.compat import yaml, force_text, urlparse +from rest_framework.compat import force_text, urlparse from rest_framework.exceptions import ParseError from rest_framework import renderers import json @@ -63,29 +63,6 @@ class JSONParser(BaseParser): raise ParseError('JSON parse error - %s' % six.text_type(exc)) -class YAMLParser(BaseParser): - """ - Parses YAML-serialized data. - """ - - media_type = 'application/yaml' - - def parse(self, stream, media_type=None, parser_context=None): - """ - Parses the incoming bytestream as YAML and returns the resulting data. - """ - assert yaml, 'YAMLParser requires pyyaml to be installed' - - parser_context = parser_context or {} - encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET) - - try: - data = stream.read().decode(encoding) - return yaml.safe_load(data) - except (ValueError, yaml.parser.ParserError) as exc: - raise ParseError('YAML parse error - %s' % six.text_type(exc)) - - class FormParser(BaseParser): """ Parser for form data. diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index e8caa40f2..173e48dc0 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -17,7 +17,7 @@ from django.template import Context, RequestContext, loader, Template from django.test.client import encode_multipart from django.utils import six from rest_framework import exceptions, serializers, status, VERSION -from rest_framework.compat import SHORT_SEPARATORS, LONG_SEPARATORS, yaml +from rest_framework.compat import SHORT_SEPARATORS, LONG_SEPARATORS from rest_framework.exceptions import ParseError from rest_framework.settings import api_settings from rest_framework.request import is_form_media_type, override_method @@ -103,29 +103,6 @@ class JSONRenderer(BaseRenderer): return ret -class YAMLRenderer(BaseRenderer): - """ - Renderer which serializes to YAML. - """ - - media_type = 'application/yaml' - format = 'yaml' - encoder = encoders.SafeDumper - charset = 'utf-8' - ensure_ascii = False - - def render(self, data, accepted_media_type=None, renderer_context=None): - """ - Renders `data` into serialized YAML. - """ - assert yaml, 'YAMLRenderer requires pyyaml to be installed' - - if data is None: - return '' - - return yaml.dump(data, stream=None, encoding=self.charset, Dumper=self.encoder, allow_unicode=not self.ensure_ascii) - - class TemplateHTMLRenderer(BaseRenderer): """ An HTML renderer for use with templates. diff --git a/rest_framework/settings.py b/rest_framework/settings.py index 1e8c27fc3..3abc1fe85 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -5,11 +5,11 @@ For example your project's `settings.py` file might look like this: REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( 'rest_framework.renderers.JSONRenderer', - 'rest_framework.renderers.YAMLRenderer', + 'rest_framework.renderers.TemplateHTMLRenderer', ) 'DEFAULT_PARSER_CLASSES': ( 'rest_framework.parsers.JSONParser', - 'rest_framework.parsers.YAMLParser', + 'rest_framework.parsers.TemplateHTMLRenderer', ) } diff --git a/rest_framework/utils/encoders.py b/rest_framework/utils/encoders.py index 4d6bb3a34..2c97f1d7a 100644 --- a/rest_framework/utils/encoders.py +++ b/rest_framework/utils/encoders.py @@ -5,10 +5,9 @@ from __future__ import unicode_literals from django.db.models.query import QuerySet from django.utils import six, timezone from django.utils.functional import Promise -from rest_framework.compat import force_text, OrderedDict +from rest_framework.compat import force_text import datetime import decimal -import types import json @@ -56,65 +55,3 @@ class JSONEncoder(json.JSONEncoder): elif hasattr(obj, '__iter__'): return tuple(item for item in obj) return super(JSONEncoder, self).default(obj) - - -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 OrderedDicts 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', six.text_type(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, OrderedDict): - 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( - decimal.Decimal, - SafeDumper.represent_decimal - ) - SafeDumper.add_representer( - OrderedDict, - yaml.representer.SafeRepresenter.represent_dict - ) - # SafeDumper.add_representer( - # DictWithMetadata, - # yaml.representer.SafeRepresenter.represent_dict - # ) - # SafeDumper.add_representer( - # OrderedDictWithMetadata, - # yaml.representer.SafeRepresenter.represent_dict - # ) - SafeDumper.add_representer( - types.GeneratorType, - yaml.representer.SafeRepresenter.represent_list - ) diff --git a/tests/test_renderers.py b/tests/test_renderers.py index eb163ea50..2c8da2dc5 100644 --- a/tests/test_renderers.py +++ b/tests/test_renderers.py @@ -9,11 +9,9 @@ from django.test import TestCase from django.utils import six from django.utils.translation import ugettext_lazy as _ from rest_framework import status, permissions -from rest_framework.compat import yaml, BytesIO from rest_framework.response import Response from rest_framework.views import APIView -from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, BrowsableAPIRenderer -from rest_framework.parsers import YAMLParser +from rest_framework.renderers import BaseRenderer, JSONRenderer, BrowsableAPIRenderer from rest_framework.settings import api_settings from rest_framework.test import APIRequestFactory from collections import MutableMapping @@ -394,55 +392,6 @@ class AsciiJSONRendererTests(TestCase): self.assertEqual(content, '{"countries":["United Kingdom","France","Espa\\u00f1a"]}'.encode('utf-8')) -if yaml: - _yaml_repr = 'foo: [bar, baz]\n' - - class YAMLRendererTests(TestCase): - """ - Tests specific to the YAML Renderer - """ - - def test_render(self): - """ - Test basic YAML rendering. - """ - obj = {'foo': ['bar', 'baz']} - renderer = YAMLRenderer() - content = renderer.render(obj, 'application/yaml') - self.assertEqual(content.decode('utf-8'), _yaml_repr) - - def test_render_and_parse(self): - """ - Test rendering and then parsing returns the original object. - IE obj -> render -> parse -> obj. - """ - obj = {'foo': ['bar', 'baz']} - - renderer = YAMLRenderer() - parser = YAMLParser() - - content = renderer.render(obj, 'application/yaml') - data = parser.parse(BytesIO(content)) - self.assertEqual(obj, data) - - def test_render_decimal(self): - """ - Test YAML decimal rendering. - """ - renderer = YAMLRenderer() - content = renderer.render({'field': Decimal('111.2')}, 'application/yaml') - self.assertYAMLContains(content.decode('utf-8'), "field: '111.2'") - - def assertYAMLContains(self, content, string): - self.assertTrue(string in content, '%r not in %r' % (string, content)) - - def test_proper_encoding(self): - obj = {'countries': ['United Kingdom', 'France', 'España']} - renderer = YAMLRenderer() - content = renderer.render(obj, 'application/yaml') - self.assertEqual(content.strip(), 'countries: [United Kingdom, France, España]'.encode('utf-8')) - - # Tests for caching issue, #346 class CacheRenderTest(TestCase): """ diff --git a/tests/test_templatetags.py b/tests/test_templatetags.py index b04a937e0..0cee91f19 100644 --- a/tests/test_templatetags.py +++ b/tests/test_templatetags.py @@ -54,7 +54,7 @@ class Issue1386Tests(TestCase): class URLizerTests(TestCase): """ - Test if both JSON and YAML URLs are transformed into links well + Test if JSON URLs are transformed into links well """ def _urlize_dict_check(self, data): """ @@ -73,14 +73,3 @@ class URLizerTests(TestCase): data['"foo_set": [\n "http://api/foos/1/"\n], '] = \ '"foo_set": [\n "http://api/foos/1/"\n], ' self._urlize_dict_check(data) - - def test_yaml_with_url(self): - """ - Test if YAML URLs are transformed into links well - """ - data = {} - data['''{users: 'http://api/users/'}'''] = \ - '''{users: 'http://api/users/'}''' - data['''foo_set: ['http://api/foos/1/']'''] = \ - '''foo_set: ['http://api/foos/1/']''' - self._urlize_dict_check(data) diff --git a/tox.ini b/tox.ini index 388eabc5d..6f1616f01 100644 --- a/tox.ini +++ b/tox.ini @@ -20,7 +20,6 @@ deps = django-filter==0.7 defusedxml==0.3 markdown>=2.1.0 - PyYAML>=3.10 [testenv:py27-flake8] deps =