def __call__(self, request, result, handler): if isinstance(result, ErrorDict): result = dictFromErrorDict(result) resource = handler.resource em_format = resource.determine_emitter(request) emitter, ct = Emitter.get(em_format) srl = emitter(result, typemapper, handler, handler.fields, anonymous=True) try: if resource.stream: stream = srl.stream_render(request) else: stream = srl.render(request) self.__init__(stream, mimetype=ct) self.streaming = resource.stream except HttpStatusCode, e: return e.response
def error_resp(message, error_type=None, resp=rc.BAD_REQUEST, status_code=None): logging.warn("Status Code " + str(resp.status_code) + ", error_type: " + repr(error_type) + ", message: " + repr(message)) error_json = {} if message and error_type: (error_type_resp, error_type) = error_type resp = error_type_resp error = {} error['type'] = error_type error['message'] = message error_json['error'] = error elif message: error = {} error['type'] = '' error['message'] = message error_json['error'] = error if message or error_type: emitter, ct = Emitter.get('json') #TODO: Make this work for other emitter formats srl = emitter(error_json, None, None, None, None) rendered_resp = srl.render(HttpRequest()) final_resp = HttpResponse(rendered_resp, mimetype=ct) if status_code: final_resp.status_code = status_code else: final_resp.status_code = resp.status_code return final_resp else: return resp
def apply_json_emitter(value_to_emit, handler=None): emitter, ct = Emitter.get('json') #TODO: Make this work for other emitter formats handler_fields = None if handler: handler_fields = handler.fields srl = emitter(value_to_emit, typemapper, handler, handler_fields, None) json = srl.construct() return json
def render_created(self, request, new_obj, new_url): """Quick hack to return a 201 Created along with a JSON rendering of what was created""" resp = rc.CREATED emitter, ct = Emitter.get('json') resp['Content-Type'] = ct resp['Location'] = new_url srl = emitter(new_obj, typemapper, self, self.fields, False) resp.content = srl.render(request) return resp
def form_validation_response(self, e, request,em_format): print 'in form_validation_response 1' try: emitter, ct = Emitter.get(em_format) fields = self.handler.fields except ValueError: result = piston.utils.rc.BAD_REQUEST result.content = "Invalid output format specified '%s'." % em_format return result serialized_errors = dict((key, [unicode(v) for v in values]) for key,values in e.form.errors.items()) srl = emitter(serialized_errors, piston.handler.typemapper, self.handler, fields, False) stream = srl.render(request) resp = HttpResponse(stream, mimetype=ct, status=400) return resp
def build_error_response(e, request): # logger.error(str(e.status_code) + ' API error: ' + e.type) content = {"error": True, "type": e.type, "status_code": e.status_code, "explanation": ""} content.update(e.extra) response = rc.BAD_REQUEST format = request.GET.get("format", "json") em_info = Emitter.get(format) RequestEmitter = em_info[0] emitter = RequestEmitter(content, typemapper, "", "", False) response.content = emitter.render(request) response["Content-Type"] = em_info[1] return response
def form_validation_response(self, e, request, em_format): print 'in form_validation_response 1' try: emitter, ct = Emitter.get(em_format) fields = self.handler.fields except ValueError: result = piston.utils.rc.BAD_REQUEST result.content = "Invalid output format specified '%s'." % em_format return result serialized_errors = dict((key, [unicode(v) for v in values]) for key, values in e.form.errors.items()) srl = emitter(serialized_errors, piston.handler.typemapper, self.handler, fields, False) stream = srl.render(request) resp = HttpResponse(stream, mimetype=ct, status=400) return resp
def render(self, request, *args, **kwargs): f = StringIO.StringIO() out = csv.writer(f,dialect='excel') c = self.construct() if not bool(request.REQUEST.get('headerless', False)): out.writerow(self.fields) def mapper(row): return [row[key] for key in self.fields] out.writerows(map(mapper, c)) # In this case we'll hanlde the HttpResponse wrapping. _, ct = Emitter.get('csv') response = HttpResponse(f.getvalue(), ct) response['Content-Disposition'] = 'attachment; filename=irack.csv' return response
def build_error_response(e, request): #logger.error(str(e.status_code) + ' API error: ' + e.type) content = { "error": True, "type": e.type, "status_code": e.status_code, "explanation": "" } content.update(e.extra) response = rc.BAD_REQUEST format = request.GET.get("format", "json") em_info = Emitter.get(format) RequestEmitter = em_info[0] emitter = RequestEmitter(content, typemapper, "", "", False) response.content = emitter.render(request) response['Content-Type'] = em_info[1] return response
assert range_end != None return (range_start, range_end) try: total = result.count() start, end = get_range(request_range[0], request_range[1], total) result = result[start:end + 1] content_range = "items %i-%i/%i" % (start, end, total) except BadRangeException, e: resp = rc.BAD_RANGE resp.write("\n%s" % e.value) return resp #end paging emitter, ct = Emitter.get(em_format) fields = handler.fields if hasattr(handler, 'list_fields') and ( isinstance(result, list) or isinstance(result, QuerySet)): fields = handler.list_fields srl = emitter(result, typemapper, handler, fields, anonymous) try: """ Decide whether or not we want a generator here, or we just want to buffer up the entire result before sending it to the client. Won't matter for smaller datasets, but larger will have an impact. """ if self.stream:
def __call__(self, request, *args, **kwargs): rm = request.method.upper() if rm == "PUT": coerce_put_post(request) actor, anonymous = self.authenticate(request, rm) if anonymous is CHALLENGE: return actor() else: handler = actor if rm in ('POST', 'PUT'): try: translate_mime(request) except MimerDataException: return rc.BAD_REQUEST if not hasattr(request, 'data'): if rm == 'POST': request.data = request.POST else: request.data = request.PUT if not rm in handler.allowed_methods: return HttpResponseNotAllowed(handler.allowed_methods) meth = getattr(handler, self.callmap.get(rm, ''), None) if not meth: raise Http404 em_format = self.determine_emitter(request, *args, **kwargs) kwargs.pop('emitter_format', None) request = self.cleanup_request(request) try: result = meth(request, *args, **kwargs) except ValueError: result = rc.BAD_REQUEST result.content = 'Invalid arguments' try: emitter, ct = Emitter.get(em_format) fields = handler.fields if hasattr(handler, 'list_fields') and isinstance( result, (list, tuple, QuerySet)): fields = handler.list_fields except ValueError: result = rc.BAD_REQUEST result.content = "Invalid output format specified '%s'." % em_format return result status_code = 200 if isinstance(result, HttpResponse) and not result._is_string: status_code = result.status_code result = result._container srl = emitter(result, typemapper, handler, fields, anonymous) try: if self.stream: stream = srl.stream_render(request) else: stream = srl.render(request) if not isinstance(stream, HttpResponse): resp = HttpResponse(stream, mimetype=ct, status=status_code) else: resp = stream resp.streaming = self.stream return resp except HttpStatusCode, e: return e.response
class Resource(object): """ Resource. Create one for your URL mappings, just like you would with Django. Takes one argument, the handler. The second argument is optional, and is an authentication handler. If not specified, `NoAuthentication` will be used by default. """ callmap = { 'GET': 'read', 'POST': 'create', 'PUT': 'update', 'DELETE': 'delete' } def __init__(self, handler, authentication=None): if not callable(handler): raise AttributeError, "Handler not callable." self.handler = handler() self.csrf_exempt = getattr(self.handler, 'csrf_exempt', True) if not authentication: self.authentication = (NoAuthentication(),) elif isinstance(authentication, (list, tuple)): self.authentication = authentication else: self.authentication = (authentication,) # Erroring self.email_errors = getattr(settings, 'PISTON_EMAIL_ERRORS', True) self.display_errors = getattr(settings, 'PISTON_DISPLAY_ERRORS', True) self.stream = getattr(settings, 'PISTON_STREAM_OUTPUT', False) def determine_emitter(self, request, *args, **kwargs): """ Function for determining which emitter to use for output. It lives here so you can easily subclass `Resource` in order to change how emission is detected. You could also check for the `Accept` HTTP header here, since that pretty much makes sense. Refer to `Mimer` for that as well. """ em = kwargs.pop('emitter_format', None) if not em: em = request.GET.get('format', 'json') return em def form_validation_response(self, e): """ Method to return form validation error information. You will probably want to override this in your own `Resource` subclass. """ resp = rc.BAD_REQUEST resp.write(' '+str(e.form.errors)) return resp @property def anonymous(self): """ Gets the anonymous handler. Also tries to grab a class if the `anonymous` value is a string, so that we can define anonymous handlers that aren't defined yet (like, when you're subclassing your basehandler into an anonymous one.) """ if hasattr(self.handler, 'anonymous'): anon = self.handler.anonymous if callable(anon): return anon for klass in typemapper.keys(): if anon == klass.__name__: return klass return None def authenticate(self, request, rm): actor, anonymous = False, True for authenticator in self.authentication: if not authenticator.is_authenticated(request): if self.anonymous and \ rm in self.anonymous.allowed_methods: actor, anonymous = self.anonymous(), True else: actor, anonymous = authenticator.challenge, CHALLENGE else: return self.handler, self.handler.is_anonymous return actor, anonymous @vary_on_headers('Authorization') def __call__(self, request, *args, **kwargs): """ NB: Sends a `Vary` header so we don't cache requests that are different (OAuth stuff in `Authorization` header.) """ rm = request.method.upper() # Django's internal mechanism doesn't pick up # PUT request, so we trick it a little here. if rm == "PUT": coerce_put_post(request) actor, anonymous = self.authenticate(request, rm) if anonymous is CHALLENGE: return actor() else: handler = actor # Translate nested datastructs into `request.data` here. if rm in ('POST', 'PUT'): try: translate_mime(request) except MimerDataException: return rc.BAD_REQUEST if not hasattr(request, 'data'): if rm == 'POST': request.data = request.POST else: request.data = request.PUT if not rm in handler.allowed_methods: return HttpResponseNotAllowed(handler.allowed_methods) meth = getattr(handler, self.callmap.get(rm, ''), None) if not meth: raise Http404 # Support emitter both through (?P<emitter_format>) and ?format=emitter. em_format = self.determine_emitter(request, *args, **kwargs) kwargs.pop('emitter_format', None) # Clean up the request object a bit, since we might # very well have `oauth_`-headers in there, and we # don't want to pass these along to the handler. request = self.cleanup_request(request) try: result = meth(request, *args, **kwargs) except Exception, e: result = self.error_handler(e, request, meth, em_format) try: emitter, ct = Emitter.get(em_format) fields = handler.fields if hasattr(handler, 'list_fields') and isinstance(result, (list, tuple, QuerySet)): fields = handler.list_fields except ValueError: result = rc.BAD_REQUEST result.content = "Invalid output format specified '%s'." % em_format return result status_code = 200 # If we're looking at a response object which contains non-string # content, then assume we should use the emitter to format that # content if isinstance(result, HttpResponse) and not result._is_string: status_code = result.status_code # Note: We can't use result.content here because that method attempts # to convert the content into a string which we don't want. # when _is_string is False _container is the raw data result = result._container srl = emitter(result, typemapper, handler, fields, anonymous) try: """ Decide whether or not we want a generator here, or we just want to buffer up the entire result before sending it to the client. Won't matter for smaller datasets, but larger will have an impact. """ if self.stream: stream = srl.stream_render(request) else: stream = srl.render(request) if not isinstance(stream, HttpResponse): resp = HttpResponse(stream, mimetype=ct, status=status_code) else: resp = stream resp.streaming = self.stream return resp except HttpStatusCode, e: return e.response