Python pyramid.httpexceptions.HTTPBadRequest() Examples

The following are 28 code examples of pyramid.httpexceptions.HTTPBadRequest(). You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may also want to check out all available functions/classes of the module pyramid.httpexceptions , or try the search function .
Example #1
Source File: test_validation.py    From pyramid_openapi3 with MIT License 6 votes vote down vote up
def test_view_raises_valid_http_exception(self) -> None:
        """Test View raises HTTPException.

        Example view raises a defined response code.
        """
        from pyramid.httpexceptions import HTTPBadRequest

        def view_func(*args):
            raise HTTPBadRequest("bad foo request")

        self._add_view(view_func)
        view = self._get_view()
        request = self._get_request(params={"bar": "1"})
        with self.assertRaises(HTTPBadRequest) as cm:
            view(None, request)
        response = cm.exception
        # not enough of pyramid has been set up so we need to render the
        # exception response ourselves.
        response.prepare({"HTTP_ACCEPT": "application/json"})
        self.assertIn("bad foo request", response.json["message"]) 
Example #2
Source File: test_pyramid.py    From sentry-python with BSD 2-Clause "Simplified" License 6 votes vote down vote up
def test_bad_request_not_captured(
    sentry_init, pyramid_config, capture_events, route, get_client
):
    import pyramid.httpexceptions as exc

    sentry_init(integrations=[PyramidIntegration()])
    events = capture_events()

    @route("/")
    def index(request):
        raise exc.HTTPBadRequest()

    def errorhandler(exc, request):
        return Response("bad request")

    pyramid_config.add_view(errorhandler, context=exc.HTTPBadRequest)

    client = get_client()
    client.get("/")

    assert not events 
Example #3
Source File: jsonschema.py    From rest_toolkit with BSD 2-Clause "Simplified" License 6 votes vote down vote up
def validate(data, schema):
    """Validate data against a JSON schema.

    This is a helper function used by :py:class:`JsonSchemaValidationMixin`
    to validate data against a JSON schema. If validation fails this function
    will raise a :py:class:`pyramid.httpexceptions.HTTPBadRequest` exception
    describing the validation error.

    :raises pyramid.httpexceptions.HTTPBadRequest: if validation fails this
        exception is raised to abort any further processing.
    """
    try:
        jsonschema.validate(data, schema,
            format_checker=jsonschema.draft4_format_checker)
    except jsonschema.ValidationError as e:
        error = {
            '.'.join(str(p) for p in e.path): e.message
        }
        response = JSONValidationError(json=error)
        response.validation_error = e
        raise response 
Example #4
Source File: colander.py    From rest_toolkit with BSD 2-Clause "Simplified" License 6 votes vote down vote up
def validate(data, schema):
    """Validate data against a Colander schema class.

    This is a helper function used by :py:class:`ColanderSchemaValidationMixin`
    to validate data against a Colander schema. If validation fails this function
    will raise a :py:class:`pyramid.httpexceptions.HTTPBadRequest` exception
    describing the validation error.

    :raises pyramid.httpexceptions.HTTPBadRequest: if validation fails this
        exception is raised to abort any further processing.
    """
    schema_instance = schema()
    try:
        schema_instance.deserialize(data)
    except colander.Invalid as e:
        raise HTTPBadRequest(e.msg) 
Example #5
Source File: resource_error.py    From rest_toolkit with BSD 2-Clause "Simplified" License 6 votes vote down vote up
def __init__(self, request):
        raise HTTPBadRequest(json={'foo': 'bar'}) 
Example #6
Source File: views_test.py    From bouncer with BSD 2-Clause "Simplified" License 6 votes vote down vote up
def test_it_rejects_invalid_or_missing_urls(self):
        invalid_urls = [
            None,
            # Unsupported protocols.
            "ftp://foo.bar",
            "doi:10.1.2/345",
            "file://foo.bar",
            # Malformed URLs.
            r"http://goo\[g",
        ]

        for url in invalid_urls:
            request = mock_request()
            request.GET["url"] = url

            with pytest.raises(httpexceptions.HTTPBadRequest):
                views.goto_url(request) 
Example #7
Source File: opaquelinks.py    From patzilla with GNU Affero General Public License v3.0 6 votes vote down vote up
def opaquelinks_verify_handler(request):
    """Verify an opaquelinks token"""

    token = token_payload(request)

    if not token:
        return HTTPBadRequest('Token missing')

    signer = request.registry.getUtility(ISigner)
    data, meta = signer.unsign(token)
    return data


