コード例 #1
0
def test_get_submission_by_name(session_scope_module):
    submission = get_submission_by_name(session_scope_module, 'iris_test',
                                        'test_user', 'starting_kit')
    assert isinstance(submission, Submission)
    assert submission.basename == 'submission_000000001'
    assert os.path.exists(os.path.join(submission.path, 'classifier.py'))
    assert submission.state == 'trained'
コード例 #2
0
def test_add_submission_create_new_submission(base_db):
    # check that we can make a new submission to the database
    # it will require to have already a team and an event
    session = base_db
    config = ramp_config_template()
    event_name, username = _setup_sign_up(session)
    ramp_config = generate_ramp_config(read_config(config))

    submission_name = 'random_forest_10_10'
    path_submission = os.path.join(
        os.path.dirname(ramp_config['ramp_sandbox_dir']), submission_name)
    add_submission(session, event_name, username, submission_name,
                   path_submission)
    all_submissions = get_submissions(session, event_name, None)
    # check that the submissions have been copied
    for sub_id, _, _ in all_submissions:
        sub = get_submission_by_id(session, sub_id)
        assert os.path.exists(sub.path)
        assert os.path.exists(os.path.join(sub.path, 'classifier.py'))

    # `sign_up_team` make a submission (sandbox) by user. This submission will
    # be the third submission.
    assert len(all_submissions) == 3
    # check that the number of submissions for an event was updated
    event = session.query(Event).filter(Event.name == event_name).one_or_none()
    assert event.n_submissions == 1
    submission = get_submission_by_name(session, event_name, username,
                                        submission_name)
    assert submission.name == submission_name
    submission_file = submission.files[0]
    assert submission_file.name == 'classifier'
    assert submission_file.extension == 'py'
    assert (os.path.join('submission_000000005', 'classifier.py')
            in submission_file.path)
コード例 #3
0
def test_add_submission_create_new_submission(base_db):
    # check that we can make a new submission to the database
    # it will require to have already a team and an event
    session = base_db
    config = read_config(ramp_config_template())
    event_name, username = _setup_sign_up(session, config)
    ramp_config = generate_ramp_config(config)

    submission_name = 'random_forest_10_10'
    path_submission = os.path.join(
        os.path.dirname(ramp_config['ramp_sandbox_dir']), submission_name)
    add_submission(session, event_name, username, submission_name,
                   path_submission)
    all_submissions = get_submissions(session, event_name, None)

    # `sign_up_team` make a submission (sandbox) by user. This submission will
    # be the third submission.
    assert len(all_submissions) == 3
    submission = get_submission_by_name(session, event_name, username,
                                        submission_name)
    assert submission.name == submission_name
    submission_file = submission.files[0]
    assert submission_file.name == 'classifier'
    assert submission_file.extension == 'py'
    assert (os.path.join('submission_000000005', 'classifier.py')
            in submission_file.path)
コード例 #4
0
ファイル: test_ramp.py プロジェクト: kegl/ramp-board
def test_sandbox_upload_file(client_session, makedrop_event, submission_dir,
                             filename):
    client, session = client_session
    sign_up_team(session, "iris_test_4event", "test_user")

    config = ramp_config_template()
    ramp_config = generate_ramp_config(read_config(config))

    # upload file in sandbox.html
    path_submissions = os.path.join(ramp_config["ramp_kit_dir"],
                                    submission_dir)

    with login_scope(client, "test_user", "test") as client:
        rv = client.get("http://localhost/events/iris_test_4event/sandbox")
        assert rv.status_code == 200

        # choose file and check if it was uploaded correctly
        path_submission = os.path.join(path_submissions, filename)
        assert os.path.isfile(path_submission)

        rv = client.post(
            "http://localhost/events/iris_test_4event/sandbox",
            headers={
                "Referer": "http://localhost/events/iris_test_4event/sandbox"
            },
            data={"file": (open(path_submission, "rb"), filename)},
            follow_redirects=False,
        )

        assert rv.status_code == 302
        assert (
            rv.location == "http://localhost/events/iris_test_4event/sandbox")

        # code of the saved file
        with open(path_submission, "r") as file:
            submitted_data = file.read()

        # code from the db
        event = get_event(session, "iris_test_4event")
        sandbox_submission = get_submission_by_name(session,
                                                    "iris_test_4event",
                                                    "test_user",
                                                    event.ramp_sandbox_name)
        submission_code = sandbox_submission.files[-1].get_code()

        # get user interactions from db and check if 'upload' was added
        user_interactions = get_user_interactions_by_name(session, "test_user")

        # check if the code of the submitted file in the 'submission_code'
        assert submitted_data is not None
        assert submitted_data in submission_code
        # check if the user_interaction was added to the db
        assert "upload" in user_interactions["interaction"].values
