prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  'NoneType' object has no attribute 'values'
  Sentry issue https://sentry.io/organizations/grand-challenge/issues/3127690895/?project=303639&query=is%3Aunresolved
  
  ```
  slugs = {slug for viewport in mapping.values() for slug in viewport}
  ```
  
  Added in https://github.com/comic/grand-challenge.org/pull/2322
  
  --- 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/hanging_protocols/forms.py`
  Content:
  ```
  1 from django import forms
  2 
  3 from grandchallenge.components.models import ComponentInterface
  4 from grandchallenge.core.forms import SaveFormInitMixin
  5 from grandchallenge.core.widgets import JSONEditorWidget
  6 from grandchallenge.hanging_protocols.models import (
  7     HANGING_PROTOCOL_SCHEMA,
  8     VIEW_CONTENT_SCHEMA,
  9     HangingProtocol,
  10 )
  11 
  12 
  13 class HangingProtocolForm(SaveFormInitMixin, forms.ModelForm):
  14     class Meta:
  15         model = HangingProtocol
  16         fields = ("title", "description", "json")
  17         widgets = {"json": JSONEditorWidget(schema=HANGING_PROTOCOL_SCHEMA)}
  18         help_texts = {
  19             "json": (
  20                 "To display a single image in full size, define the "
  21                 "protocol as follows: "
  22                 '[{"viewport_name": "main", "x": 0,"y": 0,"w": 1,"h": 1,'
  23                 '"fullsizable": true,"draggable": false,"selectable": true,'
  24                 '"order": 0}]'
  25             )
  26         }
  27 
  28 
  29 class ViewContentMixin:
  30     def clean_view_content(self):
  31         mapping = self.cleaned_data["view_content"]
  32         hanging_protocol = self.cleaned_data["hanging_protocol"]
  33         if mapping and not hanging_protocol:
  34             self.add_error(
  35                 error="Please select a hanging protocol before filling this field.",
  36                 field="view_content",
  37             )
  38 
  39         if mapping and hanging_protocol:
  40             if set(mapping.keys()) != {
  41                 x["viewport_name"] for x in hanging_protocol.json
  42             }:
  43                 self.add_error(
  44                     error=(
  45                         "Image ports in view_content do not match "
  46                         "those in the selected hanging protocol."
  47                     ),
  48                     field="view_content",
  49                 )
  50 
  51         slugs = {slug for viewport in mapping.values() for slug in viewport}
  52         unknown = []
  53         for slug in slugs:
  54             if not ComponentInterface.objects.filter(slug=slug).exists():
  55                 unknown.append(slug)
  56         if len(unknown) > 0:
  57             self.add_error(
  58                 error=f"Unkown slugs in view_content: {', '.join(unknown)}",
  59                 field="view_content",
  60             )
  61 
  62         return mapping
  63 
  64     class Meta:
  65         widgets = {
  66             "view_content": JSONEditorWidget(schema=VIEW_CONTENT_SCHEMA),
  67         }
  68         help_texts = {
  69             "view_content": (
  70                 "Indicate which Component Interfaces need to be displayed in "
  71                 'which image port. E.g. {"main": ["interface1"]}. The first '
  72                 "item in the list of interfaces will be the main image in "
  73                 "the image port. The first overlay type interface thereafter "
  74                 "will be rendered as an overlay. For now, any other items "
  75                 "will be ignored by the viewer."
  76             )
  77         }
  78
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/app/grandchallenge/hanging_protocols/forms.py b/app/grandchallenge/hanging_protocols/forms.py
  --- a/app/grandchallenge/hanging_protocols/forms.py
  +++ b/app/grandchallenge/hanging_protocols/forms.py
  @@ -28,7 +28,7 @@
   
   class ViewContentMixin:
       def clean_view_content(self):
  -        mapping = self.cleaned_data["view_content"]
  +        mapping = self.cleaned_data["view_content"] or {}
           hanging_protocol = self.cleaned_data["hanging_protocol"]
           if mapping and not hanging_protocol:
               self.add_error(
  
verification_info: {"golden_diff": "diff --git a/app/grandchallenge/hanging_protocols/forms.py b/app/grandchallenge/hanging_protocols/forms.py\n--- a/app/grandchallenge/hanging_protocols/forms.py\n+++ b/app/grandchallenge/hanging_protocols/forms.py\n@@ -28,7 +28,7 @@\n \r\n class ViewContentMixin:\r\n     def clean_view_content(self):\r\n-        mapping = self.cleaned_data[\"view_content\"]\r\n+        mapping = self.cleaned_data[\"view_content\"] or {}\r\n         hanging_protocol = self.cleaned_data[\"hanging_protocol\"]\r\n         if mapping and not hanging_protocol:\r\n             self.add_error(\n", "issue": "'NoneType' object has no attribute 'values'\nSentry issue https://sentry.io/organizations/grand-challenge/issues/3127690895/?project=303639&query=is%3Aunresolved\r\n\r\n```\r\nslugs = {slug for viewport in mapping.values() for slug in viewport}\r\n```\r\n\r\nAdded in https://github.com/comic/grand-challenge.org/pull/2322\n", "before_files": [{"content": "from django import forms\r\n\r\nfrom grandchallenge.components.models import ComponentInterface\r\nfrom grandchallenge.core.forms import SaveFormInitMixin\r\nfrom grandchallenge.core.widgets import JSONEditorWidget\r\nfrom grandchallenge.hanging_protocols.models import (\r\n    HANGING_PROTOCOL_SCHEMA,\r\n    VIEW_CONTENT_SCHEMA,\r\n    HangingProtocol,\r\n)\r\n\r\n\r\nclass HangingProtocolForm(SaveFormInitMixin, forms.ModelForm):\r\n    class Meta:\r\n        model = HangingProtocol\r\n        fields = (\"title\", \"description\", \"json\")\r\n        widgets = {\"json\": JSONEditorWidget(schema=HANGING_PROTOCOL_SCHEMA)}\r\n        help_texts = {\r\n            \"json\": (\r\n                \"To display a single image in full size, define the \"\r\n                \"protocol as follows: \"\r\n                '[{\"viewport_name\": \"main\", \"x\": 0,\"y\": 0,\"w\": 1,\"h\": 1,'\r\n                '\"fullsizable\": true,\"draggable\": false,\"selectable\": true,'\r\n                '\"order\": 0}]'\r\n            )\r\n        }\r\n\r\n\r\nclass ViewContentMixin:\r\n    def clean_view_content(self):\r\n        mapping = self.cleaned_data[\"view_content\"]\r\n        hanging_protocol = self.cleaned_data[\"hanging_protocol\"]\r\n        if mapping and not hanging_protocol:\r\n            self.add_error(\r\n                error=\"Please select a hanging protocol before filling this field.\",\r\n                field=\"view_content\",\r\n            )\r\n\r\n        if mapping and hanging_protocol:\r\n            if set(mapping.keys()) != {\r\n                x[\"viewport_name\"] for x in hanging_protocol.json\r\n            }:\r\n                self.add_error(\r\n                    error=(\r\n                        \"Image ports in view_content do not match \"\r\n                        \"those in the selected hanging protocol.\"\r\n                    ),\r\n                    field=\"view_content\",\r\n                )\r\n\r\n        slugs = {slug for viewport in mapping.values() for slug in viewport}\r\n        unknown = []\r\n        for slug in slugs:\r\n            if not ComponentInterface.objects.filter(slug=slug).exists():\r\n                unknown.append(slug)\r\n        if len(unknown) > 0:\r\n            self.add_error(\r\n                error=f\"Unkown slugs in view_content: {', '.join(unknown)}\",\r\n                field=\"view_content\",\r\n            )\r\n\r\n        return mapping\r\n\r\n    class Meta:\r\n        widgets = {\r\n            \"view_content\": JSONEditorWidget(schema=VIEW_CONTENT_SCHEMA),\r\n        }\r\n        help_texts = {\r\n            \"view_content\": (\r\n                \"Indicate which Component Interfaces need to be displayed in \"\r\n                'which image port. E.g. {\"main\": [\"interface1\"]}. The first '\r\n                \"item in the list of interfaces will be the main image in \"\r\n                \"the image port. The first overlay type interface thereafter \"\r\n                \"will be rendered as an overlay. For now, any other items \"\r\n                \"will be ignored by the viewer.\"\r\n            )\r\n        }\r\n", "path": "app/grandchallenge/hanging_protocols/forms.py"}], "after_files": [{"content": "from django import forms\r\n\r\nfrom grandchallenge.components.models import ComponentInterface\r\nfrom grandchallenge.core.forms import SaveFormInitMixin\r\nfrom grandchallenge.core.widgets import JSONEditorWidget\r\nfrom grandchallenge.hanging_protocols.models import (\r\n    HANGING_PROTOCOL_SCHEMA,\r\n    VIEW_CONTENT_SCHEMA,\r\n    HangingProtocol,\r\n)\r\n\r\n\r\nclass HangingProtocolForm(SaveFormInitMixin, forms.ModelForm):\r\n    class Meta:\r\n        model = HangingProtocol\r\n        fields = (\"title\", \"description\", \"json\")\r\n        widgets = {\"json\": JSONEditorWidget(schema=HANGING_PROTOCOL_SCHEMA)}\r\n        help_texts = {\r\n            \"json\": (\r\n                \"To display a single image in full size, define the \"\r\n                \"protocol as follows: \"\r\n                '[{\"viewport_name\": \"main\", \"x\": 0,\"y\": 0,\"w\": 1,\"h\": 1,'\r\n                '\"fullsizable\": true,\"draggable\": false,\"selectable\": true,'\r\n                '\"order\": 0}]'\r\n            )\r\n        }\r\n\r\n\r\nclass ViewContentMixin:\r\n    def clean_view_content(self):\r\n        mapping = self.cleaned_data[\"view_content\"] or {}\r\n        hanging_protocol = self.cleaned_data[\"hanging_protocol\"]\r\n        if mapping and not hanging_protocol:\r\n            self.add_error(\r\n                error=\"Please select a hanging protocol before filling this field.\",\r\n                field=\"view_content\",\r\n            )\r\n\r\n        if mapping and hanging_protocol:\r\n            if set(mapping.keys()) != {\r\n                x[\"viewport_name\"] for x in hanging_protocol.json\r\n            }:\r\n                self.add_error(\r\n                    error=(\r\n                        \"Image ports in view_content do not match \"\r\n                        \"those in the selected hanging protocol.\"\r\n                    ),\r\n                    field=\"view_content\",\r\n                )\r\n\r\n        slugs = {slug for viewport in mapping.values() for slug in viewport}\r\n        unknown = []\r\n        for slug in slugs:\r\n            if not ComponentInterface.objects.filter(slug=slug).exists():\r\n                unknown.append(slug)\r\n        if len(unknown) > 0:\r\n            self.add_error(\r\n                error=f\"Unkown slugs in view_content: {', '.join(unknown)}\",\r\n                field=\"view_content\",\r\n            )\r\n\r\n        return mapping\r\n\r\n    class Meta:\r\n        widgets = {\r\n            \"view_content\": JSONEditorWidget(schema=VIEW_CONTENT_SCHEMA),\r\n        }\r\n        help_texts = {\r\n            \"view_content\": (\r\n                \"Indicate which Component Interfaces need to be displayed in \"\r\n                'which image port. E.g. {\"main\": [\"interface1\"]}. The first '\r\n                \"item in the list of interfaces will be the main image in \"\r\n                \"the image port. The first overlay type interface thereafter \"\r\n                \"will be rendered as an overlay. For now, any other items \"\r\n                \"will be ignored by the viewer.\"\r\n            )\r\n        }\r\n", "path": "app/grandchallenge/hanging_protocols/forms.py"}]}