# ------------------------------------------
#   utility functions
# ------------------------------------------ 
Example #8
Source File: ificlaims.py    From patzilla with GNU Affero General Public License v3.0 6 votes vote down vote up
def ificlaims_download_handler(request):
    """Download resources from IFI CLAIMS Direct"""

    resource = request.matchdict['resource']
    format   = request.matchdict['format'].lower()
    pretty   = asbool(request.params.get('pretty'))
    seq      = int(request.params.get('seq', 1))
    options = {'pretty': pretty, 'seq': seq}

    try:
        response = ificlaims_download(resource, format, options)

    except IFIClaimsException, ex:
        if type(ex) is IFIClaimsFormatException:
            raise HTTPNotFound(ex)
        else:
            raise HTTPBadRequest(ex) 
Example #9
Source File: dpma.py    From patzilla with GNU Affero General Public License v3.0 6 votes vote down vote up
def depatisconnect_abstract_handler(request):
    # TODO: use jsonified error responses
    patent = request.matchdict['patent']
    language = request.params.get('language')
    try:
        abstract = depatisconnect_abstracts(patent, language)

    except KeyError as ex:
        log.error('Problem fetching details of DEPATISconnect: %s %s', type(ex), ex)
        raise HTTPNotFound(ex)

    except ValueError as ex:
        log.error('Problem fetching details of DEPATISconnect: %s %s', type(ex), ex)
        raise HTTPBadRequest(ex)

    return abstract 
Example #10
Source File: dpma.py    From patzilla with GNU Affero General Public License v3.0 6 votes vote down vote up
def depatisconnect_description_handler_real(patent):
    try:
        description = depatisconnect_description(patent)
        if not description['xml']:
            raise KeyError('Description is empty')

    except KeyError as ex:
        log.error('No details at DEPATISconnect: %s %s', type(ex), ex)
        raise HTTPNotFound(ex)

    except ValueError as ex:
        log.error('Fetching details from DEPATISconnect failed: %s %s', type(ex), ex)
        raise HTTPBadRequest(ex)

    except Exception as ex:
        log.error('Unknown error from DEPATISconnect: %s %s.', type(ex), ex)
        log.error(exception_traceback())
        raise HTTPBadRequest(ex)

    return description 
Example #11
Source File: dpma.py    From patzilla with GNU Affero General Public License v3.0 6 votes vote down vote up
def depatisconnect_claims_handler_real(patent):
    try:
        claims = depatisconnect_claims(patent)

    except KeyError as ex:
        log.error('No details at DEPATISconnect: %s %s', type(ex), ex)
        raise HTTPNotFound(ex)

    except ValueError as ex:
        log.error('Fetching details from DEPATISconnect failed: %s %s', type(ex), ex)
        raise HTTPBadRequest(ex)

    except Exception as ex:
        log.error('Unknown error from DEPATISconnect: %s %s.', type(ex), ex)
        log.error(exception_traceback())
        raise HTTPBadRequest(ex)

    return claims 
Example #12
Source File: views.py    From wut4lunch_demos with GNU General Public License v3.0 5 votes vote down vote up
def newlunch(request):
    form = Form(request, schema=LunchSchema())
    if not form.validate:
        raise exc.HTTPBadRequest

    l = Lunch(
        submitter=request.POST.get('submitter', 'nobody'),
        food=request.POST.get('food', 'nothing'),
    )

    with transaction.manager:
        DBSession.add(l)

    raise exc.HTTPSeeOther('/') 
