def test_identical_when_drivers_unmatched(self): driver1 = CodeResourceRevision() driver2 = CodeResourceRevision() user = User() m1 = Method(revision_name='A', driver=driver1, user=user) for i in range(2): inp = m1.inputs.create(dataset_name='a_in_{}'.format(i), dataset_idx=i + 1) inp.transformationinput = inp for i in range(3): out = m1.outputs.create(dataset_name='a_out_{}'.format(i), dataset_idx=i + 1) out.transformationoutput = out m2 = Method(revision_name='B', driver=driver2, user=user) for i in range(2): inp = m2.inputs.create(dataset_name='b_in_{}'.format(i), dataset_idx=i + 1) inp.transformationinput = inp for i in range(3): out = m2.outputs.create(dataset_name='b_in_{}'.format(i), dataset_idx=i + 1) out.transformationoutput = out self.assertFalse(m1.is_identical(m2))
def setUp(self): super(CodeResourceViewMockTests, self).setUp() patcher = mocked_relations(KiveUser, CodeResource, CodeResourceRevision, User, Group) patcher.start() self.addCleanup(patcher.stop) # noinspection PyUnresolvedReferences patchers = [patch.object(CodeResource._meta, 'default_manager', CodeResource.objects), patch.object(CodeResourceRevision._meta, 'default_manager', CodeResource.objects)] def dummy_save(r): r.id = id(r) # noinspection PyUnresolvedReferences patchers.append(patch.object(CodeResource, 'save', dummy_save)) patcher = PatcherChain(patchers) 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.content_file = ContentFile('some text', 'existing.txt') self.code_resource = CodeResource(pk='99', user=self.user, name='existing', filename='existing.txt') self.code_resource._state.adding = False self.other_user = User(pk=5) self.other_code_resource = CodeResource(pk='150', user=self.other_user) CodeResource.objects.add(self.code_resource, self.other_code_resource) self.code_resource_revision = CodeResourceRevision( pk='199', user=self.user, content_file=self.content_file) self.code_resource_revision.coderesource = self.code_resource self.other_code_resource_revision = CodeResourceRevision( pk='200', user=self.other_user) self.other_code_resource_revision.coderesource = self.other_code_resource self.other_code_resource.revisions.add(self.other_code_resource_revision) CodeResourceRevision.objects.add(self.code_resource_revision, self.other_code_resource_revision) k = KiveUser(pk=users.KIVE_USER_PK) k.groups.add(self.dev_group) KiveUser.objects.add(k)
def __init__(self, data=None, user=None, initial=None, *args, **kwargs): super(MethodDependencyForm, self).__init__(data, initial=initial, *args, **kwargs) eligible_crs = _get_code_resource_list(user) self.fields['coderesource'].choices = eligible_crs # Re-populate drop-downs before rendering if possible. populator = None if data is not None: populator = data elif initial is not None: populator = initial if populator is not None: # Re-populate drop-downs before rendering the template. cr_pk = populator["coderesource"] # The first entry of eligible_crs is ("", "--- CodeResource ---") so we skip it. if int(cr_pk) not in [int(x[0]) for x in eligible_crs[1:]]: raise Http404( "CodeResource with ID {} used in dependency definition is invalid".format( populator["coderesource"])) rev = CodeResourceRevision.filter_by_user(user).filter(coderesource__pk=cr_pk) self.fields['revisions'].widget.choices = [ (x.pk, x.revision_name) for x in rev] if "revisions" in populator: try: assert "coderesource" in populator assert int(populator["revisions"]) in (x.pk for x in rev) except AssertionError as e: raise Http404(e)
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 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 resource_revision_add(request, pk): """ Add a code resource revision. The form will initially be populated with values of the last revision to this code resource. """ t = loader.get_template('method/resource_revision_add.html') c = {} creating_user = request.user parent_revision = CodeResourceRevision.check_accessible(pk, creating_user) coderesource = parent_revision.coderesource if request.method == 'POST': # Use forms here, just as in resource_add. Again note that entries of dep_forms may be None. revision_form = CodeResourceRevisionForm(request.POST, request.FILES) if not revision_form.is_valid(): c.update({ 'revision_form': revision_form, 'parent_revision': parent_revision, 'coderesource': coderesource }) return HttpResponse(t.render(c, request)) try: _make_crv(request.FILES.get('content_file', None), creating_user, revision_form, parent_revision=parent_revision) except ValidationError: # The forms have all been updated with the appropriate errors. c.update({ 'revision_form': revision_form, 'parent_revision': parent_revision, 'coderesource': coderesource }) return HttpResponse( t.render(c, request) ) # CodeResourceRevision object required for next steps # Success; return to the resources page. return HttpResponseRedirect('/resources') # Having reached here, we know that this CR is being revised. Return a form pre-populated # with default info. 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() ] crv_form = CodeResourceRevisionForm( initial={"permissions": [parent_users_allowed, parent_groups_allowed]}) c.update({ 'revision_form': crv_form, 'parent_revision': parent_revision, 'coderesource': coderesource }) return HttpResponse(t.render(c, request))
def resource_revision_add(request, pk): """ Add a code resource revision. The form will initially be populated with values of the last revision to this code resource. """ t = loader.get_template('method/resource_revision_add.html') c = {} creating_user = request.user parent_revision = CodeResourceRevision.check_accessible(pk, creating_user) coderesource = parent_revision.coderesource if request.method == 'POST': # Use forms here, just as in resource_add. Again note that entries of dep_forms may be None. revision_form = CodeResourceRevisionForm(request.POST, request.FILES) if not revision_form.is_valid(): c.update({ 'revision_form': revision_form, 'parent_revision': parent_revision, 'coderesource': coderesource }) return HttpResponse(t.render(c, request)) try: _make_crv(request.FILES.get('content_file', None), creating_user, revision_form, parent_revision=parent_revision) except ValidationError: # The forms have all been updated with the appropriate errors. c.update( { 'revision_form': revision_form, 'parent_revision': parent_revision, 'coderesource': coderesource }) return HttpResponse(t.render(c, request)) # CodeResourceRevision object required for next steps # Success; return to the resources page. return HttpResponseRedirect('/resources') # Having reached here, we know that this CR is being revised. Return a form pre-populated # with default info. 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()] crv_form = CodeResourceRevisionForm( initial={ "permissions": [parent_users_allowed, parent_groups_allowed] } ) c.update( { 'revision_form': crv_form, 'parent_revision': parent_revision, 'coderesource': coderesource } ) return HttpResponse(t.render(c, request))
def test_method_revise_access_denied(self): """ Hides ungranted code revisions. """ revision1 = CodeResourceRevision(pk=101, revision_name='alpha', revision_number=1, user=self.user) revision2 = CodeResourceRevision(pk=102, revision_name='beta', revision_number=2, user=self.other_user) self.driver.coderesource.revisions.add(revision1, revision2) response = self.client.get(reverse('method_revise', kwargs=dict(pk='199'))) self.assertEqual(200, response.status_code) revisions = response.context['method_form']['driver_revisions'] self.assertEqual([('101', '1: alpha')], revisions.field.widget.choices)
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 download(self, request, pk=None): """ Download the file pointed to by this CodeResourceRevision. """ accessible_revisions = CodeResourceRevision.filter_by_user(request.user) if not accessible_revisions.filter(pk=pk).exists(): return Response(None, status=status.HTTP_404_NOT_FOUND) revision = self.get_object() if not revision.content_file: return Response({"errors": "This CodeResourceRevision has no content file."}, status=status.HTTP_403_FORBIDDEN) return build_download_response(revision.content_file)
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 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 resource_revision_view(request, pk): revision = CodeResourceRevision.check_accessible(pk, request.user) addable_users, addable_groups = revision.other_users_groups() if request.method == 'POST': # We are attempting to update the CodeResourceRevision's metadata/permissions. revision_form = CodeResourceRevisionDetailsForm( request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=revision) if revision_form.is_valid(): try: revision.revision_name = revision_form.cleaned_data[ "revision_name"] revision.revision_desc = revision_form.cleaned_data[ "revision_desc"] revision.save() revision.grant_from_json( revision_form.cleaned_data["permissions"]) revision.clean() # Success -- go back to the CodeResource page. return HttpResponseRedirect('/resource_revisions/{}'.format( revision.coderesource.pk)) except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) revision_form.add_error(None, e) else: revision_form = CodeResourceRevisionDetailsForm( addable_users=addable_users, addable_groups=addable_groups, initial={ "revision_name": revision.revision_name, "revision_desc": revision.revision_desc }) t = loader.get_template("method/resource_revision_view.html") c = { "revision": revision, "revision_form": revision_form, "is_owner": revision.user == request.user, "is_admin": admin_check(request.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 resource_revision_view(request, pk): revision = CodeResourceRevision.check_accessible(pk, request.user) addable_users, addable_groups = revision.other_users_groups() if request.method == 'POST': # We are attempting to update the CodeResourceRevision's metadata/permissions. revision_form = CodeResourceRevisionDetailsForm( request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=revision ) if revision_form.is_valid(): try: revision.revision_name = revision_form.cleaned_data["revision_name"] revision.revision_desc = revision_form.cleaned_data["revision_desc"] revision.save() revision.grant_from_json(revision_form.cleaned_data["permissions"]) revision.clean() # Success -- go back to the CodeResource page. return HttpResponseRedirect('/resource_revisions/{}'.format(revision.coderesource.pk)) except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) revision_form.add_error(None, e) else: revision_form = CodeResourceRevisionDetailsForm( addable_users=addable_users, addable_groups=addable_groups, initial={ "revision_name": revision.revision_name, "revision_desc": revision.revision_desc } ) t = loader.get_template("method/resource_revision_view.html") c = { "revision": revision, "revision_form": revision_form, "is_owner": revision.user == request.user, "is_admin": admin_check(request.user) } return HttpResponse(t.render(c, request))
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 __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 __init__(self, data=None, user=None, initial=None, *args, **kwargs): super(MethodDependencyForm, self).__init__(data, initial=initial, *args, **kwargs) eligible_crs = _get_code_resource_list(user) self.fields['coderesource'].choices = eligible_crs # Re-populate drop-downs before rendering if possible. populator = None if data is not None: populator = data elif initial is not None: populator = initial if populator is not None: # Re-populate drop-downs before rendering the template. cr_pk = populator["coderesource"] # The first entry of eligible_crs is ("", "--- CodeResource ---") so we skip it. if int(cr_pk) not in [int(x[0]) for x in eligible_crs[1:]]: raise Http404( "CodeResource with ID {} used in dependency definition is invalid" .format(populator["coderesource"])) rev = CodeResourceRevision.filter_by_user(user).filter( coderesource__pk=cr_pk) self.fields['revisions'].widget.choices = [(x.pk, x.revision_name) for x in rev] if "revisions" in populator: try: assert "coderesource" in populator assert int(populator["revisions"]) in (x.pk for x in rev) except AssertionError as e: raise Http404(e)
def create(self, validated_data): """ Create a CodeResourceRevision from the validated deserialized data. Note that no cleaning occurs here. That will fall to the calling method. """ crr_data = validated_data users_allowed = crr_data.pop( "users_allowed") if "users_allowed" in crr_data else [] groups_allowed = crr_data.pop( "groups_allowed") if "groups_allowed" in crr_data else [] with transaction.atomic(): crr = CodeResourceRevision(**crr_data) crr.clean() # this sets the MD5 crr.save() crr.users_allowed.add(*users_allowed) crr.groups_allowed.add(*groups_allowed) return crr
def _make_crv(file_in_memory, creating_user, crv_form, parent_revision=None, code_resource=None): """ Helper that creates a CodeResourceRevision (and a CodeResource as well if appropriate). """ assert isinstance(crv_form, (CodeResourcePrototypeForm, CodeResourceRevisionForm)) # If parent_revision is specified, we are only making a CodeResourceRevision and not its parent CodeResource. assert not (parent_revision is None and isinstance(crv_form, CodeResourceRevision)) cr_filename = "" if file_in_memory is None else file_in_memory.name if code_resource is None and parent_revision is not None: code_resource = parent_revision.coderesource if code_resource is None: # crv_form is a CodeResourcePrototypeForm. code_resource = CodeResource( name=crv_form.cleaned_data['resource_name'], description=crv_form.cleaned_data['resource_desc'], filename=cr_filename, user=creating_user ) try: code_resource.full_clean() # Skip the clean until later; after all, we're protected by a transaction here. code_resource.save() except ValidationError as e: crv_form.add_error('content_file', e.error_dict.get('filename', [])) crv_form.add_error('resource_name', e.error_dict.get('name', [])) crv_form.add_error('resource_desc', e.error_dict.get('description', [])) raise e code_resource.grant_from_json(crv_form.cleaned_data["permissions"]) rev_name = "Prototype" rev_desc = crv_form.cleaned_data["resource_desc"] else: rev_name = crv_form.cleaned_data["revision_name"] rev_desc = crv_form.cleaned_data["revision_desc"] # Modify actual filename prior to saving revision object. if file_in_memory is not None: file_in_memory.name += '_' + datetime.now().strftime('%Y%m%d%H%M%S') revision = CodeResourceRevision( revision_parent=parent_revision, revision_name=rev_name, revision_desc=rev_desc, coderesource=code_resource, content_file=file_in_memory, user=creating_user ) # This sets the MD5. try: revision.clean() except ValidationError as e: crv_form.add_error(None, e) raise e revision.save() revision.grant_from_json(crv_form.cleaned_data["permissions"]) try: code_resource.full_clean() revision.full_clean() except ValidationError as e: crv_form.add_error(None, e) raise e return revision
def resource_revisions(request, pk): """ Display a list of all revisions of a specific Code Resource in database. """ coderesource = CodeResource.check_accessible(pk, request.user) addable_users, addable_groups = coderesource.other_users_groups() if request.method == 'POST': # We are attempting to update the CodeResource's metadata/permissions. resource_form = CodeResourceDetailsForm( request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=coderesource ) if resource_form.is_valid(): try: coderesource.name = resource_form.cleaned_data["name"] coderesource.description = resource_form.cleaned_data["description"] coderesource.clean() coderesource.save() coderesource.grant_from_json(resource_form.cleaned_data["permissions"]) # Success -- go back to the resources page. return HttpResponseRedirect('/resources') except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) resource_form.add_error(None, e) else: resource_form = CodeResourceDetailsForm( addable_users=addable_users, addable_groups=addable_groups, initial={"name": coderesource.name, "description": coderesource.description} ) revisions = CodeResourceRevision.filter_by_user( request.user, queryset=coderesource.revisions.all()).order_by('-revision_number') if len(revisions) == 0: # Go to the resource_revision_add page to create a first revision. t = loader.get_template('method/resource_revision_add.html') crv_form = CodeResourceRevisionForm() c = { 'revision_form': crv_form, 'parent_revision': None, 'coderesource': coderesource, } return HttpResponse(t.render(c, request)) # Load template, setup context t = loader.get_template('method/resource_revisions.html') c = { 'coderesource': coderesource, "resource_form": resource_form, 'revisions': revisions, 'is_admin': admin_check(request.user), "is_owner": request.user == coderesource.user } return HttpResponse(t.render(c, request))
def method_revise(request, pk): """ Add a revision of an existing Method. revision_parent is defined by the previous version. """ t = loader.get_template('method/method.html') c = {} creating_user = request.user # Retrieve the most recent member of this Method's family. parent_method = Method.check_accessible(pk, creating_user) family = parent_method.family # Retrieve the most recent revision of the corresponding CR. parent_revision = parent_method.driver if not parent_revision: this_code_resource = None all_revisions = [] else: this_code_resource = parent_revision.coderesource # Filter the available revisions by user. all_revisions = CodeResourceRevision.filter_by_user( creating_user, queryset=this_code_resource.revisions.all()).order_by( '-revision_DateTime') parent_container = parent_method.container if not parent_container: this_container_family = None all_containers = [] else: this_container_family = parent_container.family all_containers = Container.filter_by_user( creating_user, queryset=this_container_family.containers.all()) if request.method == 'POST': # Because there is no CodeResource specified, the second value is of type MethodReviseForm. family_form, method_revise_form,\ dep_forms, input_form_tuples,\ output_form_tuples, _ = create_method_forms(request.POST, creating_user, family=family) if not _method_forms_check_valid(family_form, method_revise_form, dep_forms, input_form_tuples, output_form_tuples): # Bail out now if there are any problems. c.update({ 'coderesource': this_code_resource, 'containerfamily': this_container_family, 'method_revise_form': method_revise_form, 'dep_forms': dep_forms, 'input_forms': input_form_tuples, 'output_forms': output_form_tuples, 'family': family, 'family_form': family_form, 'parent': parent_method, 'docker_default': DockerImage.DEFAULT_IMAGE }) return HttpResponse(t.render(c, request)) # Next, attempt to build the Method and add it to family. create_method_from_forms(family_form, method_revise_form, dep_forms, input_form_tuples, output_form_tuples, creating_user, family=family, parent_method=parent_method) if _method_forms_check_valid(family_form, method_revise_form, dep_forms, input_form_tuples, output_form_tuples): # Success! return HttpResponseRedirect('/methods/{}'.format(family.pk)) else: # Initialize forms with values of parent Method. family_form = MethodFamilyForm({ "name": family.name, "description": family.description }) parent_users_allowed = [ x.username for x in parent_method.users_allowed.all() ] parent_groups_allowed = [ x.name for x in parent_method.groups_allowed.all() ] method_revise_form = MethodReviseForm( initial={ "revision_desc": parent_method.revision_desc, "driver_revisions": parent_revision and parent_revision.pk, "docker_image": parent_method.docker_image_id, "reusable": parent_method.reusable, "threads": parent_method.threads, "memory": parent_method.memory, "permissions": [parent_users_allowed, parent_groups_allowed] }) dependencies = parent_method.dependencies.all() dep_forms = [] for i, dependency in enumerate(dependencies): its_crv = dependency.requirement its_cr = its_crv.coderesource dep_form = MethodDependencyForm(user=creating_user, auto_id='id_%s_' + str(i), initial={ 'coderesource': its_cr.pk, 'revisions': its_crv.pk, 'path': dependency.path, 'filename': dependency.filename }) dep_forms.append(dep_form) # If the parent Method has no dependencies, add a blank form. if len(dep_forms) == 0: dep_forms.append( MethodDependencyForm(user=creating_user, auto_id='id_%s_0')) xput_forms = [] inputs = parent_method.inputs.order_by("dataset_idx") outputs = parent_method.outputs.order_by("dataset_idx") for xput_type, xputs in (("in", inputs), ("out", outputs)): forms = [] for xput in xputs: tx_form = TransformationXputForm(auto_id='id_%s_{}_{}'.format( xput_type, len(forms)), initial={ 'dataset_name': xput.dataset_name, 'dataset_idx': xput.dataset_idx }) if xput.has_structure: structure = xput.structure xs_form = XputStructureForm( user=creating_user, auto_id='id_%s_{}_{}'.format(xput_type, len(forms)), initial={ 'compounddatatype': structure.compounddatatype.id, 'min_row': structure.min_row, 'max_row': structure.max_row }) else: xs_form = XputStructureForm( user=creating_user, auto_id='id_%s_{}_{}'.format(xput_type, len(forms)), initial={'compounddatatype': '__raw__'}) forms.append((tx_form, xs_form)) xput_forms.append(forms) input_form_tuples, output_form_tuples = xput_forms # if previous Method has no inputs, provide blank forms if len(input_form_tuples) == 0: tx_form = TransformationXputForm(auto_id='id_%s_in_0') xs_form = XputStructureForm(user=creating_user, auto_id='id_%s_in_0') input_form_tuples.append((tx_form, xs_form)) method_revise_form.fields['driver_revisions'].widget.choices = [ (str(x.id), '{}: {}'.format(x.revision_number, x.revision_name)) for x in all_revisions ] method_revise_form.fields['container'].widget.choices = [ (str(x.id), x.tag) for x in all_containers ] c.update({ 'coderesource': this_code_resource, 'containerfamily': this_container_family, 'method_form': method_revise_form, 'dep_forms': dep_forms, 'input_forms': input_form_tuples, 'output_forms': output_form_tuples, 'family': family, 'family_form': family_form, 'parent': parent_method, 'docker_default': DockerImage.DEFAULT_IMAGE }) return HttpResponse(t.render(c, request))
def resource_revisions(request, pk): """ Display a list of all revisions of a specific Code Resource in database. """ coderesource = CodeResource.check_accessible(pk, request.user) addable_users, addable_groups = coderesource.other_users_groups() if request.method == 'POST': # We are attempting to update the CodeResource's metadata/permissions. resource_form = CodeResourceDetailsForm(request.POST, addable_users=addable_users, addable_groups=addable_groups, instance=coderesource) if resource_form.is_valid(): try: coderesource.name = resource_form.cleaned_data["name"] coderesource.description = resource_form.cleaned_data[ "description"] coderesource.clean() coderesource.save() coderesource.grant_from_json( resource_form.cleaned_data["permissions"]) # Success -- go back to the resources page. return HttpResponseRedirect('/resources') except (AttributeError, ValidationError, ValueError) as e: LOGGER.exception(e.message) resource_form.add_error(None, e) else: resource_form = CodeResourceDetailsForm(addable_users=addable_users, addable_groups=addable_groups, initial={ "name": coderesource.name, "description": coderesource.description }) revisions = CodeResourceRevision.filter_by_user( request.user, queryset=coderesource.revisions.all()).order_by('-revision_number') if len(revisions) == 0: # Go to the resource_revision_add page to create a first revision. t = loader.get_template('method/resource_revision_add.html') crv_form = CodeResourceRevisionForm() c = { 'revision_form': crv_form, 'parent_revision': None, 'coderesource': coderesource, } return HttpResponse(t.render(c, request)) # Load template, setup context t = loader.get_template('method/resource_revisions.html') c = { 'coderesource': coderesource, "resource_form": resource_form, 'revisions': revisions, 'is_admin': admin_check(request.user), "is_owner": request.user == coderesource.user } return HttpResponse(t.render(c, request))
def method_revise(request, pk): """ Add a revision of an existing Method. revision_parent is defined by the previous version. """ t = loader.get_template('method/method.html') c = {} creating_user = request.user # Retrieve the most recent member of this Method's family. parent_method = Method.check_accessible(pk, creating_user) family = parent_method.family # Retrieve the most recent revision of the corresponding CR. parent_revision = parent_method.driver if not parent_revision: this_code_resource = None all_revisions = [] else: this_code_resource = parent_revision.coderesource # Filter the available revisions by user. all_revisions = CodeResourceRevision.filter_by_user( creating_user, queryset=this_code_resource.revisions.all()).order_by('-revision_DateTime') parent_container = parent_method.container if not parent_container: this_container_family = None all_containers = [] else: this_container_family = parent_container.family all_containers = Container.filter_by_user( creating_user, queryset=this_container_family.containers.all()) if request.method == 'POST': # Because there is no CodeResource specified, the second value is of type MethodReviseForm. family_form, method_revise_form,\ dep_forms, input_form_tuples,\ output_form_tuples, _ = create_method_forms(request.POST, creating_user, family=family) if not _method_forms_check_valid(family_form, method_revise_form, dep_forms, input_form_tuples, output_form_tuples): # Bail out now if there are any problems. c.update( { 'coderesource': this_code_resource, 'containerfamily': this_container_family, 'method_revise_form': method_revise_form, 'dep_forms': dep_forms, 'input_forms': input_form_tuples, 'output_forms': output_form_tuples, 'family': family, 'family_form': family_form, 'parent': parent_method, 'docker_default': DockerImage.DEFAULT_IMAGE }) return HttpResponse(t.render(c, request)) # Next, attempt to build the Method and add it to family. create_method_from_forms( family_form, method_revise_form, dep_forms, input_form_tuples, output_form_tuples, creating_user, family=family, parent_method=parent_method ) if _method_forms_check_valid(family_form, method_revise_form, dep_forms, input_form_tuples, output_form_tuples): # Success! return HttpResponseRedirect('/methods/{}'.format(family.pk)) else: # Initialize forms with values of parent Method. family_form = MethodFamilyForm({"name": family.name, "description": family.description}) parent_users_allowed = [x.username for x in parent_method.users_allowed.all()] parent_groups_allowed = [x.name for x in parent_method.groups_allowed.all()] method_revise_form = MethodReviseForm( initial={ "revision_desc": parent_method.revision_desc, "driver_revisions": parent_revision and parent_revision.pk, "docker_image": parent_method.docker_image_id, "reusable": parent_method.reusable, "threads": parent_method.threads, "memory": parent_method.memory, "permissions": [parent_users_allowed, parent_groups_allowed] }) dependencies = parent_method.dependencies.all() dep_forms = [] for i, dependency in enumerate(dependencies): its_crv = dependency.requirement its_cr = its_crv.coderesource dep_form = MethodDependencyForm( user=creating_user, auto_id='id_%s_'+str(i), initial={ 'coderesource': its_cr.pk, 'revisions': its_crv.pk, 'path': dependency.path, 'filename': dependency.filename } ) dep_forms.append(dep_form) # If the parent Method has no dependencies, add a blank form. if len(dep_forms) == 0: dep_forms.append(MethodDependencyForm(user=creating_user, auto_id='id_%s_0')) xput_forms = [] inputs = parent_method.inputs.order_by("dataset_idx") outputs = parent_method.outputs.order_by("dataset_idx") for xput_type, xputs in (("in", inputs), ("out", outputs)): forms = [] for xput in xputs: tx_form = TransformationXputForm(auto_id='id_%s_{}_{}'.format(xput_type, len(forms)), initial={'dataset_name': xput.dataset_name, 'dataset_idx': xput.dataset_idx}) if xput.has_structure: structure = xput.structure xs_form = XputStructureForm(user=creating_user, auto_id='id_%s_{}_{}'.format(xput_type, len(forms)), initial={'compounddatatype': structure.compounddatatype.id, 'min_row': structure.min_row, 'max_row': structure.max_row}) else: xs_form = XputStructureForm(user=creating_user, auto_id='id_%s_{}_{}'.format(xput_type, len(forms)), initial={'compounddatatype': '__raw__'}) forms.append((tx_form, xs_form)) xput_forms.append(forms) input_form_tuples, output_form_tuples = xput_forms # if previous Method has no inputs, provide blank forms if len(input_form_tuples) == 0: tx_form = TransformationXputForm(auto_id='id_%s_in_0') xs_form = XputStructureForm(user=creating_user, auto_id='id_%s_in_0') input_form_tuples.append((tx_form, xs_form)) method_revise_form.fields['driver_revisions'].widget.choices = [ (str(x.id), '{}: {}'.format(x.revision_number, x.revision_name)) for x in all_revisions ] method_revise_form.fields['container'].widget.choices = [ (str(x.id), x.tag) for x in all_containers] c.update( { 'coderesource': this_code_resource, 'containerfamily': this_container_family, 'method_form': method_revise_form, 'dep_forms': dep_forms, 'input_forms': input_form_tuples, 'output_forms': output_form_tuples, 'family': family, 'family_form': family_form, 'parent': parent_method, 'docker_default': DockerImage.DEFAULT_IMAGE } ) return HttpResponse(t.render(c, request))
def _make_crv(file_in_memory, creating_user, crv_form, parent_revision=None, code_resource=None): """ Helper that creates a CodeResourceRevision (and a CodeResource as well if appropriate). """ assert isinstance(crv_form, (CodeResourcePrototypeForm, CodeResourceRevisionForm)) # If parent_revision is specified, we are only making a CodeResourceRevision and not its parent CodeResource. assert not (parent_revision is None and isinstance(crv_form, CodeResourceRevision)) cr_filename = "" if file_in_memory is None else file_in_memory.name if code_resource is None and parent_revision is not None: code_resource = parent_revision.coderesource if code_resource is None: # crv_form is a CodeResourcePrototypeForm. code_resource = CodeResource( name=crv_form.cleaned_data['resource_name'], description=crv_form.cleaned_data['resource_desc'], filename=cr_filename, user=creating_user) try: code_resource.full_clean() # Skip the clean until later; after all, we're protected by a transaction here. code_resource.save() except ValidationError as e: crv_form.add_error('content_file', e.error_dict.get('filename', [])) crv_form.add_error('resource_name', e.error_dict.get('name', [])) crv_form.add_error('resource_desc', e.error_dict.get('description', [])) raise e code_resource.grant_from_json(crv_form.cleaned_data["permissions"]) rev_name = "Prototype" rev_desc = crv_form.cleaned_data["resource_desc"] else: rev_name = crv_form.cleaned_data["revision_name"] rev_desc = crv_form.cleaned_data["revision_desc"] # Modify actual filename prior to saving revision object. if file_in_memory is not None: file_in_memory.name += '_' + datetime.now().strftime('%Y%m%d%H%M%S') revision = CodeResourceRevision(revision_parent=parent_revision, revision_name=rev_name, revision_desc=rev_desc, coderesource=code_resource, content_file=file_in_memory, user=creating_user) # This sets the MD5. try: revision.clean() except ValidationError as e: crv_form.add_error(None, e) raise e revision.save() revision.grant_from_json(crv_form.cleaned_data["permissions"]) try: code_resource.full_clean() revision.full_clean() except ValidationError as e: crv_form.add_error(None, e) raise e return revision
def test_identical_self(self): """A Method should be identical to itself.""" m = Method(driver=CodeResourceRevision(), user=User()) self.assertTrue(m.is_identical(m))
def add_dependency(self, filename): helper = CodeResourceRevision( coderesource=CodeResource(filename=filename)) dependency = self.method.dependencies.create(requirement=helper) dependency.method = self.method return dependency