def create_dataset(): """Create a new dataset. **Example request**: .. sourcecode:: json { "name": "Mood", "description": "Dataset for mood classification.", "public": true, "classes": [ { "name": "Happy", "description": "Recordings that represent happiness.", "recordings": ["770cc467-8dde-4d22-bc4c-a42f91e"] }, { "name": "Sad" } ] } :reqheader Content-Type: *application/json* :<json string name: *Required.* Name of the dataset. :<json string description: *Optional.* Description of the dataset. :<json boolean public: *Optional.* ``true`` to make dataset public, ``false`` to make it private. New datasets are public by default. :<json array classes: *Optional.* Array of objects containing information about classes to add into new dataset. For example: .. sourcecode:: json { "name": "Happy", "description": "Recordings that represent happiness.", "recordings": ["770cc467-8dde-4d22-bc4c-a42f91e"] } :resheader Content-Type: *application/json* :>json boolean success: ``True`` on successful creation. :>json string dataset_id: ID (UUID) of newly created dataset. """ dataset_dict = request.get_json() if not dataset_dict: raise api_exceptions.APIBadRequest("Data must be submitted in JSON format.") if "public" not in dataset_dict: dataset_dict["public"] = True if "classes" not in dataset_dict: dataset_dict["classes"] = [] try: dataset_id = db.dataset.create_from_dict(dataset_dict, current_user.id) except dataset_validator.ValidationException as e: raise api_exceptions.APIBadRequest(e.message) return jsonify( success=True, dataset_id=dataset_id, )
def submit_low_level(mbid): """Endpoint for submitting low-level information to AcousticBrainz.""" raw_data = request.get_data() try: data = json.loads(raw_data.decode("utf-8")) except ValueError as e: raise exceptions.APIBadRequest("Cannot parse JSON document: %s" % e) try: submit_low_level_data(mbid, data, 'mbid') except BadDataException as e: raise exceptions.APIBadRequest("%s" % e) return jsonify({"message": "ok"})
def delete_class(dataset_id): """Delete class and all of its recordings from a dataset. **Example request**: .. sourcecode:: json { "name": "Sad" } :reqheader Content-Type: *application/json* :<json string name: *Required.* Name of the class. :resheader Content-Type: *application/json* """ ds = get_check_dataset(dataset_id, write=True) class_dict = request.get_json() try: dataset_validator.validate_class(class_dict, recordings_required=False) except dataset_validator.ValidationException as e: raise api_exceptions.APIBadRequest(e.error) db.dataset.delete_class(ds["id"], class_dict) return jsonify(success=True, message="Class deleted.")
def update_dataset_details(dataset_id): """Update dataset details. If one of the fields is not specified, it will not be updated. **Example request**: .. sourcecode:: json { "name": "Not Mood", "description": "Dataset for mood misclassification.", "public": true } :reqheader Content-Type: *application/json* :<json string name: *Optional.* Name of the dataset. :<json string description: *Optional.* Description of the dataset. :<json boolean public: *Optional.* ``true`` to make dataset public, ``false`` to make it private. :resheader Content-Type: *application/json* """ ds = get_check_dataset(dataset_id, write=True) dataset_data = request.get_json() try: dataset_validator.validate_dataset_update(dataset_data) except dataset_validator.ValidationException as e: raise api_exceptions.APIBadRequest(e.error) db.dataset.update_dataset_meta(ds["id"], dataset_data) return jsonify(success=True, message="Dataset updated.")
def submit_low_level(mbid): """Endpoint for submitting low-level information to AcousticBrainz.""" raw_data = request.get_data() try: data = json.loads(raw_data.decode("utf-8")) except ValueError as e: raise exceptions.APIBadRequest("Cannot parse JSON document: %s" % e) max_duplicate_submissions = current_app.config.get( 'MAX_NUMBER_DUPLICATE_SUBMISSIONS', None) try: submit_low_level_data(mbid, data, 'mbid', max_duplicate_submissions) except BadDataException as e: raise exceptions.APIBadRequest("%s" % e) return jsonify({"message": "ok"})
def delete_recordings(dataset_id): """Delete recordings from a class in a dataset. **Example request**: .. sourcecode:: json { "class_name": "Happy", "recordings": ["770cc467-8dde-4d22-bc4c-a42f91e"] } :reqheader Content-Type: *application/json* :<json string class_name: *Required.* Name of the class. :<json array recordings: *Required.* Array of recoding MBIDs (``string``) that need be deleted from a class. :resheader Content-Type: *application/json* """ ds = get_check_dataset(dataset_id, write=True) class_dict = request.get_json() try: dataset_validator.validate_recordings_add_delete(class_dict) except dataset_validator.ValidationException as e: raise api_exceptions.APIBadRequest(e.error) unique_mbids = list(set(class_dict["recordings"])) class_dict["recordings"] = unique_mbids try: db.dataset.delete_recordings(ds["id"], class_dict["class_name"], class_dict["recordings"]) except db.exceptions.NoDataFoundException as e: # NoDataFoundException is raised if the class name doesn't exist in this dataset. # We treat this as a bad request, because it's based on data in the request body, # and not the url raise api_exceptions.APIBadRequest(str(e)) return jsonify(success=True, message="Recordings deleted.")
def update_class(dataset_id): """Update class in a dataset. If one of the fields is not specified, it will not be updated. **Example request**: .. sourcecode:: json { "name": "Very happy", "new_name": "Recordings that represent ultimate happiness." } :reqheader Content-Type: *application/json* :<json string name: *Required.* Current name of the class. :<json string new_name: *Optional.* New name of the class. Must be unique within a dataset. :<json string description: *Optional.* Description of the class. :resheader Content-Type: *application/json* """ ds = get_check_dataset(dataset_id, write=True) class_data = request.get_json() try: dataset_validator.validate_class_update(class_data) except dataset_validator.ValidationException as e: raise api_exceptions.APIBadRequest(e.error) try: db.dataset.update_class(ds["id"], class_data["name"], class_data) except db.exceptions.NoDataFoundException as e: # NoDataFoundException is raised if the class name doesn't exist in this dataset. # We treat this as a bad request, because it's based on data in the request body, # and not the url raise api_exceptions.APIBadRequest(str(e)) return jsonify(success=True, message="Class updated.")
def _validate_data_arguments(mbid, offset): """Validate the mbid and offset. If the mbid is not a valid uuid, raise 404. If the offset is None, return 0, otherwise interpret it as a number. If it is not a number, raise 400.""" try: mbid = str(uuid.UUID(mbid)) except ValueError: # an invalid uuid is 404 raise exceptions.APINotFound("Not found") if offset: try: offset = int(offset) except ValueError: raise exceptions.APIBadRequest("Offset must be an integer value") else: offset = 0 return mbid, offset
def add_class(dataset_id): """Add a class to a dataset. The data can include an optional list of recording ids. If these are included, the recordings are also added to the list. Duplicate recording ids are ignored. If a class with the given name already exists, the recordings (if provided) will be added to the existing class. **Example request**: .. sourcecode:: json { "name": "Not Mood", "description": "Dataset for mood misclassification.", "recordings": ["770cc467-8dde-4d22-bc4c-a42f91e"] } :reqheader Content-Type: *application/json* :<json string name: *Required.* Name of the class. Must be unique within a dataset. :<json string description: *Optional.* Description of the class. :<json array recordings: *Optional.* Array of recording MBIDs (``string``) to add into that class. For example: ``["770cc467-8dde-4d22-bc4c-a42f91e"]``. :resheader Content-Type: *application/json* """ ds = get_check_dataset(dataset_id, write=True) class_dict = request.get_json() try: dataset_validator.validate_class(class_dict, recordings_required=False) except dataset_validator.ValidationException as e: raise api_exceptions.APIBadRequest(e.error) if "recordings" in class_dict: unique_mbids = list(set(class_dict["recordings"])) class_dict["recordings"] = unique_mbids db.dataset.add_class(ds["id"], class_dict) return jsonify(success=True, message="Class added.")
def get_jobs(): """Return a list of jobs related to the current user. Identify the current user by being logged in or by passing a Token for authentication. :query status: *Required.* Status of jobs to be returned. Possible values: "pending" :query location: *Required.* Location that the user wants to evaluate jobs. Possible values: "remote" **Example Response**: .. sourcecode:: json { 'username': '******' 'jobs': [ { 'dataset_name': 'test_dataset', 'created': 'Wed, 08 Jun 2016 21:41:58 GMT', 'job_id': '0fc553b6-f3a8-4e24-af39-56ac02276ed9' } ] } :reqheader Content-Type: *application/json* :<json string username: MusicBrainz username of the user. :<json array jobs: Jobs which match the query. """ location = request.args.get("location") status = request.args.get("status") # TODO: This endpoint can be used in the future to get any type of job, # but for now we only use it for pending/remote. if location != db.dataset_eval.EVAL_REMOTE or status != db.dataset_eval.STATUS_PENDING: raise exceptions.APIBadRequest( "parameter location must be 'remote' and status 'pending'") jobs = db.dataset_eval.get_remote_pending_jobs_for_user(current_user.id) return jsonify(username=current_user.musicbrainz_id, jobs=jobs)