Example #13
Source File: context.py    From muesli with GNU General Public License v3.0 5 votes vote down vote up
def __init__(self, request):
        exercise_id = request.matchdict['exercise_id']
        exercise_id = exercise_id.strip("/")
        user_id = request.matchdict.get('user_id', None)
        self.exercise = request.db.query(Exercise).get(exercise_id)
        if self.exercise is None:
            raise HTTPBadRequest("Die Angeforderte Übung existiert nicht!")
        self.lecture = self.exercise.exam.lecture
        student = None
        self.user = None
        if user_id is not None:
            user_id = user_id.strip("/")
            self.user = request.db.query(User).get(user_id)
            try:
                student = request.db.query(LectureStudent).filter(and_(LectureStudent.student_id == self.user.id, LectureStudent.lecture == self.lecture)).one()
            except SQLAlchemyError:
                student = None
        self.__acl__ = [(Allow, 'group:administrators', ALL_PERMISSIONS)]
        self.__acl__ += [(Allow, 'user:{0}'.format(request.user.id), ('view', 'viewAll', 'viewOwn'))] if request.user in self.lecture.assistants else []
        if request.user == self.user and request.user is not None:
            self.__acl__ += [(Allow, 'user:{0}'.format(request.user.id), ('view', 'viewOwn'))]
        if self.lecture.tutor_rights == editAllTutorials:
            self.__acl__ += [(Allow, 'user:{0}'.format(request.user.id), ('view', 'viewAll', 'viewOwn'))] if request.user == self.lecture.tutors else []
        else:
            self.__acl__ += [(Allow, 'user:{0}'.format(request.user.id), ('view'))] if request.user in self.lecture.tutors else []
        if student is not None:
            tutorial = student.tutorial
            self.__acl__ += [(Allow, 'user:{0}'.format(request.user.id), ('viewOwn'))] if request.user == tutorial.tutor else [] 
Example #14
Source File: viewsUser.py    From muesli with GNU General Public License v3.0 5 votes vote down vote up
def removeKey(request):
    code_id = int(request.matchdict['key_id'])
    api_key = request.db.query(models.BearerToken).get(code_id)
    if api_key is None:
        raise HTTPBadRequest("API Key nicht gefunden")
    if api_key.user == request.user or request.user.is_admin:
        api_key.revoked = True
        request.db.add(api_key)
        request.db.commit()
        request.session.flash('API Key entfernt ', queue='messages')
    else:
        request.session.flash('API Key nicht gefunden', queue='errors')
    if request.referrer:
        return HTTPFound(location=request.referrer)
    return HTTPFound(location=request.route_url('overview')) 
Example #15
Source File: viewsUser.py    From muesli with GNU General Public License v3.0 5 votes vote down vote up
def list_auth_keys(request):
    form = forms.SetAuthCodeDescription(request)
    jwt_token = ""
    if request.matchdict.get('user_id', ""):
        user_id = request.matchdict.get('user_id', "")
    else:
        user_id = request.user.id
    tokens = (request.db.query(models.BearerToken)
              .filter_by(user_id=user_id).filter(models.BearerToken.revoked == False).all())
    if request.method == 'POST' and form.processPostData(request.POST):
        exp = datetime.timedelta(days=muesli.config["api"]["KEY_EXPIRATION"])
        max_keys = muesli.config["api"].get("MAX_KEYS", 0)
        if len(tokens) >= max_keys and max_keys != -1:
            raise HTTPBadRequest(
                "Sie haben das Maximum von {} Keys überschritten!"
                .format(max_keys)
            )
        token = models.BearerToken(client="Personal Token",
                                   user=request.user,
                                   description=form['description'],
                                   expires=datetime.datetime.utcnow()+exp
                                   )
        request.db.add(token)
        request.db.flush()
        jwt_token = request.create_jwt_token(request.user.id,
                                             admin=(request.user.is_admin),
                                             jti=token.id,
                                             expiration=exp)
        request.session.flash("Ihr API Token wurde erstellt!", queue='messages')
        request.db.commit()
        tokens.append(token)
    return {'keys': tokens,
            'form': form,
            'freshtoken': jwt_token} 
Example #16
Source File: ificlaims.py    From patzilla with GNU Affero General Public License v3.0 5 votes vote down vote up
def ificlaims_deliver_handler(request):
    """Deliver resources from IFI CLAIMS Direct in bulk"""

    kind = request.matchdict['kind']
    formats = map(unicode.strip, request.params.get('formats', u'').lower().split(u','))
    numberlist = filter(lambda item: bool(item), map(unicode.strip, re.split('[\n,]', request.params.get('numberlist', u''))))

    if kind == 'zip':
        multi = ificlaims_download_multi(numberlist, formats)

        #for entry in multi['results']:
        #    print 'entry:', entry
        print 'report:'
        print json.dumps(multi['report'], indent=4)

        payload = zip_multi(multi)

        disposition = 'attachment'
        zipname = time.strftime('ificlaims-delivery_%Y%m%d-%H%M%S.zip')

        content_disposition = '{disposition}; filename={filename}'.format(disposition=disposition, filename=zipname)
        request.response.content_type = 'application/zip'
        request.response.headers['Content-Disposition'] = content_disposition
        request.response.headers['Data-Source'] = 'ifi'

        return payload
    else:
        raise HTTPBadRequest("Unknown delivery kind '{kind}'".format(**locals()))





