diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py index 53262366a..43b33f504 100644 --- a/djangorestframework/mixins.py +++ b/djangorestframework/mixins.py @@ -233,8 +233,8 @@ class RequestMixin(object): @property def default_parser(self): - """Return the view's most preffered emitter. - (This has no behavioural effect, but is may be used by documenting emitters)""" + """Return the view's most preffered renderer. + (This has no behavioural effect, but is may be used by documenting renderers)""" return self.parsers[0] @@ -249,7 +249,7 @@ class RequestMixin(object): ########## ResponseMixin ########## class ResponseMixin(object): - """Adds behaviour for pluggable Emitters to a :class:`.Resource` or Django :class:`View`. class. + """Adds behaviour for pluggable Renderers to a :class:`.Resource` or Django :class:`View`. class. Default behaviour is to use standard HTTP Accept header content negotiation. Also supports overidding the content type by specifying an _accept= parameter in the URL. @@ -260,7 +260,7 @@ class ResponseMixin(object): #request = None #response = None - emitters = () + renderers = () #def render_to_response(self, obj): # if isinstance(obj, Response): @@ -285,21 +285,21 @@ class ResponseMixin(object): # return content - def emit(self, response): + def render(self, response): """Takes a :class:`Response` object and returns a Django :class:`HttpResponse`.""" self.response = response try: - emitter = self._determine_emitter(self.request) + renderer = self._determine_renderer(self.request) except ErrorResponse, exc: - emitter = self.default_emitter + renderer = self.default_renderer response = exc.response # Serialize the response content if response.has_content_body: - content = emitter(self).emit(output=response.cleaned_content) + content = renderer(self).render(output=response.cleaned_content) else: - content = emitter(self).emit() + content = renderer(self).render() # Munge DELETE Response code to allow us to return content # (Do this *after* we've rendered the template so that we include the normal deletion response code in the output) @@ -307,16 +307,16 @@ class ResponseMixin(object): response.status = 200 # Build the HTTP Response - # TODO: Check if emitter.mimetype is underspecified, or if a content-type header has been set - resp = HttpResponse(content, mimetype=emitter.media_type, status=response.status) + # TODO: Check if renderer.mimetype is underspecified, or if a content-type header has been set + resp = HttpResponse(content, mimetype=renderer.media_type, status=response.status) for (key, val) in response.headers.items(): resp[key] = val return resp - def _determine_emitter(self, request): - """Return the appropriate emitter for the output, given the client's 'Accept' header, + def _determine_renderer(self, request): + """Return the appropriate renderer for the output, given the client's 'Accept' header, and the content types that this Resource knows how to serve. See: RFC 2616, Section 14 - http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html""" @@ -333,7 +333,7 @@ class ResponseMixin(object): accept_list = request.META["HTTP_ACCEPT"].split(',') else: # No accept header specified - return self.default_emitter + return self.default_renderer # Parse the accept header into a dict of {qvalue: set of media types} # We ignore mietype parameters @@ -363,34 +363,34 @@ class ResponseMixin(object): for accept_set in accept_sets: # Return any exact match - for emitter in self.emitters: - if emitter.media_type in accept_set: - return emitter + for renderer in self.renderers: + if renderer.media_type in accept_set: + return renderer # Return any subtype match - for emitter in self.emitters: - if emitter.media_type.split('/')[0] + '/*' in accept_set: - return emitter + for renderer in self.renderers: + if renderer.media_type.split('/')[0] + '/*' in accept_set: + return renderer # Return default if '*/*' in accept_set: - return self.default_emitter + return self.default_renderer raise ErrorResponse(status.HTTP_406_NOT_ACCEPTABLE, {'detail': 'Could not satisfy the client\'s Accept header', - 'available_types': self.emitted_media_types}) + 'available_types': self.renderted_media_types}) @property - def emitted_media_types(self): - """Return an list of all the media types that this resource can emit.""" - return [emitter.media_type for emitter in self.emitters] + def renderted_media_types(self): + """Return an list of all the media types that this resource can render.""" + return [renderer.media_type for renderer in self.renderers] @property - def default_emitter(self): - """Return the resource's most prefered emitter. - (This emitter is used if the client does not send and Accept: header, or sends Accept: */*)""" - return self.emitters[0] + def default_renderer(self): + """Return the resource's most prefered renderer. + (This renderer is used if the client does not send and Accept: header, or sends Accept: */*)""" + return self.renderers[0] ########## Auth Mixin ########## diff --git a/djangorestframework/modelresource.py b/djangorestframework/modelresource.py index 79505c6c9..c61cc375e 100644 --- a/djangorestframework/modelresource.py +++ b/djangorestframework/modelresource.py @@ -49,7 +49,7 @@ class ModelResource(Resource): #def get_form(self, content=None): - # """Return a form that may be used in validation and/or rendering an html emitter""" + # """Return a form that may be used in validation and/or rendering an html renderer""" # if self.form: # return super(self.__class__, self).get_form(content) # @@ -121,8 +121,8 @@ class ModelResource(Resource): elif inspect.isfunction(thing): if not inspect.getargspec(thing)[0]: ret = _any(thing()) - elif hasattr(thing, '__emittable__'): - f = thing.__emittable__ + elif hasattr(thing, '__rendertable__'): + f = thing.__rendertable__ if inspect.ismethod(f) and len(inspect.getargspec(f)[0]) == 1: ret = _any(f()) else: diff --git a/djangorestframework/resource.py b/djangorestframework/resource.py index 636fe0bab..cb4d080c7 100644 --- a/djangorestframework/resource.py +++ b/djangorestframework/resource.py @@ -4,13 +4,13 @@ from django.views.decorators.csrf import csrf_exempt from djangorestframework.compat import View from djangorestframework.response import Response, ErrorResponse from djangorestframework.mixins import RequestMixin, ResponseMixin, AuthMixin -from djangorestframework import emitters, parsers, authenticators, permissions, validators, status +from djangorestframework import renderers, parsers, authenticators, permissions, validators, status # TODO: Figure how out references and named urls need to work nicely # TODO: POST on existing 404 URL, PUT on existing 404 URL # -# NEXT: Exceptions on func() -> 500, tracebacks emitted if settings.DEBUG +# NEXT: Exceptions on func() -> 500, tracebacks renderted if settings.DEBUG __all__ = ['Resource'] @@ -21,12 +21,12 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View): http_method_names = ['get', 'post', 'put', 'delete', 'head', 'options', 'trace', 'patch'] - # List of emitters the resource can serialize the response with, ordered by preference. - emitters = ( emitters.JSONEmitter, - emitters.DocumentingHTMLEmitter, - emitters.DocumentingXHTMLEmitter, - emitters.DocumentingPlainTextEmitter, - emitters.XMLEmitter ) + # List of renderers the resource can serialize the response with, ordered by preference. + renderers = ( renderers.JSONRenderer, + renderers.DocumentingHTMLRenderer, + renderers.DocumentingXHTMLRenderer, + renderers.DocumentingPlainTextRenderer, + renderers.XMLRenderer ) # List of parsers the resource can parse the request with. parsers = ( parsers.JSONParser, @@ -48,7 +48,7 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View): # Allow name and description for the Resource to be set explicitly, # overiding the default classname/docstring behaviour. - # These are used for documentation in the standard html and text emitters. + # These are used for documentation in the standard html and text renderers. name = None description = None @@ -69,7 +69,7 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View): Eg filter complex objects that cannot be serialized by json/xml/etc into basic objects that can. TODO: This is going to be removed. I think that the 'fields' behaviour is going to move into - the EmitterMixin and Emitter classes.""" + the RendererMixin and Renderer classes.""" return data @@ -123,7 +123,7 @@ class Resource(RequestMixin, ResponseMixin, AuthMixin, View): response.headers['Allow'] = ', '.join(self.allowed_methods) response.headers['Vary'] = 'Authenticate, Accept' - return self.emit(response) + return self.render(response) except: import traceback traceback.print_exc() diff --git a/djangorestframework/tests/breadcrumbs.py b/djangorestframework/tests/breadcrumbs.py index cc0d283d6..724f2ff56 100644 --- a/djangorestframework/tests/breadcrumbs.py +++ b/djangorestframework/tests/breadcrumbs.py @@ -28,7 +28,7 @@ urlpatterns = patterns('', class BreadcrumbTests(TestCase): - """Tests the breadcrumb functionality used by the HTML emitter.""" + """Tests the breadcrumb functionality used by the HTML renderer.""" urls = 'djangorestframework.tests.breadcrumbs' diff --git a/djangorestframework/utils.py b/djangorestframework/utils.py index 8b12294c7..f60bdee4d 100644 --- a/djangorestframework/utils.py +++ b/djangorestframework/utils.py @@ -125,7 +125,7 @@ def xml2dict(input): # Piston: -class XMLEmitter(): +class XMLRenderer(): def _to_xml(self, xml, data): if isinstance(data, (list, tuple)): for item in data: @@ -156,4 +156,4 @@ class XMLEmitter(): return stream.getvalue() def dict2xml(input): - return XMLEmitter().dict2xml(input) + return XMLRenderer().dict2xml(input) diff --git a/examples/mixin/urls.py b/examples/mixin/urls.py index 96b630e38..f4300f419 100644 --- a/examples/mixin/urls.py +++ b/examples/mixin/urls.py @@ -1,6 +1,6 @@ from djangorestframework.compat import View # Use Django 1.3's django.views.generic.View, or fall back to a clone of that if Django < 1.3 from djangorestframework.mixins import ResponseMixin -from djangorestframework.emitters import DEFAULT_EMITTERS +from djangorestframework.renderers import DEFAULT_RENDERERS from djangorestframework.response import Response from django.conf.urls.defaults import patterns, url @@ -9,8 +9,8 @@ from django.core.urlresolvers import reverse class ExampleView(ResponseMixin, View): """An example view using Django 1.3's class based views. - Uses djangorestframework's EmitterMixin to provide support for multiple output formats.""" - emitters = DEFAULT_EMITTERS + Uses djangorestframework's RendererMixin to provide support for multiple output formats.""" + renderers = DEFAULT_RENDERERS def get(self, request): response = Response(200, {'description': 'Some example content', diff --git a/examples/pygments_api/views.py b/examples/pygments_api/views.py index 4e6d12307..278e82506 100644 --- a/examples/pygments_api/views.py +++ b/examples/pygments_api/views.py @@ -4,7 +4,7 @@ from django.core.urlresolvers import reverse from djangorestframework.resource import Resource from djangorestframework.response import Response -from djangorestframework.emitters import BaseEmitter +from djangorestframework.renderers import BaseRenderer from djangorestframework import status from pygments.formatters import HtmlFormatter @@ -32,8 +32,8 @@ def remove_oldest_files(dir, max_files): [os.remove(path) for path in list_dir_sorted_by_ctime(dir)[max_files:]] -class HTMLEmitter(BaseEmitter): - """Basic emitter which just returns the content without any further serialization.""" +class HTMLRenderer(BaseRenderer): + """Basic renderer which just returns the content without any further serialization.""" media_type = 'text/html' @@ -68,8 +68,8 @@ class PygmentsRoot(Resource): class PygmentsInstance(Resource): """Simply return the stored highlighted HTML file with the correct mime type. - This Resource only emits HTML and uses a standard HTML emitter rather than the emitters.DocumentingHTMLEmitter class.""" - emitters = (HTMLEmitter,) + This Resource only emits HTML and uses a standard HTML renderer rather than the renderers.DocumentingHTMLRenderer class.""" + renderers = (HTMLRenderer,) def get(self, request, unique_id): """Return the highlighted snippet.""" diff --git a/examples/sandbox/views.py b/examples/sandbox/views.py index 5b84e8e42..04e4da412 100644 --- a/examples/sandbox/views.py +++ b/examples/sandbox/views.py @@ -11,14 +11,14 @@ class Sandbox(Resource): All the example APIs allow anonymous access, and can be navigated either through the browser or from the command line... - bash: curl -X GET http://api.django-rest-framework.org/ # (Use default emitter) - bash: curl -X GET http://api.django-rest-framework.org/ -H 'Accept: text/plain' # (Use plaintext documentation emitter) + bash: curl -X GET http://api.django-rest-framework.org/ # (Use default renderer) + bash: curl -X GET http://api.django-rest-framework.org/ -H 'Accept: text/plain' # (Use plaintext documentation renderer) The examples provided: 1. A basic example using the [Resource](http://django-rest-framework.org/library/resource.html) class. 2. A basic example using the [ModelResource](http://django-rest-framework.org/library/modelresource.html) class. - 3. An basic example using Django 1.3's [class based views](http://docs.djangoproject.com/en/dev/topics/class-based-views/) and djangorestframework's [EmitterMixin](http://django-rest-framework.org/library/emitters.html). + 3. An basic example using Django 1.3's [class based views](http://docs.djangoproject.com/en/dev/topics/class-based-views/) and djangorestframework's [RendererMixin](http://django-rest-framework.org/library/renderers.html). 4. A generic object store API. 5. A code highlighting API. 6. A blog posts and comments API.