prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Internal server error on multiview.py with invalid record ID
  multiview.py returns Internal server error when one of the specified IDs is invalid. It should return 404 or something instead.
  
  ```
  AttributeError: 'NoneType' object has no attribute 'person_record_id'
  at get (multiview.py:47)
  at serve (main.py:622)
  at get (main.py:647)
  ```
  
  --- 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/multiview.py`
  Content:
  ```
  1 #!/usr/bin/python2.7
  2 # Copyright 2010 Google Inc.
  3 #
  4 # Licensed under the Apache License, Version 2.0 (the "License");
  5 # you may not use this file except in compliance with the License.
  6 # You may obtain a copy of the License at
  7 #
  8 #      http://www.apache.org/licenses/LICENSE-2.0
  9 #
  10 # Unless required by applicable law or agreed to in writing, software
  11 # distributed under the License is distributed on an "AS IS" BASIS,
  12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 # See the License for the specific language governing permissions and
  14 # limitations under the License.
  15 
  16 from model import *
  17 from utils import *
  18 import pfif
  19 import reveal
  20 import subscribe
  21 import view
  22 
  23 from django.utils.translation import ugettext as _
  24 
  25 # Fields to show for side-by-side comparison.
  26 COMPARE_FIELDS = pfif.PFIF_1_4.fields['person'] + ['primary_full_name']
  27 
  28 
  29 class Handler(BaseHandler):
  30     def get(self):
  31         # To handle multiple persons, we create a single object where
  32         # each property is a list of values, one for each person.
  33         # This makes page rendering easier.
  34         person = dict([(prop, []) for prop in COMPARE_FIELDS])
  35         any_person = dict([(prop, None) for prop in COMPARE_FIELDS])
  36 
  37         # Get all persons from db.
  38         # TODO: Can later optimize to use fewer DB calls.
  39         for i in [1, 2, 3]:
  40             id = self.request.get('id%d' % i)
  41             if not id:
  42                 break
  43             p = Person.get(self.repo, id)
  44             sanitize_urls(p)
  45 
  46             for prop in COMPARE_FIELDS:
  47                 val = getattr(p, prop)
  48                 if prop == 'sex':  # convert enum value to localized text
  49                     val = get_person_sex_text(p)
  50                 person[prop].append(val)
  51                 any_person[prop] = any_person[prop] or val
  52 
  53         # Compute the local times for the date fields on the person and format.
  54         person['source_datetime_local_string'] = map(
  55             self.to_formatted_local_datetime, person['source_date'])
  56 
  57         # Check if private info should be revealed.
  58         content_id = 'multiview:' + ','.join(person['person_record_id'])
  59         reveal_url = reveal.make_reveal_url(self, content_id)
  60         show_private_info = reveal.verify(content_id, self.params.signature)
  61 
  62         standalone = self.request.get('standalone')
  63 
  64         # TODO: Handle no persons found.
  65 
  66         person['profile_pages'] = [view.get_profile_pages(profile_urls, self)
  67             for profile_urls in person['profile_urls']]
  68         any_person['profile_pages'] = any(person['profile_pages'])
  69 
  70         # Note: we're not showing notes and linked persons information
  71         # here at the moment.
  72         self.render('multiview.html',
  73                     person=person, any=any_person, standalone=standalone,
  74                     cols=len(person['full_name']) + 1,
  75                     onload_function='view_page_loaded()', markdup=True,
  76                     show_private_info=show_private_info, reveal_url=reveal_url)
  77 
  78     def post(self):
  79         if not self.params.text:
  80             return self.error(
  81                 200, _('Message is required. Please go back and try again.'))
  82 
  83         if not self.params.author_name:
  84             return self.error(
  85                 200, _('Your name is required in the "About you" section.  Please go back and try again.'))
  86 
  87         # TODO: To reduce possible abuse, we currently limit to 3 person
  88         # match. We could guard using e.g. an XSRF token, which I don't know how
  89         # to build in GAE.
  90 
  91         ids = set()
  92         for i in [1, 2, 3]:
  93             id = getattr(self.params, 'id%d' % i)
  94             if not id:
  95                 break
  96             ids.add(id)
  97 
  98         if len(ids) > 1:
  99             notes = []
  100             for person_id in ids:
  101                 person = Person.get(self.repo, person_id)
  102                 person_notes = []
  103                 for other_id in ids - set([person_id]):
  104                     note = Note.create_original(
  105                         self.repo,
  106                         entry_date=get_utcnow(),                        
  107                         person_record_id=person_id,
  108                         linked_person_record_id=other_id,
  109                         text=self.params.text,
  110                         author_name=self.params.author_name,
  111                         author_phone=self.params.author_phone,
  112                         author_email=self.params.author_email,
  113                         source_date=get_utcnow())
  114                     person_notes.append(note)
  115                 # Notify person's subscribers of all new duplicates. We do not
  116                 # follow links since each Person record in the ids list gets its
  117                 # own note. However, 1) when > 2 records are marked as
  118                 # duplicates, subscribers will still receive multiple
  119                 # notifications, and 2) subscribers to already-linked Persons
  120                 # will not be notified of the new link.
  121                 subscribe.send_notifications(self, person, person_notes, False)
  122                 notes += person_notes
  123             # Write all notes to store
  124             db.put(notes)
  125         self.redirect('/view', id=self.params.id1)
  126
  ```
  --- 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/multiview.py b/app/multiview.py
  --- a/app/multiview.py
  +++ b/app/multiview.py
  @@ -41,6 +41,11 @@
               if not id:
                   break
               p = Person.get(self.repo, id)
  +            if not p:
  +                return self.error(
  +                    404,
  +                    _("This person's entry does not exist or has been "
  +                      "deleted."))
               sanitize_urls(p)
   
               for prop in COMPARE_FIELDS:
  @@ -103,7 +108,7 @@
                   for other_id in ids - set([person_id]):
                       note = Note.create_original(
                           self.repo,
  -                        entry_date=get_utcnow(),                        
  +                        entry_date=get_utcnow(),
                           person_record_id=person_id,
                           linked_person_record_id=other_id,
                           text=self.params.text,
  
verification_info: {"golden_diff": "diff --git a/app/multiview.py b/app/multiview.py\n--- a/app/multiview.py\n+++ b/app/multiview.py\n@@ -41,6 +41,11 @@\n             if not id:\n                 break\n             p = Person.get(self.repo, id)\n+            if not p:\n+                return self.error(\n+                    404,\n+                    _(\"This person's entry does not exist or has been \"\n+                      \"deleted.\"))\n             sanitize_urls(p)\n \n             for prop in COMPARE_FIELDS:\n@@ -103,7 +108,7 @@\n                 for other_id in ids - set([person_id]):\n                     note = Note.create_original(\n                         self.repo,\n-                        entry_date=get_utcnow(),                        \n+                        entry_date=get_utcnow(),\n                         person_record_id=person_id,\n                         linked_person_record_id=other_id,\n                         text=self.params.text,\n", "issue": "Internal server error on multiview.py with invalid record ID\nmultiview.py returns Internal server error when one of the specified IDs is invalid. It should return 404 or something instead.\r\n\r\n```\r\nAttributeError: 'NoneType' object has no attribute 'person_record_id'\r\nat get (multiview.py:47)\r\nat serve (main.py:622)\r\nat get (main.py:647)\r\n```\n", "before_files": [{"content": "#!/usr/bin/python2.7\n# Copyright 2010 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom model import *\nfrom utils import *\nimport pfif\nimport reveal\nimport subscribe\nimport view\n\nfrom django.utils.translation import ugettext as _\n\n# Fields to show for side-by-side comparison.\nCOMPARE_FIELDS = pfif.PFIF_1_4.fields['person'] + ['primary_full_name']\n\n\nclass Handler(BaseHandler):\n    def get(self):\n        # To handle multiple persons, we create a single object where\n        # each property is a list of values, one for each person.\n        # This makes page rendering easier.\n        person = dict([(prop, []) for prop in COMPARE_FIELDS])\n        any_person = dict([(prop, None) for prop in COMPARE_FIELDS])\n\n        # Get all persons from db.\n        # TODO: Can later optimize to use fewer DB calls.\n        for i in [1, 2, 3]:\n            id = self.request.get('id%d' % i)\n            if not id:\n                break\n            p = Person.get(self.repo, id)\n            sanitize_urls(p)\n\n            for prop in COMPARE_FIELDS:\n                val = getattr(p, prop)\n                if prop == 'sex':  # convert enum value to localized text\n                    val = get_person_sex_text(p)\n                person[prop].append(val)\n                any_person[prop] = any_person[prop] or val\n\n        # Compute the local times for the date fields on the person and format.\n        person['source_datetime_local_string'] = map(\n            self.to_formatted_local_datetime, person['source_date'])\n\n        # Check if private info should be revealed.\n        content_id = 'multiview:' + ','.join(person['person_record_id'])\n        reveal_url = reveal.make_reveal_url(self, content_id)\n        show_private_info = reveal.verify(content_id, self.params.signature)\n\n        standalone = self.request.get('standalone')\n\n        # TODO: Handle no persons found.\n\n        person['profile_pages'] = [view.get_profile_pages(profile_urls, self)\n            for profile_urls in person['profile_urls']]\n        any_person['profile_pages'] = any(person['profile_pages'])\n\n        # Note: we're not showing notes and linked persons information\n        # here at the moment.\n        self.render('multiview.html',\n                    person=person, any=any_person, standalone=standalone,\n                    cols=len(person['full_name']) + 1,\n                    onload_function='view_page_loaded()', markdup=True,\n                    show_private_info=show_private_info, reveal_url=reveal_url)\n\n    def post(self):\n        if not self.params.text:\n            return self.error(\n                200, _('Message is required. Please go back and try again.'))\n\n        if not self.params.author_name:\n            return self.error(\n                200, _('Your name is required in the \"About you\" section.  Please go back and try again.'))\n\n        # TODO: To reduce possible abuse, we currently limit to 3 person\n        # match. We could guard using e.g. an XSRF token, which I don't know how\n        # to build in GAE.\n\n        ids = set()\n        for i in [1, 2, 3]:\n            id = getattr(self.params, 'id%d' % i)\n            if not id:\n                break\n            ids.add(id)\n\n        if len(ids) > 1:\n            notes = []\n            for person_id in ids:\n                person = Person.get(self.repo, person_id)\n                person_notes = []\n                for other_id in ids - set([person_id]):\n                    note = Note.create_original(\n                        self.repo,\n                        entry_date=get_utcnow(),                        \n                        person_record_id=person_id,\n                        linked_person_record_id=other_id,\n                        text=self.params.text,\n                        author_name=self.params.author_name,\n                        author_phone=self.params.author_phone,\n                        author_email=self.params.author_email,\n                        source_date=get_utcnow())\n                    person_notes.append(note)\n                # Notify person's subscribers of all new duplicates. We do not\n                # follow links since each Person record in the ids list gets its\n                # own note. However, 1) when > 2 records are marked as\n                # duplicates, subscribers will still receive multiple\n                # notifications, and 2) subscribers to already-linked Persons\n                # will not be notified of the new link.\n                subscribe.send_notifications(self, person, person_notes, False)\n                notes += person_notes\n            # Write all notes to store\n            db.put(notes)\n        self.redirect('/view', id=self.params.id1)\n", "path": "app/multiview.py"}], "after_files": [{"content": "#!/usr/bin/python2.7\n# Copyright 2010 Google Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom model import *\nfrom utils import *\nimport pfif\nimport reveal\nimport subscribe\nimport view\n\nfrom django.utils.translation import ugettext as _\n\n# Fields to show for side-by-side comparison.\nCOMPARE_FIELDS = pfif.PFIF_1_4.fields['person'] + ['primary_full_name']\n\n\nclass Handler(BaseHandler):\n    def get(self):\n        # To handle multiple persons, we create a single object where\n        # each property is a list of values, one for each person.\n        # This makes page rendering easier.\n        person = dict([(prop, []) for prop in COMPARE_FIELDS])\n        any_person = dict([(prop, None) for prop in COMPARE_FIELDS])\n\n        # Get all persons from db.\n        # TODO: Can later optimize to use fewer DB calls.\n        for i in [1, 2, 3]:\n            id = self.request.get('id%d' % i)\n            if not id:\n                break\n            p = Person.get(self.repo, id)\n            if not p:\n                return self.error(\n                    404,\n                    _(\"This person's entry does not exist or has been \"\n                      \"deleted.\"))\n            sanitize_urls(p)\n\n            for prop in COMPARE_FIELDS:\n                val = getattr(p, prop)\n                if prop == 'sex':  # convert enum value to localized text\n                    val = get_person_sex_text(p)\n                person[prop].append(val)\n                any_person[prop] = any_person[prop] or val\n\n        # Compute the local times for the date fields on the person and format.\n        person['source_datetime_local_string'] = map(\n            self.to_formatted_local_datetime, person['source_date'])\n\n        # Check if private info should be revealed.\n        content_id = 'multiview:' + ','.join(person['person_record_id'])\n        reveal_url = reveal.make_reveal_url(self, content_id)\n        show_private_info = reveal.verify(content_id, self.params.signature)\n\n        standalone = self.request.get('standalone')\n\n        # TODO: Handle no persons found.\n\n        person['profile_pages'] = [view.get_profile_pages(profile_urls, self)\n            for profile_urls in person['profile_urls']]\n        any_person['profile_pages'] = any(person['profile_pages'])\n\n        # Note: we're not showing notes and linked persons information\n        # here at the moment.\n        self.render('multiview.html',\n                    person=person, any=any_person, standalone=standalone,\n                    cols=len(person['full_name']) + 1,\n                    onload_function='view_page_loaded()', markdup=True,\n                    show_private_info=show_private_info, reveal_url=reveal_url)\n\n    def post(self):\n        if not self.params.text:\n            return self.error(\n                200, _('Message is required. Please go back and try again.'))\n\n        if not self.params.author_name:\n            return self.error(\n                200, _('Your name is required in the \"About you\" section.  Please go back and try again.'))\n\n        # TODO: To reduce possible abuse, we currently limit to 3 person\n        # match. We could guard using e.g. an XSRF token, which I don't know how\n        # to build in GAE.\n\n        ids = set()\n        for i in [1, 2, 3]:\n            id = getattr(self.params, 'id%d' % i)\n            if not id:\n                break\n            ids.add(id)\n\n        if len(ids) > 1:\n            notes = []\n            for person_id in ids:\n                person = Person.get(self.repo, person_id)\n                person_notes = []\n                for other_id in ids - set([person_id]):\n                    note = Note.create_original(\n                        self.repo,\n                        entry_date=get_utcnow(),\n                        person_record_id=person_id,\n                        linked_person_record_id=other_id,\n                        text=self.params.text,\n                        author_name=self.params.author_name,\n                        author_phone=self.params.author_phone,\n                        author_email=self.params.author_email,\n                        source_date=get_utcnow())\n                    person_notes.append(note)\n                # Notify person's subscribers of all new duplicates. We do not\n                # follow links since each Person record in the ids list gets its\n                # own note. However, 1) when > 2 records are marked as\n                # duplicates, subscribers will still receive multiple\n                # notifications, and 2) subscribers to already-linked Persons\n                # will not be notified of the new link.\n                subscribe.send_notifications(self, person, person_notes, False)\n                notes += person_notes\n            # Write all notes to store\n            db.put(notes)\n        self.redirect('/view', id=self.params.id1)\n", "path": "app/multiview.py"}]}