# TODO: implement as JSON POST 
Example #17
Source File: pyramid.py    From patzilla with GNU Affero General Public License v3.0 5 votes vote down vote up
def espacenet_description_handler(patent):
    try:
        description = espacenet_description(patent)

    except KeyError as ex:
        logger.error('No details at Espacenet: %s %s', type(ex), ex)
        raise HTTPNotFound(ex)

    except ValueError as ex:
        logger.error('Fetching details from Espacenet failed: %s %s', type(ex), ex)
        raise HTTPBadRequest(ex)

    return description 
Example #18
Source File: pyramid.py    From patzilla with GNU Affero General Public License v3.0 5 votes vote down vote up
def espacenet_claims_handler(patent):
    try:
        claims = espacenet_claims(patent)

    except KeyError as ex:
        logger.error('No details at Espacenet: %s %s', type(ex), ex)
        raise HTTPNotFound(ex)

    except ValueError as ex:
        logger.error('Fetching details from Espacenet failed: %s %s', type(ex), ex)
        raise HTTPBadRequest(ex)

    return claims 
Example #19
Source File: admin.py    From thinkhazard with GNU General Public License v3.0 5 votes vote down vote up
def admindiv_hazardsets_hazardtype(request):

    try:
        hazardtype = request.matchdict.get("hazardtype")
    except:
        raise HTTPBadRequest(detail="incorrect value for parameter " '"hazardtype"')

    if HazardType.get(request.dbsession, hazardtype) is None:
        raise HTTPBadRequest(detail="hazardtype doesn't exist")

    query = (
        request.dbsession.query(AdministrativeDivision)
        .join(HazardCategoryAdministrativeDivisionAssociation)
        .join(HazardCategory)
        .join(HazardType)
        .filter(HazardType.mnemonic == hazardtype)
        .join(AdminLevelType)
        .filter(AdminLevelType.id == 3)
        .order_by(AdministrativeDivision.name)
        .options(contains_eager(AdministrativeDivision.hazardcategories))
    )

    data = [
        {
            "code": row.code,
            "name": row.name,
            "level_2": row.parent.name,
            "level_1": row.parent.parent.name,
            "hazardset": row.hazardcategories[0].hazardsets[0].id
            if row.hazardcategories[0].hazardsets
            else None,
            "hazard_level": row.hazardcategories[0].hazardcategory.hazardlevel.mnemonic,
        }
        for row in query
    ]

    return data 
Example #20
Source File: search.py    From thinkhazard with GNU General Public License v3.0 5 votes vote down vote up
def administrativedivision(request):

    if "q" not in request.params:
        raise HTTPBadRequest(detail='parameter "q" is missing')

    term = request.params["q"]

    filter_lang = None

    if request.locale_name != "en":
        attribute = getattr(AdDiv, "name_" + request.locale_name)
        filter_lang = func.unaccent(attribute).ilike(func.unaccent("%{}%".format(term)))
        filter_lang = and_(filter_lang, AdminLevelType.mnemonic == "COU")

    filter = func.unaccent(AdDiv.name).ilike(func.unaccent("%{}%".format(term)))

    if filter_lang is not None:
        filter = or_(filter_lang, filter)

    query = (
        request.dbsession.query(AdDiv)
        .filter(filter)
        .join(AdminLevelType)
        .order_by(
            AdDiv.name.ilike(term).desc(),
            AdDiv.name.ilike("{}%".format(term)).desc(),
            AdDiv.leveltype_id,
            AdDiv.name,
        )
        .limit(10)
    )
    data = query.all()

    return {"data": data} 
