def _validate_resource_assignments(self, resource_assignment_dict, serializer): """ Validates the resource assignments May throw ValidationError. Returns a validated dictionary. """ if not isinstance(resource_assignment_dict, dict): raise ValidationError(["This field must be a JSON object"]) unsatisfied_ips = set( InputPort.objects.filter( workflow_job__in=serializer.validated_data["workflow"]. workflow_jobs.all(), connections__isnull=True, )) validated_resource_assignment_dict = {} # Keep track of the collection with multiple Resources or ResourceLists resource_collection_length = None resource_collection_ip = None for input_port, resources in resource_assignment_dict.items(): # 1. InputPort is not satisfied h_ip = HyperlinkedIdentityField(view_name="inputport-detail") h_ip.queryset = InputPort.objects.all() try: ip = h_ip.to_internal_value(input_port) except ValidationError as e: e.detail = {input_port: e.detail} raise e if ip not in unsatisfied_ips: raise ValidationError( {input_port: ["Assigned InputPort must be unsatisfied"]}) unsatisfied_ips.remove(ip) types_of_ip = ip.input_port_type.resource_types.all() # 2. Resources and ResourceLists: if not isinstance(resources, list): raise ValidationError({ input_port: ["A list of resources or resource lists is expected"] }) h_res = HyperlinkedIdentityField(view_name="resource-detail") h_res.queryset = Resource.objects.all() h_resl = HyperlinkedIdentityField(view_name="resourcelist-detail") h_resl.queryset = ResourceList.objects.all() ress = [] for index, r in enumerate(resources): try: ress.append(h_res.to_internal_value(r)) # a Resource except ValidationError as e: try: ress.append( h_resl.to_internal_value(r)) # a ResourceList except ValidationError as e: e.detail = {input_port: {index: e.detail}} raise e # No empty collection if len(ress) == 0: raise ValidationError({ input_port: ["It is not allowed to assign an empty collection"] }) # Collection with multiple Resources or ResourceLists if len(ress) > 1: if resource_collection_length is None: # This is the first resource collection we've encountered that has multiple items resource_collection_length = len(ress) resource_collection_ip = input_port else: # Validate if the lengths are even if len(ress) != resource_collection_length: raise ValidationError({ input_port: [ "The number of assigned Resources of ResourceLists is not even with that of {}" .format(resource_collection_ip) ] }) ## Resource must be in project and resource types are matched ## If a ResourceList, it should not be empty and all individuals should satisfy the above requirements. for index, res in enumerate(ress): if isinstance(res, Resource): if ip.input_port_type.is_list is True: raise ValidationError({ input_port: { index: [ "The InputPort requires ResourceLists but is provided with Resources" ] } }) if not res.resource_file: raise ValidationError({ input_port: { index: ["The resource file is not ready"] } }) else: # ResourceList if ip.input_port_type.is_list is False: raise ValidationError({ input_port: { index: [ "The InputPort requires Resources but is provided with ResourceLists" ] } }) for i, r in enumerate(res.resources.all()): if not r.resource_file: raise ValidationError({ input_port: { index: [ "The resource file of #{0} in the resource list is not ready" .format(i) ] } }) if res.project != serializer.validated_data["workflow"].project: raise ValidationError({ input_port: { index: [ "Resource or ResourceList is not in the project of Workflow" ] } }) type_of_res = res.resource_type if type_of_res not in types_of_ip: raise ValidationError({ input_port: { index: [ "The resource type {0} does not match the InputPort {1}" .format(type_of_res, types_of_ip) ] } }) validated_resource_assignment_dict[ip] = ress # Still we have unsatisfied input ports if unsatisfied_ips: raise ValidationError([ "There are still unsatisfied InputPorts: {0}".format(" ".join([ h_ip.get_url(ip, "inputport-detail", self.request, None) for ip in unsatisfied_ips ])) ]) return validated_resource_assignment_dict
def _validate_resource_assignments(self, resource_assignment_dict, serializer): """ Validates the resource assignments May throw ValidationError. Returns a validated dictionary. """ if not isinstance(resource_assignment_dict, dict): raise ValidationError(['This field must be a JSON object']) unsatisfied_ips = set(InputPort.objects.filter(workflow_job__in=serializer.validated_data['workflow'].workflow_jobs.all(), connections__isnull=True)) validated_resource_assignment_dict = {} multiple_resource_set = None for input_port, resources in resource_assignment_dict.iteritems(): # 1. InputPort is not satisfied h_ip = HyperlinkedIdentityField(view_name="inputport-detail") h_ip.queryset = InputPort.objects.all() try: ip = h_ip.to_internal_value(input_port) except ValidationError as e: e.detail = {input_port: e.detail} raise e if ip not in unsatisfied_ips: raise ValidationError({input_port: ['Assigned InputPort must be unsatisfied']}) unsatisfied_ips.remove(ip) types_of_ip = ip.input_port_type.resource_types.all() # 2. Resources and ResourceLists: if not isinstance(resources, list): raise ValidationError({input_port: ['A list of resources or resource lists is expected']}) h_res = HyperlinkedIdentityField(view_name="resource-detail") h_res.queryset = Resource.objects.all() h_resl = HyperlinkedIdentityField(view_name="resourcelist-detail") h_resl.queryset = ResourceList.objects.all() ress = [] for index, r in enumerate(resources): try: ress.append(h_res.to_internal_value(r)) # a Resource except ValidationError as e: try: ress.append(h_resl.to_internal_value(r)) # a ResourceList except ValidationError as e: e.detail = {input_port: {index: e.detail}} raise e ## No empty resource set if len(ress) == 0: raise ValidationError({input_port: ['It is not allowed to assign an empty resource set']}) ## There must be at most one multiple resource set if len(ress) > 1: ress_set = set(map(lambda r: r.uuid, ress)) if not multiple_resource_set: multiple_resource_set = ress_set else: if multiple_resource_set != ress_set: raise ValidationError({input_port: ['It is not allowed to assign multiple resource sets']}) ## Resource must be in project and resource types are matched ## If a ResourceList, it should not be empty and all individuals should satisfy the above requirements. for index, res in enumerate(ress): if isinstance(res, Resource): if ip.input_port_type.is_list is True: raise ValidationError({input_port: {index: ['The InputPort requires ResourceLists but is provided with Resources']}}) if not res.resource_file: raise ValidationError({input_port: {index: ['The resource file is not ready']}}) else: # ResourceList if ip.input_port_type.is_list is False: raise ValidationError({input_port: {index: ['The InputPort requires Resources but is provided with ResourceLists']}}) for i, r in enumerate(res.resources.all()): if not r.resource_file: raise ValidationError({input_port: {index: ['The resource file of #{0} in the resource list is not ready'.format(i)]}}) if res.project != serializer.validated_data['workflow'].project: raise ValidationError({input_port: {index: ['Resource or ResourceList is not in the project of Workflow']}}) type_of_res = res.resource_type if type_of_res not in types_of_ip: raise ValidationError({input_port: {index: ['The resource type does not match the InputPort']}}) validated_resource_assignment_dict[ip] = ress # Still we have unsatisfied input ports if unsatisfied_ips: raise ValidationError(['There are still unsatisfied InputPorts: {0}'.format( ' '.join([h_ip.get_url(ip, 'inputport-detail', self.request, None) for ip in unsatisfied_ips]) )]) return validated_resource_assignment_dict