コード例 #5
0
ファイル: test_ramp.py プロジェクト: kegl/ramp-board
def test_view_model(client_session):
    client, session = client_session

    # unknown submission
    with login_scope(client, 'test_user', 'test') as client:
        rv = client.get('/xxxxx/xx.py')
        assert rv.status_code == 302
        assert rv.location == 'http://localhost/problems'
        with client.session_transaction() as cs:
            flash_message = dict(cs['_flashes'])
        assert "Missing submission" in flash_message['message']

    submission = get_submission_by_name(session, 'iris_test', 'test_user',
                                        'random_forest_10_10')
    submission_hash = submission.hash_

    # unknown workflow element
    with login_scope(client, 'test_user', 'test') as client:
        rv = client.get('{}/{}'.format(submission_hash, 'extractor.py'))
        assert rv.status_code == 302
        assert rv.location == 'http://localhost/problems'
        with client.session_transaction() as cs:
            flash_message = dict(cs['_flashes'])
        assert "is not a valid workflow element" in flash_message['message']

    # The file does not exist on the server
    # temporary rename the file
    os.rename(submission.path, submission.path + 'xxxxx')
    try:
        with login_scope(client, 'test_user', 'test') as client:
            rv = client.get('{}/{}'.format(submission_hash, 'estimator.py'))
            assert rv.status_code == 302
            assert rv.location == 'http://localhost/problems'
            with client.session_transaction() as cs:
                flash_message = dict(cs['_flashes'])
            assert "does not exist by" in flash_message['message']
    finally:
        os.rename(submission.path + 'xxxxx', submission.path)

    # GET: normal file display
    with login_scope(client, 'test_user', 'test') as client:
        rv = client.get('{}/{}'.format(submission_hash, 'estimator.py'))
        assert rv.status_code == 200
        assert b'file = estimator.py' in rv.data
        assert (b'from sklearn.ensemble import RandomForestClassifier'
                in rv.data)
コード例 #6
0
ファイル: test_ramp.py プロジェクト: kegl/ramp-board
def test_sandbox_save_file(client_session, makedrop_event):
    client, session = client_session
    sign_up_team(session, "iris_test_4event", "test_user")

    example_code = "example content"

    with login_scope(client, "test_user", "test") as client:
        rv = client.get("http://localhost/events/iris_test_4event/sandbox")
        assert rv.status_code == 200

        rv = client.post(
            "http://localhost/events/iris_test_4event/sandbox",
            headers={
                "Referer": "http://localhost/events/iris_test_4event/sandbox"
            },
            data={
                "estimator": example_code,
                "code-csrf_token": "temp_token"
            },
            follow_redirects=False,
        )
        assert rv.status_code == 200

        # code from the db
        event = get_event(session, "iris_test_4event")
        sandbox_submission = get_submission_by_name(session,
                                                    "iris_test_4event",
                                                    "test_user",
                                                    event.ramp_sandbox_name)
        submission_code = sandbox_submission.files[-1].get_code()

        # get user interactions from db and check if 'save' was added
        user_interactions = get_user_interactions_by_name(session, "test_user")

        assert "save" in user_interactions["interaction"].values
        assert example_code in submission_code

    # make sure that after changing the code example
    # and reloading the page the code is still changed
    with login_scope(client, "test_user", "test") as client:
        rv = client.get("http://localhost/events/iris_test_4event/sandbox")
        assert rv.status_code == 200
        assert example_code.encode() in rv.data
コード例 #7
0
ファイル: test_ramp.py プロジェクト: kegl/ramp-board
def test_view_submission_error(client_session):
    client, session = client_session

    # unknown submission
    with login_scope(client, 'test_user', 'test') as client:
        rv = client.get('/xxxxx/error.txt')
        assert rv.status_code == 302
        assert rv.location == 'http://localhost/problems'
        with client.session_transaction() as cs:
            flash_message = dict(cs['_flashes'])
        assert "Missing submission" in flash_message['message']

    submission = get_submission_by_name(session, 'iris_test', 'test_user',
                                        'error')
    submission.error_msg = 'This submission is a failure'
    session.commit()
    submission_hash = submission.hash_
    # GET: normal error display
    with login_scope(client, 'test_user', 'test') as client:
        rv = client.get('{}/{}'.format(submission_hash, 'error.txt'))
        assert rv.status_code == 200
        assert b'This submission is a failure' in rv.data
