Exemplo n.º 1
0
def api_init_model_ready(project_id):  # noqa: F401
    """Check if trained model is available
    """

    error_path = get_project_path(project_id) / "error.json"
    if error_path.exists():
        logging.error("error on training")
        with open(error_path, "r") as f:
            error_message = json.load(f)
        return jsonify(message=error_message), 400

    try:

        if get_proba_path(project_id).exists():

            # read the file with project info
            with open(get_project_file_path(project_id), "r") as fp:
                project_info = json.load(fp)

            project_info["projectInitReady"] = True

            # update the file with project info
            with open(get_project_file_path(project_id), "w") as fp:
                json.dump(project_info, fp)

            response = jsonify({'status': 1})
        else:
            response = jsonify({'status': 0})

    except Exception as err:
        logging.error(err)
        return jsonify(message="Failed to initiate the project."), 500

    response.headers.add('Access-Control-Allow-Origin', '*')
    return response
Exemplo n.º 2
0
def main(argv):

    # parse arguments
    parser = argparse.ArgumentParser()
    parser.add_argument("project_id", type=str, help="Project id")
    parser.add_argument("--label_method",
                        type=str,
                        default=None,
                        help="Label method (for example 'prior')")
    args = parser.parse_args(argv)

    try:
        train_model(args.project_id, args.label_method)
    except Exception as err:
        err_type = type(err).__name__
        logging.error(f"Project {args.project_id} - {err_type}: {err}")

        # write error to file is label method is prior (first iteration)
        if args.label_method == "prior":
            message = {"message": f"{err_type}: {err}"}

            fp = get_project_path(args.project_id) / "error.json"
            with open(fp, 'w') as f:
                json.dump(message, f)

        # raise the error for full traceback
        raise err
Exemplo n.º 3
0
def api_init_model_ready(project_id):  # noqa: F401
    """Check if trained model is available
    """

    error_path = get_project_path(project_id) / "error.json"
    if error_path.exists():
        print("error on training")
        with open(error_path, "r") as f:
            error_message = json.load(f)
        return jsonify(error_message), 400

    if get_proba_path(project_id).exists():
        logging.info("Model trained - go to review screen")

        # read the file with project info
        with open(get_project_file_path(project_id), "r") as fp:
            project_info = json.load(fp)

        project_info["projectInitReady"] = True

        # update the file with project info
        with open(get_project_file_path(project_id), "w") as fp:
            json.dump(project_info, fp)

        response = jsonify({'status': 1})
    else:
        response = jsonify({'status': 0})

    response.headers.add('Access-Control-Allow-Origin', '*')
    return response
Exemplo n.º 4
0
def export_project(project_id):
    """Export the project file.

    The ASReview project file is a file with .asreview extension.
    The ASReview project file is a zipped file and contains
    all information to continue working on the project as well
    as the orginal dataset.
    """

    # create a temp folder to zip
    tmpdir = tempfile.TemporaryDirectory()

    # copy the source tree, but ignore pickle files
    shutil.copytree(get_project_path(project_id),
                    Path(tmpdir.name, project_id),
                    ignore=shutil.ignore_patterns('*.pickle'))

    # create the archive
    shutil.make_archive(Path(tmpdir.name, project_id),
                        "zip",
                        root_dir=Path(tmpdir.name, project_id))

    # return the project file to the user
    return send_file(str(Path(tmpdir.name, f"{project_id}.zip")),
                     as_attachment=True,
                     attachment_filename=f"{project_id}.asreview",
                     cache_timeout=0)
Exemplo n.º 5
0
def update_project_info(project_id,
                        project_name=None,
                        project_description=None,
                        project_authors=None):
    '''Update project info'''

    project_id_new = re.sub('[^A-Za-z0-9]+', '-', project_name).lower()

    if not project_id_new and not isinstance(project_id_new, str) \
            and len(project_id_new) >= 3:
        raise ValueError("Project name should be at least 3 characters.")

    if (project_id != project_id_new) & is_project(project_id_new):
        raise ValueError("Project name already exists.")

    try:

        # read the file with project info
        with open(get_project_file_path(project_id), "r") as fp:
            project_info = json.load(fp)

        project_info["id"] = project_id_new
        project_info["name"] = project_name
        project_info["authors"] = project_authors
        project_info["description"] = project_description

        # # backwards support <0.10
        # if "projectInitReady" not in project_info:
        #     project_info["projectInitReady"] = True

        # update the file with project info
        with open(get_project_file_path(project_id), "w") as fp:
            json.dump(project_info, fp)

        # rename the folder
        get_project_path(project_id) \
            .rename(Path(asreview_path(), project_id_new))

    except Exception as err:
        raise err

    return project_info["id"]
