def test_validate_singularity_container_fail(self): """ A non-Singularity container should raise an error. :return: """ with self.assertRaisesMessage( ValidationError, Container. DEFAULT_ERROR_MESSAGES["invalid_singularity_container"]): Container.validate_singularity_container(self.useless_file)
def test_validate_singularity_container_fail(self): """ A non-Singularity container should raise an error. :return: """ with self.assertRaisesMessage( ValidationError, Container.DEFAULT_ERROR_MESSAGES["invalid_singularity_container"] ): Container.validate_singularity_container(self.useless_file)
def test_good_zip_archive(self): """ A good zip archive container passes validation. :return: """ parent = Container(id=41, file_type=Container.SIMG) container = Container(id=42, file_type=Container.ZIP, parent=parent) with open(self.zip_archive, "rb") as zip_archive: container.file = File(zip_archive) container.clean()
def test_good_tar_archive(self): """ A good tar archive container passes validation. :return: """ parent = Container(id=41, file_type=Container.SIMG) container = Container(id=42, file_type=Container.TAR, parent=parent) with open(self.tar_archive, "rb") as tar_archive: container.file = File(tar_archive) container.clean()
def clean(self): """ Perform Singularity container file validation (it's more efficient to do here than at the model level). Fill in the values for file and file_type. :return: """ self.cleaned_data = super(ContainerForm, self).clean() # Check the file extension of the file. the_file = self.cleaned_data.get("file") if the_file is None: raise ValidationError( Container.DEFAULT_ERROR_MESSAGES["invalid_archive"], code="invalid_archive", ) upload_name = getattr(the_file, 'name', 'container.simg') upload_base, upload_ext = os.path.splitext(upload_name) upload_lower = upload_name.lower() file_type = None for ext in Container.ACCEPTED_FILE_EXTENSIONS: if upload_lower.endswith(ext): file_type = Container.ACCEPTED_FILE_EXTENSIONS[ext] break if file_type is None: raise ValidationError( Container.DEFAULT_ERROR_MESSAGES["bad_extension"], code="bad_extension") if file_type == Container.SIMG: # We need to get a file object to validate. We might have a path or we might # have to read the data out of memory. if hasattr(the_file, 'temporary_file_path'): Container.validate_singularity_container( the_file.temporary_file_path()) else: with NamedTemporaryFile(prefix=upload_base, suffix=upload_ext) as f_temp: if hasattr(the_file, 'read'): f_temp.write(the_file.read()) else: f_temp.write(the_file['content']) f_temp.flush() Container.validate_singularity_container(f_temp.name) if hasattr(the_file, 'seek') and callable(the_file.seek): the_file.seek(0) # Annotate self.instance with a marker that we already validated the container. self.instance.singularity_validated = True # Having figured out the file type, add it to self.instance manually. self.instance.file_type = file_type return self.cleaned_data
def bad_archive_test_helper(self, archive_type): """ Helper for testing bad archive containers. :return: """ parent = Container(id=41, file_type=Container.SIMG) container = Container(id=42, file_type=archive_type, parent=parent) with open(self.useless_file, "rb") as f: container.file = File(f) with self.assertRaisesMessage( ValidationError, Container.DEFAULT_ERROR_MESSAGES["invalid_archive"]): container.clean()
def empty_archive_test_helper(self, archive_type): """ Helper for testing archive containers that are just empty files (as opposed to empty archives). :return: """ parent = Container(id=41, file_type=Container.SIMG) container = Container(id=42, file_type=archive_type, parent=parent) with open(self.empty_file, "rb") as f: container.file = File(f) with self.assertRaisesMessage( ValidationError, Container.DEFAULT_ERROR_MESSAGES["invalid_archive"]): container.clean()
def test_clean_singularity_image_with_parent(self): """ A Singularity container should not have a parent. :return: """ parent = Container(id=41) container = Container(id=42, parent=parent, file_type=Container.SIMG) with open(self.alpine_path, "rb") as alpine_file: container.file = File(alpine_file) with self.assertRaisesMessage( ValidationError, Container. DEFAULT_ERROR_MESSAGES["singularity_cannot_have_parent"]): container.clean()
def admissible_driver_test_helper(self, archive_type, driver_type): """ Helper for testing archive containers' drivers' admissibility. :return: """ pipeline_dict = {"steps": [{"driver": "foobarbaz"}]} # Archives that contain a mix of files, including one driver. fd, archive = tempfile.mkstemp() try: with open(archive, mode="wb") as f: if archive_type == Container.ZIP: archive_handler = ZipHandler(f, mode="w") else: archive_handler = TarHandler(f, mode="w") archive_handler.write(u"hello_world.sh", self.hello_world_script) archive_handler.write(u"useless.lib", self.useless) archive_handler.write(u"not_a_script", self.not_a_script) if driver_type == "good": pipeline_dict["steps"][0]["driver"] = "hello_world.sh" elif driver_type == "bad": pipeline_dict["steps"][0]["driver"] = "not_a_script" archive_handler.write("kive/pipeline0.json", json.dumps(pipeline_dict)) archive_handler.close() parent = Container(id=41, file_type=Container.SIMG) container = Container(id=42, file_type=archive_type, parent=parent) with open(archive, "rb") as f: container.file = File(f) if driver_type == "good": container.clean() elif driver_type == "bad": with self.assertRaisesMessage( ValidationError, Container. DEFAULT_ERROR_MESSAGES["inadmissible_driver"]): container.clean() elif driver_type == "nonexistent": with self.assertRaisesMessage( ValidationError, Container. DEFAULT_ERROR_MESSAGES["driver_not_in_archive"]): container.clean() finally: os.remove(archive)
def clean(self): """ Perform Singularity container file validation (it's more efficient to do here than at the model level). Fill in the values for file and file_type. :return: """ self.cleaned_data = super(ContainerForm, self).clean() # Check the file extension of the file. the_file = self.cleaned_data["file"] upload_name = getattr(the_file, 'name', 'container.simg') upload_base, upload_ext = os.path.splitext(upload_name) upload_lower = upload_name.lower() file_type = None for ext in Container.ACCEPTED_FILE_EXTENSIONS: if upload_lower.endswith(ext): file_type = Container.ACCEPTED_FILE_EXTENSIONS[ext] break if file_type is None: raise ValidationError( Container.DEFAULT_ERROR_MESSAGES["bad_extension"], code="bad_extension" ) if file_type == Container.SIMG: # We need to get a file object to validate. We might have a path or we might # have to read the data out of memory. if hasattr(the_file, 'temporary_file_path'): Container.validate_singularity_container(the_file.temporary_file_path()) else: with NamedTemporaryFile(prefix=upload_base, suffix=upload_ext) as f_temp: if hasattr(the_file, 'read'): f_temp.write(the_file.read()) else: f_temp.write(the_file['content']) f_temp.flush() Container.validate_singularity_container(f_temp.name) if hasattr(the_file, 'seek') and callable(the_file.seek): the_file.seek(0) # Annotate self.instance with a marker that we already validated the container. self.instance.singularity_validated = True # Having figured out the file type, add it to self.instance manually. self.instance.file_type = file_type return self.cleaned_data
def test_removal(self): container = Container(id=42) expected_plan = {'Containers': {container}} plan = container.build_removal_plan() self.assertEqual(expected_plan, strip_removal_plan(plan))
def test_str(self): family = ContainerFamily(name='Spline Reticulator') container = Container(tag='v1.0.7', family=family) s = str(container) self.assertEqual("Spline Reticulator:v1.0.7", s)
def get_context_data(self, **kwargs): app_id = int(self.request.GET.get("app")) visible_containers = Container.filter_by_user(self.request.user) app_qs = ContainerApp.objects.filter(pk=app_id, container__in=visible_containers) app = app_qs.first() if app is None: raise Http404("ID {} is not accessible".format(app_id)) context = super(ContainerInputList, self).get_context_data(**kwargs) context['app'] = app context['app_url'] = rest_framework.reverse.reverse( str('containerapp-detail'), kwargs=dict(pk=app.pk), request=self.request) context['batch_form'] = BatchForm() context['inputs'] = [ dict(name=arg.name, url=rest_framework.reverse.reverse( str('containerargument-detail'), kwargs=dict(pk=arg.pk), request=self.request)) for arg in app.arguments.filter( type=ContainerArgument.INPUT).order_by('position') ] context['priolist'] = [t[0] for t in settings.SLURM_QUEUES] return context
def get_context_data(self, **kwargs): app_id = int(self.request.GET.get("app")) visible_containers = Container.filter_by_user(self.request.user) app_qs = ContainerApp.objects.filter(pk=app_id, container__in=visible_containers) app = app_qs.first() if app is None: raise Http404("ID {} is not accessible".format(app_id)) context = super(ContainerInputList, self).get_context_data(**kwargs) context['app'] = app context['app_url'] = rest_framework.reverse.reverse( str('containerapp-detail'), kwargs=dict(pk=app.pk), request=self.request) context['batch_form'] = BatchForm() context['inputs'] = [ dict(name=arg.name, url=rest_framework.reverse.reverse( str('containerargument-detail'), kwargs=dict(pk=arg.pk), request=self.request)) for arg in app.arguments.filter( type=ContainerArgument.INPUT).order_by('position')] context['priolist'] = [t[0] for t in settings.SLURM_QUEUES] return context
def test_removal_with_app(self): container = Container(id=42) app = container.apps.create(id=43) expected_plan = {'Containers': {container}, 'ContainerApps': {app}} plan = container.build_removal_plan() self.assertEqual(expected_plan, strip_removal_plan(plan))
def test_removal_with_child(self): container = Container(id=42) child_container = container.children.create(id=43) expected_plan = {'Containers': {container, child_container}} plan = container.build_removal_plan() self.assertEqual(expected_plan, strip_removal_plan(plan))
def test_removal_with_method(self): container = Container(id=42) method = container.methods.create(transformation_ptr_id=43) expected_plan = {'Containers': {container}, 'Methods': {method}} plan = container.build_removal_plan() self.assertEqual(expected_plan, strip_removal_plan(plan))
def get_context(request): """ Returns the context for lemmatised feature words. The parameters object; { containerid: int, lemma: list[str], highlight: bool, } :param request: :return: """ params = request.GET.dict() or json.loads(request.body) if not params: raise Http404 try: containerid = int(params['containerid']) container = Container.get_object(pk=containerid) lemma = params['lemma'] except (ValueError, KeyError, TypeError) as _: raise Http404(params) highlight = params.get('highlight', False) lemma_to_words, lemma = container.get_lemma_words(lemma) matchwords = [] for i in lemma: try: mapping = next(_ for _ in lemma_to_words if _.get('lemma') == i) matchwords.extend(mapping.get('words')) except StopIteration: matchwords.append(i) data = search_texts(path=container.container_path(), highlight=highlight, words=matchwords) serialiser = SerialiserFactory().get_serialiser('search_text_csv') data_objs = [{ 'title': _.title, 'url': _.url, 'pk': _.pk, 'dataid': _.dataid, 'created': _.created } for _ in container.data_set.filter(file_id__in=list( uuid.UUID(_['dataid']) for _ in data['data']))] serialiser = serialiser(data={ 'docs': data_objs, 'response': data, 'lemma': lemma }) zip_name = serialiser.get_zip_name( f'Feature-Context-ContainerID-{containerid}') resp = HttpResponse(serialiser.get_value(), content_type='application/force-download') resp['Content-Disposition'] = 'attachment; filename="%s"' % zip_name return resp
def test_display_default(self): app = ContainerApp(name='') # default app app.container = Container(tag='v1.0') app.container.family = ContainerFamily(name='Splines') expected_display_name = 'Splines:v1.0' display_name = app.display_name self.assertEqual(expected_display_name, display_name)
def build_run(self): run = ContainerRun() run.app = ContainerApp() run.app.container = Container() run.app.container.file = Namespace(path='/tmp/foo.simg') run.sandbox_path = '/tmp/box23' run.app.arguments.create(type=ContainerArgument.INPUT, name='in_csv') run.app.arguments.create(type=ContainerArgument.OUTPUT, name='out_csv') return run
def test_clean_good_singularity_image(self): """ A proper Singularity container should pass validation. :return: """ container = Container(id=42) container.file_type = Container.SIMG with open(self.alpine_path, 'rb') as alpine_file: container.file = File(alpine_file) container.clean()
def test_display_name(self): app = ContainerApp(name='reticulate') app.container = Container(tag='v1.0') app.container.family = ContainerFamily(name='Splines') expected_display_name = 'Splines:v1.0 / reticulate' display_name = app.display_name app_str = str(app) self.assertEqual(expected_display_name, display_name) self.assertEqual(expected_display_name, app_str)
def get_file_path(self, container: Container = None): """ Returns the path of the file as it is saved on disk :return: """ containerid = self.container.pk if not container: container = Container.get_object(containerid) return os.path.normpath( os.path.join(container.container_path(), self.dataid))
def no_driver_archive_test_helper(self, archive_type, empty=True): """ Helper for testing archive containers with no driver. :return: """ parent = Container(id=41, file_type=Container.SIMG) container = Container(id=42, file_type=archive_type, parent=parent) archive_file = self.empty_zip_archive if empty and archive_type == Container.TAR: archive_file = self.empty_tar_archive elif not empty: if archive_type == Container.ZIP: archive_file = self.no_driver_zip else: archive_file = self.no_driver_tar with open(archive_file, "rb") as f: container.file = File(f) with self.assertRaisesMessage( ValidationError, Container. DEFAULT_ERROR_MESSAGES["archive_has_no_drivers"]): container.clean()
def test_skip_singularity_validation(self, mock_val): """ Skip Singularity validation if it's marked as having already been done. :param mock_val: :return: """ container = Container(id=42, file_type=Container.SIMG) container.singularity_validated = True with open(self.alpine_path, 'rb') as alpine_file: container.file = File(alpine_file) container.clean() mock_val.assert_not_called()
def save(self, data, element_object=None): if element_object == None: container = Container() uid = self.generateUID() container.uid = uid else: container = element_object vars = container.variable.all() for vr in vars: container.variable.remove(vr) uid_deploy = self.parseData(data, "parent") deployment = self.getDeployment(uid_deploy) if not deployment == None: container.name = self.parseData(data, "name") container.type = self.parseData(data, "type") container.base_image = self.parseData(data, "base_image") container.image_name = self.parseData(data, "image_name") container.source = self.parseData(data, "source") container.port = self.parseData(data, "port") container.commands = self.parseData(data, "commands") container.cmd = self.parseData(data, "cmd") container.volume_path = self.parseData(data, "volume_path") container.save() list_variables = self.parseData(data, "variables") for variable_uid in list_variables: variable_item = self.getVariable(variable_uid) if not variable_item == None: container.variable.add(variable_item) list_variables_items = self.parseData(data, "variables_items") print(list_variables_items) for var_item in list_variables_items: var_item_object = self.saveVariable(var_item) if not var_item_object == None: container.variable.add(var_item_object) container.deployment.add(deployment) return { "status" : "success", "message" : "Saved", "uid" : container.uid, "element" : "container" } else: return {"status": "error", "message": "Deployment Not exist", "element" : "container"}
def test_archive_with_no_parent(self): """ An archive container must have a parent. :return: """ container = Container(id=42, file_type=Container.ZIP) with open(self.zip_archive, "rb") as zip_archive: container.file = File(zip_archive) with self.assertRaisesMessage( ValidationError, Container. DEFAULT_ERROR_MESSAGES["archive_must_have_parent"]): container.clean()
def delete_many(cls, data_ids: typing.List[int], containerid: int = None): """ Delete many objects for a given containerid and a list of data ids. :param data_ids: :param containerid: :return: """ container = Container.get_object(pk=containerid) for obj in cls.objects.filter(pk__in=data_ids): if container != obj.container: continue _path = obj.file_path if os.path.exists(_path): os.remove(_path) obj.delete()
def test_slurm_command_custom_memory(self): run = ContainerRun(pk=99) run.user = User(username='******') run.app = ContainerApp(threads=3, memory=100) run.app.container = Container() run.app.container.family = ContainerFamily(name='my container') run.sandbox_path = 'run23' expected_command = [ 'sbatch', '-J', 'r99 my container', '--parsable', '--output', '/tmp/kive_media/run23/logs/job%J_node%N_stdout.txt', '--error', '/tmp/kive_media/run23/logs/job%J_node%N_stderr.txt', '-c', '3', '--mem', '100', EXPECTED_MANAGE_PATH, 'runcontainer', '99' ] command = run.build_slurm_command() self.assertListEqual(expected_command, command)
def create(cls, data: ( str, list, ) = None, containerid: int = None, links: list = None, title: str = None, endpoint: str = None, seed: bool = False): """ Create and save a Data object with all the urls that make it. :param data: :param containerid: :param links: :param title: :param endpoint: :param seed: :return: """ container_obj = Container.get_object(containerid) url_parse = urllib.parse.urlparse(endpoint) obj = cls(title=title, container=container_obj, url=endpoint, seed=seed, hostname=url_parse.hostname) file_path = obj.get_file_path(container=container_obj) obj.file_path = file_path try: hash_text = obj.write_data_to_file(path=file_path, data=data) except DuplicateUrlError as _: return None else: obj.hash_text = hash_text obj.save() for item in links: Link.create(url=item, data=obj) return obj
def test_slurm_command_priority(self): run = ContainerRun(pk=99) run.user = User(username='******') run.app = ContainerApp() run.app.container = Container() run.app.container.family = ContainerFamily(name='my container') slurm_queues = (('low', 'kive-low'), ('medium', 'kive-medium'), ('high', 'kive-high')) run.priority = 2 run.sandbox_path = 'run23' expected_command = [ 'sbatch', '-J', 'r99 my container', '--parsable', '--output', '/tmp/kive_media/run23/logs/job%J_node%N_stdout.txt', '--error', '/tmp/kive_media/run23/logs/job%J_node%N_stderr.txt', '-c', '1', '--mem', '6000', '-p', 'kive-high', EXPECTED_MANAGE_PATH, 'runcontainer', '99' ] command = run.build_slurm_command(slurm_queues) self.assertListEqual(expected_command, command)
def prepare_data(self, containerid, data): """ :param containerid: :param data: :return: """ try: container = Container.get_object(pk=containerid) except ValueError: raise Http404(containerid) dataset = list(container.data_set.all()) for item in data: try: rec = next(_ for _ in dataset if _.dataid == item['fileid']) except StopIteration: continue else: del item['fileid'] item['url'] = rec.url item['title'] = rec.title item['pk'] = rec.pk item['created'] = rec.created data.reverse() return data
def filter_granted(self, queryset): """ Args don't have permissions, so filter by parent containers. """ granted_containers = Container.filter_by_user(self.request.user) return queryset.filter(app__container_id__in=granted_containers)
def test_validate_singularity_container_pass(self): """ A proper Singularity container should pass validation. :return: """ Container.validate_singularity_container(self.alpine_path)
def post(self, request, format=None): url = f"{BACKEND_DOMAIN}{reverse('lti')}" consumers = LTI_CONFIG["consumers"] method = request.method headers = request.META payload = request.POST.dict() # Verify that the payload received from LTI is valid try: verify_request_common(consumers, url, method, headers, payload) # If not, redirect to the error page # This page would be displayed in an iframe on Moodle except LTIException: # TODO: Implement logging of this error return redirect(FRONTEND_DOMAIN + "/forbidden") current_user_email = payload["lis_person_contact_email_primary"] data = { "email": current_user_email, "first_name": payload["lis_person_name_given"], "last_name": payload["lis_person_name_family"], } user = get_or_create_user(data) # Elevate the user to instructor group if they have a staff role in LTI # If they are already instructor or admin, then do nothing user_groups = [group.name for group in user.groups.all()] is_lti_instructor = (LTI_CONFIG["staff_role"] in payload["roles"].split(",") if LTI_CONFIG.get("staff_role") else False) if "user" in user_groups and is_lti_instructor: user.groups.set([Group.objects.get(name="instructor")]) token = generate_one_time_token(user) user.last_login = dt.now(timezone.utc) user.save() logger.info("authentication.login", extra={ "user": user.email, "type": "LTI" }) # Store the important LTI fields for this user # These fields be used to grant permissions in containers lti_payload = { "lti_id": payload["user_id"], "lti_email": current_user_email, "user_id": payload.get(LTI_CONFIG.get("username_field")), } lti.objects(user=user.id).update_one(payload=lti_payload, upsert=True) # If any containers have been bound to this LTI resource, then # redirect to that container # Otherwise, prompt the user to choose a container for binding lti_resource_id = payload["resource_link_id"] try: container = Container.objects.get(lti_resource=lti_resource_id) if LTI_CONFIG.get("auto_create_share_containers"): if container.owner != current_user_email and current_user_email not in container.sharing: container.sharing.append(current_user_email) container.save() return redirect(FRONTEND_DOMAIN + "?tkn=" + token + "&container=" + str(container.id)) except: if LTI_CONFIG.get("auto_create_share_containers"): container = Container(owner=current_user_email, code=payload["context_title"], lti_resource=payload["resource_link_id"], lti_context=payload["context_id"]) container.save() return redirect(FRONTEND_DOMAIN + "?tkn=" + token + "<i=" + lti_resource_id)
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))