コード例 #8
0
ファイル: ramp.py プロジェクト: mehdidc/ramp-board
def view_model(submission_hash, f_name):
    """Rendering submission codes using templates/submission.html.

    The code of f_name is displayed in the left panel, the list of submissions
    files is in the right panel. Clicking on a file will show that file (using
    the same template). Clicking on the name on the top will download the file
    itself (managed in the template). Clicking on "Archive" will zip all the
    submission files and download them (managed here).

    Parameters
    ----------
    submission_hash : str
        The hash_ of the submission.
    f_name : tr
        The name of the submission file.
    """
    submission = (Submission.query.filter_by(
        hash_=submission_hash).one_or_none())
    if (submission is None or not is_accessible_code(
            db.session, submission.event.name, flask_login.current_user.name,
            submission.name)):
        error_str = u'Missing submission: {}'.format(submission_hash)
        return redirect_to_user(error_str)
    event = submission.event_team.event
    team = submission.event_team.team
    workflow_element_name = f_name.split('.')[0]
    workflow_element = \
        (WorkflowElement.query.filter_by(name=workflow_element_name,
                                         workflow=event.workflow)
                              .one_or_none())
    if workflow_element is None:
        error_str = (u'{} is not a valid workflow element by {} '.format(
            workflow_element_name, flask_login.current_user.name))
        error_str += u'in {}/{}/{}/{}'.format(event, team, submission, f_name)
        return redirect_to_user(error_str)
    submission_file = \
        (SubmissionFile.query.filter_by(submission=submission,
                                        workflow_element=workflow_element)
                             .one_or_none())
    if submission_file is None:
        error_str = (u'No submission file by {} in {}/{}/{}/{}'.format(
            flask_login.current_user.name, event, team, submission, f_name))
        return redirect_to_user(error_str)

    # superfluous, perhaps when we'll have different extensions?
    f_name = submission_file.f_name

    submission_abspath = os.path.abspath(submission.path)
    if not os.path.exists(submission_abspath):
        error_str = (u'{} does not exist by {} in {}/{}/{}/{}'.format(
            submission_abspath, flask_login.current_user.name, event, team,
            submission, f_name))
        return redirect_to_user(error_str)

    if app.config['TRACK_USER_INTERACTION']:
        add_user_interaction(db.session,
                             interaction='looking at submission',
                             user=flask_login.current_user,
                             event=event,
                             submission=submission,
                             submission_file=submission_file)

    logger.info(u'{} is looking at {}/{}/{}/{}'.format(
        flask_login.current_user.name, event, team, submission, f_name))

    # Downloading file if it is not editable (e.g., external_data.csv)
    if not workflow_element.is_editable:
        # archive_filename = f_name  + '.zip'
        # with changedir(submission_abspath):
        #    with ZipFile(archive_filename, 'w') as archive:
        #        archive.write(f_name)
        if app.config['TRACK_USER_INTERACTION']:
            add_user_interaction(db.session,
                                 interaction='download',
                                 user=flask_login.current_user,
                                 event=event,
                                 submission=submission,
                                 submission_file=submission_file)

        return send_from_directory(submission_abspath,
                                   f_name,
                                   as_attachment=True,
                                   attachment_filename=u'{}_{}'.format(
                                       submission.hash_[:6], f_name),
                                   mimetype='application/octet-stream')

    # Importing selected files into sandbox
    choices = [(f, f) for f in submission.f_names]
    import_form = ImportForm()
    import_form.selected_f_names.choices = choices
    if import_form.validate_on_submit():
        sandbox_submission = get_submission_by_name(
            db.session, event.name, flask_login.current_user.name,
            event.ramp_sandbox_name)
        for filename in import_form.selected_f_names.data:
            logger.info(u'{} is importing {}/{}/{}/{}'.format(
                flask_login.current_user.name, event, team, submission,
                filename))

            # TODO: deal with different extensions of the same file
            src = os.path.join(submission.path, filename)
            dst = os.path.join(sandbox_submission.path, filename)
            shutil.copy2(src, dst)  # copying also metadata
            logger.info(u'Copying {} to {}'.format(src, dst))

            workflow_element = WorkflowElement.query.filter_by(
                name=filename.split('.')[0], workflow=event.workflow).one()
            submission_file = SubmissionFile.query.filter_by(
                submission=submission,
                workflow_element=workflow_element).one()
            if app.config['TRACK_USER_INTERACTION']:
                add_user_interaction(db.session,
                                     interaction='copy',
                                     user=flask_login.current_user,
                                     event=event,
                                     submission=submission,
                                     submission_file=submission_file)

        return redirect(u'/events/{}/sandbox'.format(event.name))

    with open(os.path.join(submission.path, f_name)) as f:
        code = f.read()
    admin = is_admin(db.session, event.name, flask_login.current_user.name)
    return render_template('submission.html',
                           event=event,
                           code=code,
                           submission=submission,
                           f_name=f_name,
                           import_form=import_form,
                           admin=admin)
