def test_with_family_str(self): """ expect "Method revision name and family name" """ family = MethodFamily(name="Example") method = Method(revision_name="rounded", revision_number=3, family=family) self.assertEqual(str(method), "Example:3 (rounded)")
def pipeline_add(request, id=None): """ Creates a new Pipeline belonging to an existing PipelineFamily. """ t = loader.get_template('pipeline/pipeline.html') method_families = MethodFamily.filter_by_user(request.user).order_by('name') # Retrieve this pipeline from database. four_oh_four = False try: family = PipelineFamily.objects.get(pk=id) if not family.can_be_accessed(request.user): four_oh_four = True except PipelineFamily.DoesNotExist: four_oh_four = True if four_oh_four: raise Http404("ID {} cannot be accessed".format(id)) family_users_allowed = [x.pk for x in family.users_allowed.all()] family_groups_allowed = [x.pk for x in family.groups_allowed.all()] acf = metadata.forms.AccessControlForm( initial={ "permissions": [family_users_allowed, family_groups_allowed] } ) c = { "family": family, "method_families": method_families, "compound_datatypes": _get_compound_datatypes(request), "access_control_form": acf } return HttpResponse(t.render(c, request))
def pipeline_add(request, id=None): """ Creates a new Pipeline belonging to an existing PipelineFamily. """ t = loader.get_template('pipeline/pipeline.html') method_families = MethodFamily.filter_by_user( request.user).order_by('name') # Retrieve this pipeline from database. four_oh_four = False try: family = PipelineFamily.objects.get(pk=id) if not family.can_be_accessed(request.user): four_oh_four = True except PipelineFamily.DoesNotExist: four_oh_four = True if four_oh_four: raise Http404("ID {} cannot be accessed".format(id)) family_users_allowed = [x.pk for x in family.users_allowed.all()] family_groups_allowed = [x.pk for x in family.groups_allowed.all()] acf = metadata.forms.AccessControlForm( initial={"permissions": [family_users_allowed, family_groups_allowed]}) c = { "family": family, "method_families": method_families, "compound_datatypes": _get_compound_datatypes(request), "access_control_form": acf } return HttpResponse(t.render(c, request))
def setUp(self): patcher = mocked_relations(Method, MethodDependency, Transformation) patcher.start() self.addCleanup(patcher.stop) driver = CodeResourceRevision( coderesource=CodeResource(filename='driver.py')) self.method = Method(driver=driver, family=MethodFamily()) self.dependency = self.add_dependency('helper.py')
def test_no_outputs_checkOutputIndices_good(self): """Test output index check, one well-indexed output case.""" driver = CodeResourceRevision(coderesource=CodeResource()) foo = Method(driver=driver, family=MethodFamily()) foo.check_output_indices() foo.clean()
def method_add(request, pk): """ Generate/validate/process forms for adding a Method to an existing MethodFamily. Allows for an arbitrary number of input and output forms. [pk] : primary key of the MethodFamily that this Method is being added to. """ this_family = MethodFamily.check_accessible(pk, request.user) return _method_creation_helper(request, method_family=this_family)
def method_add(request, pk): """ Generate/validate/process forms for adding a Method to an existing MethodFamily. Allows for an arbitrary number of input and output forms. [pk] : primary key of the MethodFamily that this Method is being added to. """ this_family = MethodFamily.check_accessible(pk, request.user) return _method_creation_helper(request, method_family=this_family)
def test_one_valid_output_checkOutputIndices_good(self): """Test output index check, one well-indexed output case.""" driver = CodeResourceRevision(coderesource=CodeResource()) foo = Method(driver=driver, family=MethodFamily()) out = foo.outputs.create(dataset_idx=1) out.transformationoutput = out foo.check_output_indices() foo.clean()
def test_many_valid_outputs_scrambled_checkOutputIndices_good(self): """Test output index check, well-indexed multi-output (scrambled order) case.""" driver = CodeResourceRevision(coderesource=CodeResource()) foo = Method(driver=driver, family=MethodFamily()) for i in (3, 1, 2): out = foo.outputs.create(dataset_idx=i) out.transformationoutput = out foo.check_output_indices() foo.clean()
def test_no_inputs_checkInputIndices_good(self): """ Method with no inputs defined should have check_input_indices() return with no exception. """ driver = CodeResourceRevision(coderesource=CodeResource()) foo = Method(driver=driver, family=MethodFamily()) # check_input_indices() should not raise a ValidationError foo.check_input_indices() foo.clean()
def pipeline_new(request): """ Most of the heavy lifting is done by JavaScript and HTML5. I don't think we need to use forms here. """ t = loader.get_template('pipeline/pipeline.html') method_families = MethodFamily.filter_by_user(request.user).order_by('name') acf = metadata.forms.AccessControlForm() c = { 'method_families': method_families, 'compound_datatypes': _get_compound_datatypes(request), "access_control_form": acf } return HttpResponse(t.render(c, request))
def setUp(self): patcher = mocked_relations(Method, MethodFamily, Transformation) patcher.start() self.addCleanup(patcher.stop) self.family = MethodFamily() self.old_method = self.family.members.create(family=self.family, revision_number=1, id=101) self.old_method.method = self.old_method self.new_method = self.family.members.create(family=self.family, revision_number=2, id=102) self.new_method.method = self.new_method
def test_single_valid_input_checkInputIndices_good(self): """ Method with a single, 1-indexed input should have check_input_indices() return with no exception. """ driver = CodeResourceRevision(coderesource=CodeResource()) foo = Method(driver=driver, family=MethodFamily()) inp = foo.inputs.create(dataset_idx=1) inp.transformationinput = inp # check_input_indices() should not raise a ValidationError foo.check_input_indices() foo.clean()
def pipeline_new(request): """ Most of the heavy lifting is done by JavaScript and HTML5. I don't think we need to use forms here. """ t = loader.get_template('pipeline/pipeline.html') method_families = MethodFamily.filter_by_user( request.user).order_by('name') acf = metadata.forms.AccessControlForm() c = { 'method_families': method_families, 'compound_datatypes': _get_compound_datatypes(request), "access_control_form": acf } return HttpResponse(t.render(c, request))
def test_many_ordered_valid_inputs_checkInputIndices_good(self): """ Test check_input_indices on a method with several inputs, correctly indexed and in order. """ driver = CodeResourceRevision(coderesource=CodeResource()) foo = Method(driver=driver, family=MethodFamily()) for i in range(3): inp = foo.inputs.create(dataset_idx=i + 1) inp.transformationinput = inp # check_input_indices() should not raise a ValidationError foo.check_input_indices() foo.clean()
def pipeline_revise(request, id): """ Make a new Pipeline based on the one specified by id. Use an AJAX transaction to load the actual Pipeline object from the database to front-end to render as HTML5 Canvas objects. """ t = loader.get_template('pipeline/pipeline.html') method_families = MethodFamily.filter_by_user( request.user).order_by('name') # Retrieve this pipeline from database. four_oh_four = False try: parent_revision = Pipeline.objects.get(pk=id) if not parent_revision.can_be_accessed(request.user): four_oh_four = True except Pipeline.DoesNotExist: four_oh_four = True if four_oh_four: raise Http404("ID {} cannot be accessed".format(id)) parent_users_allowed = [ x.username for x in parent_revision.users_allowed.all() ] parent_groups_allowed = [ x.name for x in parent_revision.groups_allowed.all() ] acf = metadata.forms.AccessControlForm( initial={"permissions": [parent_users_allowed, parent_groups_allowed]}) parent_revision_json = json.dumps( PipelineSerializer(parent_revision, context={ "request": request }).data) c = { "family": parent_revision.family, "parent_revision": parent_revision, "parent_revision_json": parent_revision_json, "method_families": method_families, "compound_datatypes": _get_compound_datatypes(request), "access_control_form": acf } return HttpResponse(t.render(c, request))
def pipeline_revise(request, id): """ Make a new Pipeline based on the one specified by id. Use an AJAX transaction to load the actual Pipeline object from the database to front-end to render as HTML5 Canvas objects. """ t = loader.get_template('pipeline/pipeline.html') method_families = MethodFamily.filter_by_user(request.user).order_by('name') # Retrieve this pipeline from database. four_oh_four = False try: parent_revision = Pipeline.objects.get(pk=id) if not parent_revision.can_be_accessed(request.user): four_oh_four = True except Pipeline.DoesNotExist: four_oh_four = True if four_oh_four: raise Http404("ID {} cannot be accessed".format(id)) parent_users_allowed = [x.username for x in parent_revision.users_allowed.all()] parent_groups_allowed = [x.name for x in parent_revision.groups_allowed.all()] acf = metadata.forms.AccessControlForm( initial={ "permissions": [parent_users_allowed, parent_groups_allowed] } ) parent_revision_json = json.dumps( PipelineSerializer( parent_revision, context={"request": request} ).data ) c = { "family": parent_revision.family, "parent_revision": parent_revision, "parent_revision_json": parent_revision_json, "method_families": method_families, "compound_datatypes": _get_compound_datatypes(request), "access_control_form": acf } return HttpResponse(t.render(c, request))
def methods(request, pk): """ Display a list of all Methods within a given MethodFamily. """ family = MethodFamily.check_accessible(pk, request.user) addable_users, addable_groups = family.other_users_groups() if request.method == 'POST': # We are attempting to update the MethodFamily's metadata/permissions. mf_form = MethodFamilyForm( request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=family ) if mf_form.is_valid(): try: family.name = mf_form.cleaned_data["name"] family.description = mf_form.cleaned_data["description"] family.save() family.grant_from_json(mf_form.cleaned_data["permissions"]) family.clean() # Success -- go back to the resources page. return HttpResponseRedirect('/method_families') except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) mf_form.add_error(None, e) else: mf_form = MethodFamilyForm( addable_users=addable_users, addable_groups=addable_groups, initial={"name": family.name, "description": family.description} ) t = loader.get_template('method/methods.html') c = { "family": family, "family_form": mf_form, "is_admin": admin_check(request.user), "is_owner": request.user == family.user } return HttpResponse(t.render(c, request))
def setUp(self): super(MethodViewMockTests, self).setUp() patcher = mocked_relations(KiveUser, MethodFamily, Method, CodeResource, CodeResourceRevision, CompoundDatatype, ContainerFamily, Container, Transformation, TransformationInput, TransformationOutput, User, Group) patcher.start() self.addCleanup(patcher.stop) # noinspection PyUnresolvedReferences patcher = patch.object(MethodFamily._meta, 'default_manager', MethodFamily.objects) patcher.start() self.addCleanup(patcher.stop) self.client = self.create_client() self.dev_group = Group(pk=groups.DEVELOPERS_PK) self.everyone = Group(pk=groups.EVERYONE_PK) Group.objects.add(self.dev_group, self.everyone) self.user = kive_user() self.user.groups.add(self.dev_group) self.other_user = User(pk=5) self.method_family = MethodFamily(pk='99', user=self.user) MethodFamily.objects.add(self.method_family) self.driver = CodeResourceRevision(user=self.user) self.driver.pk = 1337 # needed for viewing a method self.driver.coderesource = CodeResource() self.method = Method(pk='199', user=self.user) self.method.driver = self.driver self.method.family = self.method_family Method.objects.add(self.method) KiveUser.objects.add(KiveUser(pk=users.KIVE_USER_PK))
def test_one_invalid_output_checkOutputIndices_bad(self): """Test output index check, one badly-indexed output case.""" driver = CodeResourceRevision(coderesource=CodeResource()) foo = Method(driver=driver, family=MethodFamily()) out = foo.outputs.create(dataset_idx=4) out.transformationoutput = out self.assertRaisesRegexp( ValidationError, "Outputs are not consecutively numbered starting from 1", foo.check_output_indices) self.assertRaisesRegexp( ValidationError, "Outputs are not consecutively numbered starting from 1", foo.clean)
def methods(request, pk): """ Display a list of all Methods within a given MethodFamily. """ family = MethodFamily.check_accessible(pk, request.user) addable_users, addable_groups = family.other_users_groups() if request.method == 'POST': # We are attempting to update the MethodFamily's metadata/permissions. mf_form = MethodFamilyForm(request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=family) if mf_form.is_valid(): try: family.name = mf_form.cleaned_data["name"] family.description = mf_form.cleaned_data["description"] family.save() family.grant_from_json(mf_form.cleaned_data["permissions"]) family.clean() # Success -- go back to the resources page. return HttpResponseRedirect('/method_families') except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) mf_form.add_error(None, e) else: mf_form = MethodFamilyForm(addable_users=addable_users, addable_groups=addable_groups, initial={ "name": family.name, "description": family.description }) t = loader.get_template('method/methods.html') c = { "family": family, "family_form": mf_form, "is_admin": admin_check(request.user), "is_owner": request.user == family.user } return HttpResponse(t.render(c, request))
def __init__(self, *args, **kwargs): super(MethodSerializer, self).__init__(*args, **kwargs) request = self.context.get("request") if request is not None: curr_user = request.user # Set the querysets of the related model fields. revision_parent_field = self.fields["revision_parent"] revision_parent_field.queryset = Method.filter_by_user(curr_user) family_field = self.fields["family"] family_field.queryset = MethodFamily.filter_by_user(curr_user) driver_field = self.fields["driver"] driver_field.queryset = CodeResourceRevision.filter_by_user( curr_user) docker_field = self.fields["docker_image"] docker_field.queryset = DockerImage.filter_by_user(curr_user)
def test_many_nonconsective_inputs_scrambled_checkInputIndices_bad(self): """Test input index check, badly-indexed multi-input case.""" driver = CodeResourceRevision(coderesource=CodeResource()) foo = Method(driver=driver, family=MethodFamily()) for i in (2, 6, 1): inp = foo.inputs.create(dataset_idx=i) inp.transformationinput = inp self.assertRaisesRegexp( ValidationError, "Inputs are not consecutively numbered starting from 1", foo.check_input_indices) self.assertRaisesRegexp( ValidationError, "Inputs are not consecutively numbered starting from 1", foo.clean)
def test_one_invalid_input_checkInputIndices_bad(self): """ Test input index check, one badly-indexed input case. """ driver = CodeResourceRevision(coderesource=CodeResource()) foo = Method(driver=driver, family=MethodFamily()) inp = foo.inputs.create(dataset_idx=4) inp.transformationinput = inp # check_input_indices() should raise a ValidationError self.assertRaisesRegexp( ValidationError, "Inputs are not consecutively numbered starting from 1", foo.check_input_indices) self.assertRaisesRegexp( ValidationError, "Inputs are not consecutively numbered starting from 1", foo.clean)
def create_method_forms(request_post, user, family=None): """ Helper function for method_add() that creates Forms from the provided information and validates them. """ query_dict = request_post.dict() if 'name' in query_dict: assert family is None family = MethodFamily(user=user) family_form = MethodFamilyForm(request_post, instance=family) else: assert family is not None family_form = MethodFamilyForm( { "name": family.name, "description": family.description }, instance=family) family_form.is_valid() # Populate main form with submitted values. if "coderesource" in query_dict: method_form = MethodForm(request_post, user=user) else: method_form = MethodReviseForm(request_post) method_form.is_valid() # Determine whether the confirm_shebang button has been clicked. # NOTE: confirm_shebang is a checkbox html element; according to HTML spec, it will only # be present iff its true. ==> we cannot rely on it being present, and set the value # to false if it is absent. has_override = (request_post.get("confirm_shebang", 'off') == 'on') # NOTE: for shebang_val, we must differentiate between yes, no and undefined missing_shebang = _get_shebang_code(method_form) == SHEBANG_NO show_shebang_field = query_dict["SHOW_SHEBANG_FIELD"] = missing_shebang query_dict["SHEBANG_OK"] = (not missing_shebang or has_override) etxt = """The code resource should be executable, which means that the file usually starts with a shebang: '#!'. The currently selected code resource does not. If you know what you are doing, you can override this requirement here.""" if show_shebang_field and not has_override: method_form.add_error("confirm_shebang", etxt) # Populate in/output forms with submitted values. input_forms = [] output_forms = [] for xput_type, formlst in [("in", input_forms), ("out", output_forms)]: num_forms = sum( k.startswith('dataset_name_{}_'.format(xput_type)) for k in query_dict) for i in range(num_forms): auto_id = "id_%s_{}_{}".format(xput_type, i) t_form = TransformationXputForm( { 'dataset_name': query_dict['dataset_name_{}_{}'.format(xput_type, i)] }, auto_id=auto_id) t_form.is_valid() xs_form = XputStructureForm( { 'compounddatatype': query_dict['compounddatatype_{}_{}'.format(xput_type, i)], 'min_row': query_dict['min_row_{}_{}'.format(xput_type, i)], 'max_row': query_dict['max_row_{}_{}'.format(xput_type, i)] }, user=user, auto_id=auto_id) xs_form.is_valid() formlst.append((t_form, xs_form)) dep_forms = _make_dep_forms(request_post.dict(), user) # the methods must have at least one input and output each. if len(input_forms) == 0: tx_form = TransformationXputForm(auto_id='id_%s_in_0') xs_form = XputStructureForm(user=user, auto_id='id_%s_in_0') input_forms.append((tx_form, xs_form)) if len(output_forms) == 0: tx_form = TransformationXputForm(auto_id='id_%s_out_0') xs_form = XputStructureForm(user=user, auto_id='id_%s_out_0') output_forms.append((tx_form, xs_form)) return family_form, method_form, dep_forms, input_forms, output_forms, query_dict