Exemplo n.º 6
0
def import_project_file(file_name):
    """Import .asreview project file"""

    try:
        # Unzip the project file
        with zipfile.ZipFile(file_name, "r") as zip_obj:
            zip_filenames = zip_obj.namelist()

            # raise error if no ASReview project file
            if "project.json" not in zip_filenames:
                raise ValueError("File doesn't contain valid project format.")

            # extract all files to a temporary folder
            tmpdir = tempfile.mkdtemp()
            zip_obj.extractall(path=tmpdir)

    except zipfile.BadZipFile:
        raise ValueError("File is not an ASReview file.")

    try:
        # Open the project file and check the id. The id needs to be
        # unique, otherwise it is exended with -copy.
        import_project = None
        fp = Path(tmpdir, "project.json")
        with open(fp, "r+") as f:

            # load the project info in scope of function
            import_project = json.load(f)

            # If the uploaded project already exists,
            # then overwrite project.json with a copy suffix.
            while is_project(import_project["id"]):
                # project update
                import_project["id"] = f"{import_project['id']}-copy"
                import_project["name"] = f"{import_project['name']} copy"
            else:
                # write to file
                f.seek(0)
                json.dump(import_project, f)
                f.truncate()

        # location to copy file to
        fp_copy = get_project_path(import_project["id"])
        # Move the project from the temp folder to the projects folder.
        os.replace(tmpdir, fp_copy)

    except Exception:
        # Unknown error.
        raise ValueError(
            "Failed to import project "
            f"'{file_name.filename}'."
        )

    return import_project["id"]
Exemplo n.º 7
0
def api_update_project_info(project_id):  # noqa: F401
    """Get info on the article"""

    logging.info("Update project info")

    project_name = request.form['name']
    project_description = request.form['description']
    project_authors = request.form['authors']

    project_id_new = re.sub('[^A-Za-z0-9]+', '-', project_name).lower()

    try:

        # read the file with project info
        with open(get_project_file_path(project_id), "r") as fp:
            project_info = json.load(fp)

        project_info["id"] = project_id_new
        project_info["name"] = project_name
        project_info["authors"] = project_authors
        project_info["description"] = project_description

        # # backwards support <0.10
        # if "projectInitReady" not in project_info:
        #     project_info["projectInitReady"] = True

        # update the file with project info
        with open(get_project_file_path(project_id), "w") as fp:
            json.dump(project_info, fp)

        # rename the folder
        get_project_path(project_id) \
            .rename(Path(asreview_path(), project_id_new))

    except Exception as err:
        logging.error(err)
        response = jsonify(message="project-update-failure")

        return response, 500

    return api_get_project_info(project_id_new)
Exemplo n.º 8
0
def init_project(project_id,
                 project_name=None,
                 project_description=None,
                 project_authors=None):
    """Initialize the necessary files specific to the web app."""

    if not project_id and not isinstance(project_id, str) \
            and len(project_id) >= 3:
        raise ValueError("Project name should be at least 3 characters.")

    if is_project(project_id):
        raise ValueError("Project already exists.")

    try:
        get_project_path(project_id).mkdir()
        get_data_path(project_id).mkdir()

        project_config = {
            'version': asreview_version,  # todo: Fail without git?
            'id': project_id,
            'name': project_name,
            'description': project_description,
            'authors': project_authors,
            'created_at_unix': int(time.time()),

            # project related variables
            'projectInitReady': False,
            'reviewFinished': False,
        }

        # create a file with project info
        with open(get_project_file_path(project_id), "w") as fp:
            json.dump(project_config, fp)

        return project_config

    except Exception as err:
        # remove all generated folders and raise error
        shutil.rmtree(get_project_path())
        raise err
Exemplo n.º 9
0
def export_project(project_id):
    """Export a zipped project file"""

    tmpdir = tempfile.TemporaryDirectory()

    shutil.make_archive(Path(tmpdir.name, f"export_{project_id}"), "zip",
                        get_project_path(project_id))
    fp_tmp_export = Path(tmpdir.name, f"export_{project_id}.zip")

    return send_file(fp_tmp_export,
                     as_attachment=True,
                     attachment_filename=f"{project_id}.asreview",
                     cache_timeout=0)
Exemplo n.º 10
0
def update_project_info(project_id,
                        project_name=None,
                        project_description=None,
                        project_authors=None):
    '''Update project info'''

    project_id_new = create_project_id(project_name)

    if (project_id != project_id_new) & is_project(project_id_new):
        raise ValueError("Project name already exists.")

    try:

        # read the file with project info
        with open(get_project_file_path(project_id), "r") as fp:
            project_info = json.load(fp)

        project_info["id"] = project_id_new
        project_info["name"] = project_name
        project_info["authors"] = project_authors
        project_info["description"] = project_description

        # # backwards support <0.10
        # if "projectInitReady" not in project_info:
        #     project_info["projectInitReady"] = True

        # update the file with project info
        with open(get_project_file_path(project_id), "w") as fp:
            json.dump(project_info, fp)

        # rename the folder
        get_project_path(project_id) \
            .rename(Path(asreview_path(), project_id_new))

    except Exception as err:
        raise err

    return project_info["id"]
