def test_create_result_event(self, mock_create_result): """Test create_result is called.""" from pybossa.core import db task = TaskFactory.create(n_answers=1) TaskRunFactory.create(task=task) conn = db.engine.connect() result_id = create_result(conn, task.project_id, task.id) result = result_repo.filter_by(project_id=task.project_id, task_id=task.id, last_version=True)[0] assert mock_create_result.called err_msg = "The result should ID should be the same" assert result_id == result.id, err_msg task.n_answers = 2 task_repo.update(task) TaskRunFactory.create(task=task) result_id = create_result(conn, task.project_id, task.id) assert mock_create_result.called result = result_repo.filter_by(project_id=task.project_id, task_id=task.id, last_version=True) assert len(result) == 1, len(result) result = result[0] err_msg = "The result should ID should be the same" assert result_id == result.id, err_msg
def _add_hateoas_links(self, item): obj = item.dictize() related = request.args.get('related') if related: if item.__class__.__name__ == 'Task': obj['task_runs'] = [] obj['result'] = None task_runs = task_repo.filter_task_runs_by(task_id=item.id) results = result_repo.filter_by(task_id=item.id, last_version=True) for tr in task_runs: obj['task_runs'].append(tr.dictize()) for r in results: obj['result'] = r.dictize() if item.__class__.__name__ == 'TaskRun': tasks = task_repo.filter_tasks_by(id=item.task_id) results = result_repo.filter_by(task_id=item.task_id, last_version=True) obj['task'] = None obj['result'] = None for t in tasks: obj['task'] = t.dictize() for r in results: obj['result'] = r.dictize() if item.__class__.__name__ == 'Result': tasks = task_repo.filter_tasks_by(id=item.task_id) task_runs = task_repo.filter_task_runs_by(task_id=item.task_id) obj['task_runs'] = [] for t in tasks: obj['task'] = t.dictize() for tr in task_runs: obj['task_runs'].append(tr.dictize()) stats = request.args.get('stats') if stats: if item.__class__.__name__ == 'Project': stats = project_stats_repo.filter_by(project_id=item.id, limit=1) obj['stats'] = stats[0].dictize() if stats else {} links, link = self.hateoas.create_links(item) if links: obj['links'] = links if link: obj['link'] = link return obj
def xml_export(short_name): """Export project results as an XML file. :param short_name: The short name of the project. """ project = project_repo.get_by_shortname(short_name) if project is None: # pragma: no cover abort(404) results = result_repo.filter_by(project_id=project.id) data = [r.info for r in results if isinstance(r.info, dict)] xml = dicttoxml.dicttoxml(data, custom_root='record-group', item_func=lambda x: 'record', attr_type=False) exporter = Exporter() name = exporter._project_name_latin_encoded(project) secure_name = secure_filename('{0}_results.xml'.format(name)) fn = "filename={0}".format(secure_name) dom = parseString(xml) pretty_xml = dom.toprettyxml() resp = make_response(pretty_xml) resp.headers["Content-Disposition"] = "attachment; {0}".format(fn) resp.headers["Content-type"] = "text/xml" resp.headers['Cache-Control'] = "no-store, no-cache, must-revalidate, \ post-check=0, pre-check=0, max-age=0" return resp
def csv_export(short_name): """Export project results as a CSV file. :param short_name: The short name of the project. """ project = project_repo.get_by_shortname(short_name) if project is None: # pragma: no cover abort(404) si = StringIO.StringIO() writer = UnicodeWriter(si) exporter = Exporter() name = exporter._project_name_latin_encoded(project) secure_name = secure_filename('{0}_{1}.csv'.format(name, 'results')) results = result_repo.filter_by(project_id=project.id) data = [] for r in results: row = {k: v for k, v in r.dictize().items()} if isinstance(row['info'], dict): # Explode info keys = row['info'].keys() for k in keys: row['info_{0}'.format(k)] = row['info'][k] data.append(row) headers = set(itertools.chain(*[row.keys() for row in data])) writer.writerow([h for h in headers]) for row in data: writer.writerow([row.get(h, '') for h in headers]) fn = "filename={0}".format(secure_name) resp = make_response(si.getvalue()) resp.headers["Content-Disposition"] = "attachment; {0}".format(fn) resp.headers["Content-type"] = "text/csv" resp.headers['Cache-Control'] = "no-store, no-cache, must-revalidate, \ post-check=0, pre-check=0, max-age=0" return resp
def _get_child_task_data(self, task_data, parent_id): """Generate tasks according to the results of a parent project.""" from pybossa.core import result_repo indexed_task_data = { row['info']['target']: row['info'] for row in task_data } rc = self._get_result_collection(parent_id) child_task_data = [] results = result_repo.filter_by(project_id=parent_id) for result in results: self._validate_parent_result(result) parent_annotations = [ a for a in rc.get_by_task_id(result.task_id) if a['motivation'] != 'commenting' ] for anno in parent_annotations: source = self._get_source(anno) data = indexed_task_data.get(source) if not data: err_msg = 'A parent annotation has an invalid target' raise BulkImportException(err_msg) data_copy = data.copy() data_copy['target'] = anno['target'] data_copy['parent_task_id'] = result.task_id child_task_data.append(data_copy) self._set_result_has_children(result) return sorted(child_task_data, key=lambda x: x['target'])
def export_results(short_name): """Export project results as an XML or CSV file. :param short_name: The short name of the project. """ project = project_repo.get_by_shortname(short_name) if project is None: # pragma: no cover abort(404) fmt = request.args.get('format') export_formats = ["xml", "csv"] if not fmt: if len(request.args) >= 1: abort(404) return redirect(url_for('.index')) results = result_repo.filter_by(project_id=project.id) if fmt not in export_formats: abort(415) elif fmt == "xml": resp = get_xml_response(results) elif fmt == "csv": resp = get_csv_response(results) exporter = Exporter() name = exporter._project_name_latin_encoded(project) secure_name = secure_filename('{0}_results.{1}'.format(name, fmt)) fn = "filename={0}".format(secure_name) resp.headers["Content-Disposition"] = "attachment; {0}".format(fn) resp.headers["Content-type"] = "text/{0}".format(fmt) resp.headers['Cache-Control'] = "no-store, no-cache, must-revalidate, \ post-check=0, pre-check=0, max-age=0" return resp
def test_get_returns_result_after_increasig_redundancy(self): """Test get method returns a result if after increasing redundancy""" n_answers = 1 task = TaskFactory.create(n_answers=n_answers) task_run = TaskRunFactory.create(task=task) result = self.result_repo.filter_by(project_id=1) err_msg = "There should be a result" assert len(result) == 1, err_msg result = result[0] assert result.project_id == 1, err_msg assert result.task_id == task.id, err_msg assert len(result.task_run_ids) == n_answers, err_msg err_msg = "The task_run id is missing in the results array" for tr_id in result.task_run_ids: assert tr_id == task_run.id, err_msg # Increase redundancy tmp = task_repo.get_task(task.id) tmp.n_answers = 2 task_repo.update(task) err_msg = "There should be only one result" results = result_repo.filter_by(project_id=1) assert len(results) == 1, err_msg task_run_2 = TaskRunFactory.create(task=task) err_msg = "There should be 1 results" results = result_repo.filter_by(project_id=1) assert len(results) == 1, err_msg err_msg = "There should be 2 results" results = result_repo.filter_by(project_id=1, last_version=False) assert len(results) == 2, err_msg assert results[1].project_id == 1, err_msg assert results[1].task_id == task.id, err_msg err_msg = "First result should have only one task run ID" assert len(results[0].task_run_ids) == 1, err_msg err_msg = "Second result should have only two task run IDs" assert len(results[1].task_run_ids) == 2, err_msg err_msg = "The task_run id is missing in the results array" for tr_id in results[1].task_run_ids: assert tr_id in [task_run.id, task_run_2.id], err_msg
def test_correct_data_written_to_xml(self): TaskRunFactory.create(project=self.project, task=self.task) result = result_repo.filter_by(project_id=self.project.id)[0] result.info = {'n': 42} result_repo.update(result) resp = self.app.get('/data/project/xml_export', follow_redirects=True) xml = ('<?xml version="1.0" encoding="UTF-8" ?><record-group>' '<record><n>42</n></record></record-group>') dom = parseString(xml) expected = dom.toprettyxml() assert resp.data == expected, resp.data
def validate_parent(project): """Validate a parent project.""" empty_results = [ r for r in result_repo.filter_by(project_id=project.id) if not r.info ] incomplete_tasks = task_repo.filter_tasks_by(state='ongoing', project_id=project.id) if empty_results or incomplete_tasks: return False return True
def test_correct_data_written_to_csv(self, mock_writer): TaskRunFactory.create(project=self.project, task=self.task) result = result_repo.filter_by(project_id=self.project.id)[0] result.info = {'n': 42} result_repo.update(result) res = self.app.get('/data/project/csv_export', follow_redirects=True) expected_headers = ['info', 'task_id', 'created', 'last_version', 'task_run_ids', 'project_id', 'id', 'info_n'] expected_row = result.dictize().values() + [42] headers = mock_writer.call_args_list[0][0][0] row = mock_writer.call_args_list[1][0][0] assert sorted(headers) == sorted(expected_headers) assert sorted(row) == sorted(expected_row)
def _add_hateoas_links(self, item): obj = item.dictize() related = request.args.get('related') if related: if item.__class__.__name__ == 'Task': obj['task_runs'] = [] obj['result'] = None task_runs = task_repo.filter_task_runs_by(task_id=item.id) results = result_repo.filter_by(task_id=item.id, last_version=True) for tr in task_runs: obj['task_runs'].append(tr.dictize()) for r in results: obj['result'] = r.dictize() if item.__class__.__name__ == 'TaskRun': tasks = task_repo.filter_tasks_by(id=item.task_id) results = result_repo.filter_by(task_id=item.task_id, last_version=True) obj['task'] = None obj['result'] = None for t in tasks: obj['task'] = t.dictize() for r in results: obj['result'] = r.dictize() if item.__class__.__name__ == 'Result': tasks = task_repo.filter_tasks_by(id=item.task_id) task_runs = task_repo.filter_task_runs_by(task_id=item.task_id) obj['task_runs'] = [] for t in tasks: obj['task'] = t.dictize() for tr in task_runs: obj['task_runs'].append(tr.dictize()) links, link = self.hateoas.create_links(item) if links: obj['links'] = links if link: obj['link'] = link return obj
def test_project_built_from_valid_parent_template(self, mock_count, mock_create_tasks): """Test that import data modified for IIIF child projects.""" self.register() user = user_repo.get(1) vol = dict(id='123abc', name='My Volume', importer='iiif', data=dict(manifest_uri=self.manifest_uri)) category = CategoryFactory() tmpl_fixtures = TemplateFixtures(category) select_task = tmpl_fixtures.iiif_select_tmpl parent_tmpl = tmpl_fixtures.create(task_tmpl=select_task) child_tmpl = tmpl_fixtures.create(task_tmpl=select_task) child_tmpl['parent_template_id'] = parent_tmpl['id'] category.info = dict(presenter='iiif-annotation', volumes=[vol], templates=[parent_tmpl, child_tmpl]) project_repo.update_category(category) parent = ProjectFactory(id=42, owner=user, category=category, info=dict(template_id=parent_tmpl['id'], volume_id=vol['id'])) n_tasks = 3 tasks = TaskFactory.create_batch(n_tasks, n_answers=1, project=parent) for task in tasks: TaskRunFactory.create(user=user, project=parent, task=task) results = result_repo.filter_by(project_id=parent.id) for result in results: result.info = 'foo' result_repo.update(result) endpoint = '/lc/projects/{}/new'.format(category.short_name) form_data = dict(name='foo', short_name='bar', template_id=child_tmpl['id'], volume_id=vol['id']) self.app_post_json(endpoint, data=form_data) expected_call = call(task_repo, 1, type='iiif-enhanced', manifest_uri=self.manifest_uri, parent_id=parent.id) assert_equal(mock_create_tasks.call_args_list, [expected_call])
def test_get_last_version(self): """Test API result returns always latest version.""" result = self.create_result() project = project_repo.get(result.project_id) task = task_repo.get_task(result.task_id) task.n_answers = 2 TaskRunFactory.create(task=task, project=project) result = result_repo.get_by(project_id=project.id) assert result.last_version is True, result.last_version result_id = result.id results = result_repo.filter_by(project_id=project.id, last_version=False) assert len(results) == 2, len(results) for r in results: if r.id == result_id: assert r.last_version is True, r.last_version else: assert r.last_version is False, r.last_version