Example #21
Source File: pdf.py    From thinkhazard with GNU General Public License v3.0 5 votes vote down vote up
def pdf_cover(request):
    try:
        division_code = request.matchdict.get("divisioncode")
    except:
        raise HTTPBadRequest(detail="incorrect value for parameter " '"divisioncode"')
    division = get_division(request, division_code)
    hazard_types = get_hazard_types(request, division_code)

    hazards_sorted = sorted(hazard_types, key=lambda a: a["hazardlevel"].order)

    hazard_categories = []
    for h in hazards_sorted:
        if h["hazardlevel"].mnemonic == _hazardlevel_nodata.mnemonic:
            continue
        hazard_categories.append(
            get_info_for_hazard_type(request, h["hazardtype"].mnemonic, division)
        )

    lon, lat = (
        request.dbsession.query(
            func.ST_X(ST_Centroid(AdministrativeDivision.geom)),
            func.ST_Y(ST_Centroid(AdministrativeDivision.geom)),
        )
        .filter(AdministrativeDivision.code == division_code)
        .first()
    )

    context = {
        "hazards": hazard_types,
        "hazards_sorted": sorted(hazard_types, key=lambda a: a["hazardlevel"].order),
        "parents": get_parents(division),
        "division": division,
        "division_lonlat": (lon, lat),
        "hazard_categories": hazard_categories,
        "date": datetime.datetime.now(),
    }

    return context 
Example #22
Source File: report.py    From thinkhazard with GNU General Public License v3.0 5 votes vote down vote up
def data_source(request):
    try:
        hazardset_id = request.matchdict.get("hazardset")
        hazardset = (
            request.dbsession.query(HazardSet)
            .join(Layer)
            .filter(HazardSet.id == hazardset_id)
            .order_by(Layer.return_period)
            .options(contains_eager(HazardSet.layers))
            .one()
        )
    except:
        raise HTTPBadRequest(detail="incorrect value for parameter " '"hazardset"')

    return {"hazardset": hazardset} 
Example #23
Source File: test_jsonschema.py    From rest_toolkit with BSD 2-Clause "Simplified" License 5 votes vote down vote up
def test_validation_error():
    resource = DummyResource()
    with pytest.raises(HTTPBadRequest):
        resource.validate({'email': 'john@example.com'}, partial=False) 
Example #24
Source File: test_colander.py    From rest_toolkit with BSD 2-Clause "Simplified" License 5 votes vote down vote up
def test_validation_error():
    resource = DummyResource()
    with pytest.raises(HTTPBadRequest):
        resource.validate({'email': 'john@example.com'}, partial=False) 
Example #25
Source File: report.py    From thinkhazard with GNU General Public License v3.0 4 votes vote down vote up
def report_neighbours_geojson(request):

    try:
        division_code = request.matchdict.get("divisioncode")
    except:
        raise HTTPBadRequest(detail="incorrect value for parameter " '"divisioncode"')

    try:
        bbox = request.params.get("bbox")
        box = [float(x) for x in bbox.split(",")]
        bbox = Polygon(
            (
                (box[0], box[1]),
                (box[0], box[3]),
                (box[2], box[3]),
                (box[2], box[1]),
                (box[0], box[1]),
            )
        )
        bbox = from_shape(bbox, srid=4326)
    except:
        raise HTTPBadRequest(detail='invalid value for parameter "bbox"')

    division = get_division(request, division_code)

    divisions = (
        request.dbsession.query(AdministrativeDivision)
        .add_columns(AdministrativeDivision.geom_simplified)
        .filter(func.ST_DWITHIN(AdministrativeDivision.geom, bbox, 0))
        .filter(AdministrativeDivision.leveltype_id == division.leveltype_id)
    )

    return [
        {
            "type": "Feature",
            "geometry": to_shape(geom_simplified) if geom_simplified is not None else None,
            "properties": {
                "name": div.name,
                "code": div.code,
                "url": request.route_url("report_overview", division=div),
            },
        }
        for div, geom_simplified in divisions
    ] 
Example #26
Source File: tutorialEndpoint.py    From muesli with GNU General Public License v3.0 4 votes vote down vote up
def get(self):
        """
        ---
        get:
          security:
            - Bearer: [read]
            - Basic: [read]
          tags:
            - "v1"
          summary: "return a specific tutorial"
          description: ""
          operationId: "tutorial_get"
          produces:
            - "application/json"
          responses:
            200:
              description: "response for 200 code"
              schema:
                $ref: "#/definitions/Tutorial"
        """
        try:
            tutorial = self.request.db.query(models.Tutorial).options(
                joinedload(models.Tutorial.tutor),
                joinedload(models.Tutorial.lecture)).filter(
                    models.Tutorial.id == self.request.matchdict['tutorial_id'] # pylint: disable=C0121
                ).one()
        except NoResultFound:
            raise HTTPBadRequest("Ungueltige Tutorial ID!")
        exa = tutorial.lecture.exams.filter((models.Exam.results_hidden == False)|(models.Exam.results_hidden == None)) # pylint: disable=C0121
        if self.request.has_permission('viewAll'):
            tut_schema = models.TutorialSchema()
        else:
            tut_schema = models.TutorialSchema(only=allowed_attributes.tutorial())
        exam_schema = models.ExamSchema(many=True, only=["id", "name"])

        result = tut_schema.dump(tutorial)
        try:
            lecture_student = tutorial.lecture.lecture_students.filter(models.LectureStudent.student_id == self.request.user.id).one()
        except NoResultFound:
            lecture_student = None
        # If the user is part of the tutorial he is allowed to view the exams
        if self.request.has_permission('viewAll') or lecture_student:
            result.update({"exams": exam_schema.dump(exa)})
        return result 