Exemplo n.º 11
0
def clean_project_tmp_files(project_id):
    """Clean temporary files in a project.

    Arguments
    ---------
    project_id: str
        The id of the current project.
    """
    project_path = get_project_path(project_id)

    # clean pickle files
    for f_pickle in project_path.rglob("*.pickle"):
        try:
            os.remove(f_pickle)
        except OSError as e:
            print(f"Error: {f_pickle} : {e.strerror}")
Exemplo n.º 12
0
def api_clear_model_error(project_id):
    """Clear model training error"""

    error_path = get_project_path(project_id) / "error.json"
    state_path = get_state_path(project_id)

    if error_path.exists() and state_path.exists():
        os.remove(error_path)
        os.remove(state_path)

        response = jsonify({'success': True})
        response.headers.add('Access-Control-Allow-Origin', '*')
        return response

    response = jsonify(message="Failed to clear model training error.")
    return response, 500
Exemplo n.º 13
0
def export_project(project_id):
    """Export a zipped project file"""

    Path(asreview_path(), "tmp").mkdir(exist_ok=True)
    shutil.make_archive(
        Path(asreview_path(), f"tmp/export_{project_id}"),
        "zip", 
        get_project_path(project_id)
    )
    fp_tmp_export = Path(asreview_path(), f"tmp/export_{project_id}.zip")

    return send_file(
        fp_tmp_export,
        as_attachment=True,
        attachment_filename=f"{project_id}.asreview.zip",
        cache_timeout=0
    )
Exemplo n.º 14
0
def read_proba_legacy(project_id):
    """Read a project <0.15 proba values"""

    # get the old json project file path
    proba_fp = Path(get_project_path(project_id), "proba.json")

    with open(proba_fp, "r") as f:

        # read the JSON file and make a list of the proba's
        proba = json.load(f)
        proba = [float(x) for x in proba]

    # make a dataframe that looks like the new structure
    as_data = read_data(project_id)
    proba = pd.DataFrame({"proba": [float(x) for x in proba]},
                         index=as_data.record_ids)
    proba.index.name = "record_id"
    return proba
Exemplo n.º 15
0
def api_delete_project(project_id):  # noqa: F401
    """Get info on the article"""

    # some checks to check if there is a project to delete
    if project_id == "" or project_id is None:
        response = jsonify(message="project-delete-failure")
        return response, 500

    project_path = get_project_path(project_id)

    if project_path.exists() and project_path.is_dir():
        shutil.rmtree(project_path)

        response = jsonify({'success': True})
        response.headers.add('Access-Control-Allow-Origin', '*')
        return response

    response = jsonify(message="project-delete-failure")
    return response, 500
Exemplo n.º 16
0
def is_project(project_id):

    if get_project_path(project_id).exists():
        return True

    return False
Exemplo n.º 17
0
def api_import_project():
    """Import uploaded project"""

    # raise error if file not given
    if 'file' not in request.files:
        response = jsonify(message="No file found to upload.")
        return response, 400

    # import project id
    import_project = None

    # set the project file
    project_file = request.files['file']

    try:

        with zipfile.ZipFile(project_file, "r") as zip_obj:
            zip_filenames = zip_obj.namelist()

            # raise error if no ASReview project file
            if "project.json" not in zip_filenames:
                response = jsonify(
                    message="File doesn't contain valid project format.")
                return response, 404

            # extract all files to a temporary folder
            tmpdir = tempfile.TemporaryDirectory()
            zip_obj.extractall(path=tmpdir.name)

            # Open the project file and check the id. The id needs to be
            # unique, otherwise it is exended with -copy.
            fp = Path(tmpdir.name, "project.json")
            with open(fp, "r+") as f:

                # load the project info in scope of function
                import_project = json.load(f)

                # If the uploaded project already exists,
                # then overwrite project.json with a copy suffix.
                while is_project(import_project["id"]):

                    # project update
                    import_project["id"] = f"{import_project['id']}-copy"
                    import_project["name"] = f"{import_project['name']} copy"

                else:
                    # write to file
                    f.seek(0)
                    json.dump(import_project, f)
                    f.truncate()

    except Exception as err:
        # Unknown error.
        logging.error(err)
        response = jsonify(message="Unknown error when uploading project "
                           f"'{project_file.filename}'.")
        return response, 400

    # location to copy file to
    fp_copy = get_project_path(import_project["id"])

    try:
        # Move the project from the temp folder to the projects folder.
        os.rename(tmpdir.name, fp_copy)

    except Exception as err:
        logging.error(err)
        response = jsonify(message=f"Failed to copy project to {fp_copy}.")
        return response, 400

    # return the project info in the same format as project_info
    return api_get_project_info(import_project["id"])