コード例 #9
0
ファイル: ramp.py プロジェクト: mehdidc/ramp-board
def sandbox(event_name):
    """Landing page for the user's sandbox.

    Parameters
    ----------
    event_name : str
        The event name.
    """
    event = get_event(db.session, event_name)
    if not is_accessible_event(db.session, event_name,
                               flask_login.current_user.name):
        return redirect_to_user(u'{}: no event named "{}"'.format(
            flask_login.current_user.firstname, event_name))
    if not is_accessible_code(db.session, event_name,
                              flask_login.current_user.name):
        error_str = ('No access to sandbox for event {}. If you have '
                     'already signed up, please wait for approval.'.format(
                         event.name))
        return redirect_to_user(error_str)
    # setup the webpage when loading
    # we use the code store in the sandbox to show to the user
    sandbox_submission = get_submission_by_name(db.session, event_name,
                                                flask_login.current_user.name,
                                                event.ramp_sandbox_name)
    event_team = get_event_team_by_name(db.session, event_name,
                                        flask_login.current_user.name)
    # initialize the form for the code
    # The amount of python magic we have to do for rendering a variable
    # number of textareas, named and populated at run time, is mind
    # boggling.

    # First we need to make sure CodeForm is empty
    # for name_code in CodeForm.names_codes:
    #     name, _ = name_code
    #     delattr(CodeForm, name)
    CodeForm.names_codes = []

    # Then we create named fields in the CodeForm class for each editable
    # submission file. They have to be populated when the code_form object
    # is created, so we also create a code_form_kwargs dictionary and
    # populate it with the codes.
    code_form_kwargs = {}
    for submission_file in sandbox_submission.files:
        if submission_file.is_editable:
            f_field = submission_file.name
            setattr(CodeForm, f_field, StringField(u'Text', widget=TextArea()))
            code_form_kwargs[f_field] = submission_file.get_code()
    code_form_kwargs['prefix'] = 'code'
    code_form = CodeForm(**code_form_kwargs)
    # Then, to be able to iterate over the files in the sandbox.html
    # template, we also fill a separate table of pairs (file name, code).
    # The text areas in the template will then have to be created manually.
    for submission_file in sandbox_submission.files:
        if submission_file.is_editable:
            code_form.names_codes.append(
                (submission_file.name, submission_file.get_code()))

    # initialize the submission field and the the uploading form
    submit_form = SubmitForm(submission_name=event_team.last_submission_name,
                             prefix='submit')
    upload_form = UploadForm(prefix='upload')

    admin = is_admin(db.session, event_name, flask_login.current_user.name)
    if request.method == 'GET':
        return render_template('sandbox.html',
                               submission_names=sandbox_submission.f_names,
                               code_form=code_form,
                               submit_form=submit_form,
                               upload_form=upload_form,
                               event=event,
                               admin=admin)

    if request.method == 'POST':
        if ('code-csrf_token' in request.form
                and code_form.validate_on_submit()):
            try:
                for submission_file in sandbox_submission.files:
                    if submission_file.is_editable:
                        old_code = submission_file.get_code()
                        submission_file.set_code(
                            request.form[submission_file.name])
                        new_code = submission_file.get_code()
                        diff = '\n'.join(
                            difflib.unified_diff(old_code.splitlines(),
                                                 new_code.splitlines()))
                        similarity = difflib.SequenceMatcher(
                            a=old_code, b=new_code).ratio()
                        if app.config['TRACK_USER_INTERACTION']:
                            add_user_interaction(
                                db.session,
                                interaction='save',
                                user=flask_login.current_user,
                                event=event,
                                submission_file=submission_file,
                                diff=diff,
                                similarity=similarity)
            except Exception as e:
                return redirect_to_sandbox(event, u'Error: {}'.format(e))
            return redirect_to_sandbox(
                event,
                'You submission has been saved. You can safely comeback to '
                'your sandbox later.',
                is_error=False,
                category='File saved')

        elif request.files:
            upload_f_name = secure_filename(request.files['file'].filename)
            upload_name = upload_f_name.split('.')[0]
            # TODO: create a get_function
            upload_workflow_element = WorkflowElement.query.filter_by(
                name=upload_name, workflow=event.workflow).one_or_none()
            if upload_workflow_element is None:
                return redirect_to_sandbox(
                    event,
                    u'{} is not in the file list.'.format(upload_f_name))

            # TODO: create a get_function
            submission_file = SubmissionFile.query.filter_by(
                submission=sandbox_submission,
                workflow_element=upload_workflow_element).one()
            if submission_file.is_editable:
                old_code = submission_file.get_code()

            tmp_f_name = os.path.join(tempfile.gettempdir(), upload_f_name)
            request.files['file'].save(tmp_f_name)
            file_length = os.stat(tmp_f_name).st_size
            if (upload_workflow_element.max_size is not None
                    and file_length > upload_workflow_element.max_size):
                return redirect_to_sandbox(
                    event, u'File is too big: {} exceeds max size {}'.format(
                        file_length, upload_workflow_element.max_size))
            if submission_file.is_editable:
                try:
                    with open(tmp_f_name) as f:
                        code = f.read()
                        submission_file.set_code(code)
                except Exception as e:
                    return redirect_to_sandbox(event, u'Error: {}'.format(e))
            else:
                # non-editable files are not verified for now
                dst = os.path.join(sandbox_submission.path, upload_f_name)
                shutil.copy2(tmp_f_name, dst)
            logger.info(u'{} uploaded {} in {}'.format(
                flask_login.current_user.name, upload_f_name, event))

            if submission_file.is_editable:
                new_code = submission_file.get_code()
                diff = '\n'.join(
                    difflib.unified_diff(old_code.splitlines(),
                                         new_code.splitlines()))
                similarity = difflib.SequenceMatcher(a=old_code,
                                                     b=new_code).ratio()
                if app.config['TRACK_USER_INTERACTION']:
                    add_user_interaction(db.session,
                                         interaction='upload',
                                         user=flask_login.current_user,
                                         event=event,
                                         submission_file=submission_file,
                                         diff=diff,
                                         similarity=similarity)
            else:
                if app.config['TRACK_USER_INTERACTION']:
                    add_user_interaction(db.session,
                                         interaction='upload',
                                         user=flask_login.current_user,
                                         event=event,
                                         submission_file=submission_file)

            return redirect(request.referrer)
            # TODO: handle different extensions for the same workflow element
            # ie: now we let upload eg external_data.bla, and only fail at
            # submission, without giving a message

        elif ('submit-csrf_token' in request.form
              and submit_form.validate_on_submit()):
            new_submission_name = request.form['submit-submission_name']
            if not 4 < len(new_submission_name) < 20:
                return redirect_to_sandbox(
                    event, 'Submission name should have length between 4 and '
                    '20 characters.')
            try:
                new_submission_name.encode('ascii')
            except Exception as e:
                return redirect_to_sandbox(event, u'Error: {}'.format(e))
            try:
                new_submission = add_submission(db.session, event_name,
                                                event_team.team.name,
                                                new_submission_name,
                                                sandbox_submission.path)
            except DuplicateSubmissionError:
                return redirect_to_sandbox(
                    event,
                    u'Submission {} already exists. Please change the name.'.
                    format(new_submission_name))
            except MissingExtensionError as e:
                return redirect_to_sandbox(event, 'Missing extension')
            except TooEarlySubmissionError as e:
                return redirect_to_sandbox(event, str(e))

            logger.info(u'{} submitted {} for {}.'.format(
                flask_login.current_user.name, new_submission.name,
                event_team))
            if event.is_send_submitted_mails:
                admin_users = User.query.filter_by(access_level='admin')
                for admin in admin_users:
                    subject = 'Submission {} sent for training'.format(
                        new_submission.name)
                    body = """A new submission have been submitted:
                    event: {}
                    user: {}
                    submission: {}
                    submission path: {}
                    """.format(event_team.event.name,
                               flask_login.current_user.name,
                               new_submission.name, new_submission.path)
                    send_mail(admin, subject, body)
            if app.config['TRACK_USER_INTERACTION']:
                add_user_interaction(db.session,
                                     interaction='submit',
                                     user=flask_login.current_user,
                                     event=event,
                                     submission=new_submission)

            return redirect_to_sandbox(event,
                                       u'{} submitted {} for {}'.format(
                                           flask_login.current_user.firstname,
                                           new_submission.name, event_team),
                                       is_error=False,
                                       category='Submission')

    admin = is_admin(db.session, event_name, flask_login.current_user.name)
    return render_template('sandbox.html',
                           submission_names=sandbox_submission.f_names,
                           code_form=code_form,
                           submit_form=submit_form,
                           upload_form=upload_form,
                           event=event,
                           admin=admin)