Example #27
Source File: tutorialEndpoint.py    From muesli with GNU General Public License v3.0 4 votes vote down vote up
def collection_post(self):
        """
        ---
        post:
          security:
            - Bearer: [write]
            - Basic: [write]
          tags:
            - "v1"
          summary: "create a tutorial"
          operationId: "tutorial_collection_post"
          produces:
            - "application/json"
          consumes:
            - "application/json"
          parameters:
          - in: "body"
            name: "body"
            description: ""
            required: true
            schema:
              $ref: "#/definitions/Tutorial"
          responses:
            200:
              description: successfull creation of a tutorial
              schema:
                type: object
                properties:
                  result:
                    type: string
                    example: ok
                  created:
                    $ref: "#/definitions/CollectionTutorial"
            400:
              description: HTTPBadRequest (Example uses A bad attribute)
              schema:
                type: object
                properties:
                  result:
                    type: string
                    example: error
                  error:
                    type: array
                    example: [{'description': {'name': ['Missing data for required field.'], 'test123': ['Unknown field.']}, 'name': 'fail', 'location': 'body'}]
        """
        schema = models.TutorialSchema()
        schema.context['session'] = self.request.db
        try:
            result = schema.load(self.request.json_body)
        except ValidationError as e:
            self.request.errors.add('body', 'fail', e.messages)
        else:
            tutorial = models.Tutorial(**result)
            self.db.add(tutorial)
            self.db.commit()
            return {'result': 'ok', 'created': schema.dump(tutorial)} 
Example #28
Source File: views.py    From kinto-attachment with Apache License 2.0 4 votes vote down vote up
def post_attachment_view(request, file_field):
    keep_old_files = asbool(utils.setting_value(request, 'keep_old_files', default=False))

    # Remove potential existing attachment.
    utils.delete_attachment(request, keep_old_files=keep_old_files)

    if "multipart/form-data" not in request.headers.get('Content-Type', ''):
        raise http_error(httpexceptions.HTTPBadRequest(),
                         errno=ERRORS.INVALID_PARAMETERS,
                         message="Content-Type should be multipart/form-data")

    # Store file locally.
    try:
        content = request.POST.get(file_field)
    except ValueError as e:
        raise http_error(httpexceptions.HTTPBadRequest(),
                         errno=ERRORS.INVALID_PARAMETERS.value,
                         message=str(e))

    if content is None:
        raise http_error(httpexceptions.HTTPBadRequest(),
                         errno=ERRORS.INVALID_POSTED_DATA,
                         message="Attachment missing.")

    folder_pattern = utils.setting_value(request, 'folder', default='')
    folder = folder_pattern.format(**request.matchdict) or None
    attachment = utils.save_file(request, content, folder=folder)

    # Update related record.
    posted_data = {k: v for k, v in request.POST.items() if k != file_field}
    record = {'data': {}}
    for field in ('data', 'permissions'):
        if field in posted_data:
            try:
                record[field] = json.loads(posted_data.pop(field))
            except ValueError as e:
                error_msg = "body: %s is not valid JSON (%s)" % (field, str(e))
                raise http_error(httpexceptions.HTTPBadRequest(),
                                 errno=ERRORS.INVALID_POSTED_DATA,
                                 message=error_msg)
    # Some fields remaining in posted_data after popping: invalid!
    for field in posted_data.keys():
        error_msg = "body: %r not in ('data', 'permissions')" % field
        raise http_error(httpexceptions.HTTPBadRequest(),
                         errno=ERRORS.INVALID_POSTED_DATA,
                         message=error_msg)

    record['data'][file_field] = attachment

    utils.patch_record(record, request)

    # Return attachment data (with location header)
    request.response.headers['Location'] = utils.record_uri(request,
                                                            prefix=True)
    return attachment