We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Cannot save phase update form without changing the title of the phase



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `app/grandchallenge/evaluation/forms.py`
Content:
```
1 from crispy_forms.bootstrap import Tab, TabHolder
2 from crispy_forms.helper import FormHelper
3 from crispy_forms.layout import ButtonHolder, Layout, Submit
4 from django import forms
5 from django.core.exceptions import ValidationError
6 from django.db.models.functions import Lower
7 from django.forms import ModelChoiceField
8 from django.utils.text import format_lazy
9 from django_summernote.widgets import SummernoteInplaceWidget
10 from guardian.shortcuts import get_objects_for_user
11 
12 from grandchallenge.algorithms.models import Algorithm
13 from grandchallenge.core.forms import SaveFormInitMixin
14 from grandchallenge.core.validators import ExtensionValidator
15 from grandchallenge.core.widgets import JSONEditorWidget
16 from grandchallenge.evaluation.models import (
17     EXTRA_RESULT_COLUMNS_SCHEMA,
18     Method,
19     Phase,
20     Submission,
21 )
22 from grandchallenge.jqfileupload.widgets import uploader
23 from grandchallenge.jqfileupload.widgets.uploader import UploadedAjaxFileList
24 from grandchallenge.subdomains.utils import reverse_lazy
25 
26 phase_options = ("title",)
27 
28 submission_options = (
29     "submission_page_html",
30     "daily_submission_limit",
31     "allow_submission_comments",
32     "supplementary_file_choice",
33     "supplementary_file_label",
34     "supplementary_file_help_text",
35     "publication_url_choice",
36 )
37 
38 scoring_options = (
39     "score_title",
40     "score_jsonpath",
41     "score_error_jsonpath",
42     "score_default_sort",
43     "score_decimal_places",
44     "extra_results_columns",
45     "scoring_method_choice",
46     "auto_publish_new_results",
47     "result_display_choice",
48 )
49 
50 leaderboard_options = (
51     "display_submission_comments",
52     "show_supplementary_file_link",
53     "show_publication_url",
54     "evaluation_comparison_observable_url",
55 )
56 
57 result_detail_options = (
58     "display_all_metrics",
59     "evaluation_detail_observable_url",
60 )
61 
62 
63 class PhaseTitleMixin:
64     def __init__(self, *args, challenge, **kwargs):
65         self.challenge = challenge
66         super().__init__(*args, **kwargs)
67 
68     def clean_title(self):
69         title = self.cleaned_data["title"]
70 
71         if self.challenge.phase_set.filter(title=title).exists():
72             raise ValidationError(
73                 "This challenge already has a phase with this title"
74             )
75 
76         return title
77 
78 
79 class PhaseCreateForm(PhaseTitleMixin, SaveFormInitMixin, forms.ModelForm):
80     class Meta:
81         model = Phase
82         fields = ("title",)
83 
84 
85 class PhaseUpdateForm(PhaseTitleMixin, forms.ModelForm):
86     def __init__(self, *args, **kwargs):
87         super().__init__(*args, **kwargs)
88         self.helper = FormHelper(self)
89         self.helper.layout = Layout(
90             TabHolder(
91                 Tab("Phase", *phase_options),
92                 Tab("Submission", *submission_options),
93                 Tab("Scoring", *scoring_options),
94                 Tab("Leaderboard", *leaderboard_options),
95                 Tab("Result Detail", *result_detail_options),
96             ),
97             ButtonHolder(Submit("save", "Save")),
98         )
99 
100     class Meta:
101         model = Phase
102         fields = (
103             *phase_options,
104             *submission_options,
105             *scoring_options,
106             *leaderboard_options,
107             *result_detail_options,
108         )
109         widgets = {
110             "submission_page_html": SummernoteInplaceWidget(),
111             "extra_results_columns": JSONEditorWidget(
112                 schema=EXTRA_RESULT_COLUMNS_SCHEMA
113             ),
114         }
115 
116 
117 class MethodForm(SaveFormInitMixin, forms.ModelForm):
118     phase = ModelChoiceField(
119         queryset=None,
120         help_text="Which phase is this evaluation container for?",
121     )
122     chunked_upload = UploadedAjaxFileList(
123         widget=uploader.AjaxUploadWidget(multifile=False, auto_commit=False),
124         label="Evaluation Method Container",
125         validators=[
126             ExtensionValidator(allowed_extensions=(".tar", ".tar.gz"))
127         ],
128         help_text=(
129             ".tar.gz archive of the container image produced from the command "
130             "'docker save IMAGE | gzip -c > IMAGE.tar.gz'. See "
131             "https://docs.docker.com/engine/reference/commandline/save/"
132         ),
133     )
134 
135     def __init__(self, *args, user, challenge, **kwargs):
136         super().__init__(*args, **kwargs)
137         self.fields["chunked_upload"].widget.user = user
138         self.fields["phase"].queryset = challenge.phase_set.all()
139 
140     class Meta:
141         model = Method
142         fields = ["phase", "chunked_upload"]
143 
144 
145 submission_fields = (
146     "comment",
147     "supplementary_file",
148     "publication_url",
149     "chunked_upload",
150 )
151 
152 
153 class SubmissionForm(forms.ModelForm):
154     chunked_upload = UploadedAjaxFileList(
155         widget=uploader.AjaxUploadWidget(multifile=False, auto_commit=False),
156         label="Predictions File",
157         validators=[ExtensionValidator(allowed_extensions=(".zip", ".csv"))],
158     )
159     algorithm = ModelChoiceField(
160         queryset=None,
161         help_text=format_lazy(
162             "Select one of your algorithms to submit as a solution to this "
163             "challenge. If you have not created your algorithm yet you can "
164             "do so <a href={}>on this page</a>.",
165             reverse_lazy("algorithms:create"),
166         ),
167     )
168 
169     def __init__(
170         self,
171         *args,
172         user,
173         algorithm_submission=False,
174         display_comment_field=False,
175         supplementary_file_choice=Phase.OFF,
176         supplementary_file_label="",
177         supplementary_file_help_text="",
178         publication_url_choice=Phase.OFF,
179         **kwargs,
180     ):
181         """
182         Conditionally render the comment field based on the
183         display_comment_field kwarg
184         """
185         super().__init__(*args, **kwargs)
186 
187         if not display_comment_field:
188             del self.fields["comment"]
189 
190         if supplementary_file_label:
191             self.fields["supplementary_file"].label = supplementary_file_label
192 
193         if supplementary_file_help_text:
194             self.fields[
195                 "supplementary_file"
196             ].help_text = supplementary_file_help_text
197 
198         if supplementary_file_choice == Phase.REQUIRED:
199             self.fields["supplementary_file"].required = True
200         elif supplementary_file_choice == Phase.OFF:
201             del self.fields["supplementary_file"]
202 
203         if publication_url_choice == Phase.REQUIRED:
204             self.fields["publication_url"].required = True
205         elif publication_url_choice == Phase.OFF:
206             del self.fields["publication_url"]
207 
208         if algorithm_submission:
209             del self.fields["chunked_upload"]
210 
211             self.fields["algorithm"].queryset = get_objects_for_user(
212                 user,
213                 f"{Algorithm._meta.app_label}.change_{Algorithm._meta.model_name}",
214                 Algorithm,
215             ).order_by("title")
216         else:
217             del self.fields["algorithm"]
218 
219             self.fields["chunked_upload"].widget.user = user
220 
221         self.helper = FormHelper(self)
222         self.helper.layout.append(Submit("save", "Save"))
223 
224     def clean_algorithm(self):
225         algorithm = self.cleaned_data["algorithm"]
226 
227         if algorithm.latest_ready_image is None:
228             raise ValidationError(
229                 "This algorithm does not have a usable container image. "
230                 "Please add one and try again."
231             )
232 
233         return algorithm
234 
235     class Meta:
236         model = Submission
237         fields = submission_fields
238 
239 
240 class LegacySubmissionForm(SubmissionForm):
241     def __init__(self, *args, challenge, **kwargs):
242         super().__init__(*args, **kwargs)
243         self.fields[
244             "creator"
245         ].queryset = challenge.participants_group.user_set.all().order_by(
246             Lower("username")
247         )
248 
249     class Meta:
250         model = Submission
251         fields = ("creator", *submission_fields)
252
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/app/grandchallenge/evaluation/forms.py b/app/grandchallenge/evaluation/forms.py
--- a/app/grandchallenge/evaluation/forms.py
+++ b/app/grandchallenge/evaluation/forms.py
@@ -66,9 +66,14 @@
         super().__init__(*args, **kwargs)
 
     def clean_title(self):
-        title = self.cleaned_data["title"]
+        title = self.cleaned_data["title"].strip()
 
-        if self.challenge.phase_set.filter(title=title).exists():
+        qs = self.challenge.phase_set.filter(title__iexact=title)
+
+        if self.instance:
+            qs = qs.exclude(pk=self.instance.pk)
+
+        if qs.exists():
             raise ValidationError(
                 "This challenge already has a phase with this title"
             )

{"golden_diff": "diff --git a/app/grandchallenge/evaluation/forms.py b/app/grandchallenge/evaluation/forms.py\n--- a/app/grandchallenge/evaluation/forms.py\n+++ b/app/grandchallenge/evaluation/forms.py\n@@ -66,9 +66,14 @@\n         super().__init__(*args, **kwargs)\n \n     def clean_title(self):\n-        title = self.cleaned_data[\"title\"]\n+        title = self.cleaned_data[\"title\"].strip()\n \n-        if self.challenge.phase_set.filter(title=title).exists():\n+        qs = self.challenge.phase_set.filter(title__iexact=title)\n+\n+        if self.instance:\n+            qs = qs.exclude(pk=self.instance.pk)\n+\n+        if qs.exists():\n             raise ValidationError(\n                 \"This challenge already has a phase with this title\"\n             )\n", "issue": "Cannot save phase update form without changing the title of the phase\n\r\n\n", "before_files": [{"content": "from crispy_forms.bootstrap import Tab, TabHolder\nfrom crispy_forms.helper import FormHelper\nfrom crispy_forms.layout import ButtonHolder, Layout, Submit\nfrom django import forms\nfrom django.core.exceptions import ValidationError\nfrom django.db.models.functions import Lower\nfrom django.forms import ModelChoiceField\nfrom django.utils.text import format_lazy\nfrom django_summernote.widgets import SummernoteInplaceWidget\nfrom guardian.shortcuts import get_objects_for_user\n\nfrom grandchallenge.algorithms.models import Algorithm\nfrom grandchallenge.core.forms import SaveFormInitMixin\nfrom grandchallenge.core.validators import ExtensionValidator\nfrom grandchallenge.core.widgets import JSONEditorWidget\nfrom grandchallenge.evaluation.models import (\n    EXTRA_RESULT_COLUMNS_SCHEMA,\n    Method,\n    Phase,\n    Submission,\n)\nfrom grandchallenge.jqfileupload.widgets import uploader\nfrom grandchallenge.jqfileupload.widgets.uploader import UploadedAjaxFileList\nfrom grandchallenge.subdomains.utils import reverse_lazy\n\nphase_options = (\"title\",)\n\nsubmission_options = (\n    \"submission_page_html\",\n    \"daily_submission_limit\",\n    \"allow_submission_comments\",\n    \"supplementary_file_choice\",\n    \"supplementary_file_label\",\n    \"supplementary_file_help_text\",\n    \"publication_url_choice\",\n)\n\nscoring_options = (\n    \"score_title\",\n    \"score_jsonpath\",\n    \"score_error_jsonpath\",\n    \"score_default_sort\",\n    \"score_decimal_places\",\n    \"extra_results_columns\",\n    \"scoring_method_choice\",\n    \"auto_publish_new_results\",\n    \"result_display_choice\",\n)\n\nleaderboard_options = (\n    \"display_submission_comments\",\n    \"show_supplementary_file_link\",\n    \"show_publication_url\",\n    \"evaluation_comparison_observable_url\",\n)\n\nresult_detail_options = (\n    \"display_all_metrics\",\n    \"evaluation_detail_observable_url\",\n)\n\n\nclass PhaseTitleMixin:\n    def __init__(self, *args, challenge, **kwargs):\n        self.challenge = challenge\n        super().__init__(*args, **kwargs)\n\n    def clean_title(self):\n        title = self.cleaned_data[\"title\"]\n\n        if self.challenge.phase_set.filter(title=title).exists():\n            raise ValidationError(\n                \"This challenge already has a phase with this title\"\n            )\n\n        return title\n\n\nclass PhaseCreateForm(PhaseTitleMixin, SaveFormInitMixin, forms.ModelForm):\n    class Meta:\n        model = Phase\n        fields = (\"title\",)\n\n\nclass PhaseUpdateForm(PhaseTitleMixin, forms.ModelForm):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.helper = FormHelper(self)\n        self.helper.layout = Layout(\n            TabHolder(\n                Tab(\"Phase\", *phase_options),\n                Tab(\"Submission\", *submission_options),\n                Tab(\"Scoring\", *scoring_options),\n                Tab(\"Leaderboard\", *leaderboard_options),\n                Tab(\"Result Detail\", *result_detail_options),\n            ),\n            ButtonHolder(Submit(\"save\", \"Save\")),\n        )\n\n    class Meta:\n        model = Phase\n        fields = (\n            *phase_options,\n            *submission_options,\n            *scoring_options,\n            *leaderboard_options,\n            *result_detail_options,\n        )\n        widgets = {\n            \"submission_page_html\": SummernoteInplaceWidget(),\n            \"extra_results_columns\": JSONEditorWidget(\n                schema=EXTRA_RESULT_COLUMNS_SCHEMA\n            ),\n        }\n\n\nclass MethodForm(SaveFormInitMixin, forms.ModelForm):\n    phase = ModelChoiceField(\n        queryset=None,\n        help_text=\"Which phase is this evaluation container for?\",\n    )\n    chunked_upload = UploadedAjaxFileList(\n        widget=uploader.AjaxUploadWidget(multifile=False, auto_commit=False),\n        label=\"Evaluation Method Container\",\n        validators=[\n            ExtensionValidator(allowed_extensions=(\".tar\", \".tar.gz\"))\n        ],\n        help_text=(\n            \".tar.gz archive of the container image produced from the command \"\n            \"'docker save IMAGE | gzip -c > IMAGE.tar.gz'. See \"\n            \"https://docs.docker.com/engine/reference/commandline/save/\"\n        ),\n    )\n\n    def __init__(self, *args, user, challenge, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.fields[\"chunked_upload\"].widget.user = user\n        self.fields[\"phase\"].queryset = challenge.phase_set.all()\n\n    class Meta:\n        model = Method\n        fields = [\"phase\", \"chunked_upload\"]\n\n\nsubmission_fields = (\n    \"comment\",\n    \"supplementary_file\",\n    \"publication_url\",\n    \"chunked_upload\",\n)\n\n\nclass SubmissionForm(forms.ModelForm):\n    chunked_upload = UploadedAjaxFileList(\n        widget=uploader.AjaxUploadWidget(multifile=False, auto_commit=False),\n        label=\"Predictions File\",\n        validators=[ExtensionValidator(allowed_extensions=(\".zip\", \".csv\"))],\n    )\n    algorithm = ModelChoiceField(\n        queryset=None,\n        help_text=format_lazy(\n            \"Select one of your algorithms to submit as a solution to this \"\n            \"challenge. If you have not created your algorithm yet you can \"\n            \"do so <a href={}>on this page</a>.\",\n            reverse_lazy(\"algorithms:create\"),\n        ),\n    )\n\n    def __init__(\n        self,\n        *args,\n        user,\n        algorithm_submission=False,\n        display_comment_field=False,\n        supplementary_file_choice=Phase.OFF,\n        supplementary_file_label=\"\",\n        supplementary_file_help_text=\"\",\n        publication_url_choice=Phase.OFF,\n        **kwargs,\n    ):\n        \"\"\"\n        Conditionally render the comment field based on the\n        display_comment_field kwarg\n        \"\"\"\n        super().__init__(*args, **kwargs)\n\n        if not display_comment_field:\n            del self.fields[\"comment\"]\n\n        if supplementary_file_label:\n            self.fields[\"supplementary_file\"].label = supplementary_file_label\n\n        if supplementary_file_help_text:\n            self.fields[\n                \"supplementary_file\"\n            ].help_text = supplementary_file_help_text\n\n        if supplementary_file_choice == Phase.REQUIRED:\n            self.fields[\"supplementary_file\"].required = True\n        elif supplementary_file_choice == Phase.OFF:\n            del self.fields[\"supplementary_file\"]\n\n        if publication_url_choice == Phase.REQUIRED:\n            self.fields[\"publication_url\"].required = True\n        elif publication_url_choice == Phase.OFF:\n            del self.fields[\"publication_url\"]\n\n        if algorithm_submission:\n            del self.fields[\"chunked_upload\"]\n\n            self.fields[\"algorithm\"].queryset = get_objects_for_user(\n                user,\n                f\"{Algorithm._meta.app_label}.change_{Algorithm._meta.model_name}\",\n                Algorithm,\n            ).order_by(\"title\")\n        else:\n            del self.fields[\"algorithm\"]\n\n            self.fields[\"chunked_upload\"].widget.user = user\n\n        self.helper = FormHelper(self)\n        self.helper.layout.append(Submit(\"save\", \"Save\"))\n\n    def clean_algorithm(self):\n        algorithm = self.cleaned_data[\"algorithm\"]\n\n        if algorithm.latest_ready_image is None:\n            raise ValidationError(\n                \"This algorithm does not have a usable container image. \"\n                \"Please add one and try again.\"\n            )\n\n        return algorithm\n\n    class Meta:\n        model = Submission\n        fields = submission_fields\n\n\nclass LegacySubmissionForm(SubmissionForm):\n    def __init__(self, *args, challenge, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.fields[\n            \"creator\"\n        ].queryset = challenge.participants_group.user_set.all().order_by(\n            Lower(\"username\")\n        )\n\n    class Meta:\n        model = Submission\n        fields = (\"creator\", *submission_fields)\n", "path": "app/grandchallenge/evaluation/forms.py"}], "after_files": [{"content": "from crispy_forms.bootstrap import Tab, TabHolder\nfrom crispy_forms.helper import FormHelper\nfrom crispy_forms.layout import ButtonHolder, Layout, Submit\nfrom django import forms\nfrom django.core.exceptions import ValidationError\nfrom django.db.models.functions import Lower\nfrom django.forms import ModelChoiceField\nfrom django.utils.text import format_lazy\nfrom django_summernote.widgets import SummernoteInplaceWidget\nfrom guardian.shortcuts import get_objects_for_user\n\nfrom grandchallenge.algorithms.models import Algorithm\nfrom grandchallenge.core.forms import SaveFormInitMixin\nfrom grandchallenge.core.validators import ExtensionValidator\nfrom grandchallenge.core.widgets import JSONEditorWidget\nfrom grandchallenge.evaluation.models import (\n    EXTRA_RESULT_COLUMNS_SCHEMA,\n    Method,\n    Phase,\n    Submission,\n)\nfrom grandchallenge.jqfileupload.widgets import uploader\nfrom grandchallenge.jqfileupload.widgets.uploader import UploadedAjaxFileList\nfrom grandchallenge.subdomains.utils import reverse_lazy\n\nphase_options = (\"title\",)\n\nsubmission_options = (\n    \"submission_page_html\",\n    \"daily_submission_limit\",\n    \"allow_submission_comments\",\n    \"supplementary_file_choice\",\n    \"supplementary_file_label\",\n    \"supplementary_file_help_text\",\n    \"publication_url_choice\",\n)\n\nscoring_options = (\n    \"score_title\",\n    \"score_jsonpath\",\n    \"score_error_jsonpath\",\n    \"score_default_sort\",\n    \"score_decimal_places\",\n    \"extra_results_columns\",\n    \"scoring_method_choice\",\n    \"auto_publish_new_results\",\n    \"result_display_choice\",\n)\n\nleaderboard_options = (\n    \"display_submission_comments\",\n    \"show_supplementary_file_link\",\n    \"show_publication_url\",\n    \"evaluation_comparison_observable_url\",\n)\n\nresult_detail_options = (\n    \"display_all_metrics\",\n    \"evaluation_detail_observable_url\",\n)\n\n\nclass PhaseTitleMixin:\n    def __init__(self, *args, challenge, **kwargs):\n        self.challenge = challenge\n        super().__init__(*args, **kwargs)\n\n    def clean_title(self):\n        title = self.cleaned_data[\"title\"].strip()\n\n        qs = self.challenge.phase_set.filter(title__iexact=title)\n\n        if self.instance:\n            qs = qs.exclude(pk=self.instance.pk)\n\n        if qs.exists():\n            raise ValidationError(\n                \"This challenge already has a phase with this title\"\n            )\n\n        return title\n\n\nclass PhaseCreateForm(PhaseTitleMixin, SaveFormInitMixin, forms.ModelForm):\n    class Meta:\n        model = Phase\n        fields = (\"title\",)\n\n\nclass PhaseUpdateForm(PhaseTitleMixin, forms.ModelForm):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.helper = FormHelper(self)\n        self.helper.layout = Layout(\n            TabHolder(\n                Tab(\"Phase\", *phase_options),\n                Tab(\"Submission\", *submission_options),\n                Tab(\"Scoring\", *scoring_options),\n                Tab(\"Leaderboard\", *leaderboard_options),\n                Tab(\"Result Detail\", *result_detail_options),\n            ),\n            ButtonHolder(Submit(\"save\", \"Save\")),\n        )\n\n    class Meta:\n        model = Phase\n        fields = (\n            *phase_options,\n            *submission_options,\n            *scoring_options,\n            *leaderboard_options,\n            *result_detail_options,\n        )\n        widgets = {\n            \"submission_page_html\": SummernoteInplaceWidget(),\n            \"extra_results_columns\": JSONEditorWidget(\n                schema=EXTRA_RESULT_COLUMNS_SCHEMA\n            ),\n        }\n\n\nclass MethodForm(SaveFormInitMixin, forms.ModelForm):\n    phase = ModelChoiceField(\n        queryset=None,\n        help_text=\"Which phase is this evaluation container for?\",\n    )\n    chunked_upload = UploadedAjaxFileList(\n        widget=uploader.AjaxUploadWidget(multifile=False, auto_commit=False),\n        label=\"Evaluation Method Container\",\n        validators=[\n            ExtensionValidator(allowed_extensions=(\".tar\", \".tar.gz\"))\n        ],\n        help_text=(\n            \".tar.gz archive of the container image produced from the command \"\n            \"'docker save IMAGE | gzip -c > IMAGE.tar.gz'. See \"\n            \"https://docs.docker.com/engine/reference/commandline/save/\"\n        ),\n    )\n\n    def __init__(self, *args, user, challenge, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.fields[\"chunked_upload\"].widget.user = user\n        self.fields[\"phase\"].queryset = challenge.phase_set.all()\n\n    class Meta:\n        model = Method\n        fields = [\"phase\", \"chunked_upload\"]\n\n\nsubmission_fields = (\n    \"comment\",\n    \"supplementary_file\",\n    \"publication_url\",\n    \"chunked_upload\",\n)\n\n\nclass SubmissionForm(forms.ModelForm):\n    chunked_upload = UploadedAjaxFileList(\n        widget=uploader.AjaxUploadWidget(multifile=False, auto_commit=False),\n        label=\"Predictions File\",\n        validators=[ExtensionValidator(allowed_extensions=(\".zip\", \".csv\"))],\n    )\n    algorithm = ModelChoiceField(\n        queryset=None,\n        help_text=format_lazy(\n            \"Select one of your algorithms to submit as a solution to this \"\n            \"challenge. If you have not created your algorithm yet you can \"\n            \"do so <a href={}>on this page</a>.\",\n            reverse_lazy(\"algorithms:create\"),\n        ),\n    )\n\n    def __init__(\n        self,\n        *args,\n        user,\n        algorithm_submission=False,\n        display_comment_field=False,\n        supplementary_file_choice=Phase.OFF,\n        supplementary_file_label=\"\",\n        supplementary_file_help_text=\"\",\n        publication_url_choice=Phase.OFF,\n        **kwargs,\n    ):\n        \"\"\"\n        Conditionally render the comment field based on the\n        display_comment_field kwarg\n        \"\"\"\n        super().__init__(*args, **kwargs)\n\n        if not display_comment_field:\n            del self.fields[\"comment\"]\n\n        if supplementary_file_label:\n            self.fields[\"supplementary_file\"].label = supplementary_file_label\n\n        if supplementary_file_help_text:\n            self.fields[\n                \"supplementary_file\"\n            ].help_text = supplementary_file_help_text\n\n        if supplementary_file_choice == Phase.REQUIRED:\n            self.fields[\"supplementary_file\"].required = True\n        elif supplementary_file_choice == Phase.OFF:\n            del self.fields[\"supplementary_file\"]\n\n        if publication_url_choice == Phase.REQUIRED:\n            self.fields[\"publication_url\"].required = True\n        elif publication_url_choice == Phase.OFF:\n            del self.fields[\"publication_url\"]\n\n        if algorithm_submission:\n            del self.fields[\"chunked_upload\"]\n\n            self.fields[\"algorithm\"].queryset = get_objects_for_user(\n                user,\n                f\"{Algorithm._meta.app_label}.change_{Algorithm._meta.model_name}\",\n                Algorithm,\n            ).order_by(\"title\")\n        else:\n            del self.fields[\"algorithm\"]\n\n            self.fields[\"chunked_upload\"].widget.user = user\n\n        self.helper = FormHelper(self)\n        self.helper.layout.append(Submit(\"save\", \"Save\"))\n\n    def clean_algorithm(self):\n        algorithm = self.cleaned_data[\"algorithm\"]\n\n        if algorithm.latest_ready_image is None:\n            raise ValidationError(\n                \"This algorithm does not have a usable container image. \"\n                \"Please add one and try again.\"\n            )\n\n        return algorithm\n\n    class Meta:\n        model = Submission\n        fields = submission_fields\n\n\nclass LegacySubmissionForm(SubmissionForm):\n    def __init__(self, *args, challenge, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.fields[\n            \"creator\"\n        ].queryset = challenge.participants_group.user_set.all().order_by(\n            Lower(\"username\")\n        )\n\n    class Meta:\n        model = Submission\n        fields = (\"creator\", *submission_fields)\n", "path": "app/grandchallenge/evaluation/forms.py"}]}