prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Name parser
  At ingestion time, we are often given data that is not split into BibTeX's "surname, given name" format. We therefore split it ourselves, heuristically, which often fails. Python has a [name parser](https://pypi.org/project/nameparser/) module, but it doesn't work on all Anthology names, either, e.g.,:
  
  - José Alejandro Lopez Gonzalez
  - Philippe Boula de Mareüil
  
  It would be cool to implement our own name parser and train it on the Anthology data. (I imagine that applying the trained model would turn up some mistakes in our data).
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `bin/likely_name_split.py`
  Content:
  ```
  1 #!/usr/bin/env python3
  2 # Daniel Gildea, 2020
  3 
  4 """Usage: likely_name_split.py [--importdir=DIR]
  5 
  6 Counts first and last names in anthology.
  7 Predicts best split into first and last.
  8 Checks whether current names match our predictions.
  9 
  10 Options:
  11   --importdir=DIR          Directory to import XML files from. [default: {scriptdir}/../data/]
  12   -h, --help               Display this helpful text.
  13 """
  14 
  15 from collections import defaultdict
  16 from docopt import docopt
  17 import re
  18 import os
  19 from math import *
  20 
  21 from anthology import Anthology
  22 from anthology.people import PersonName
  23 
  24 
  25 class NameSplitter:
  26     def __init__(self, anthology):
  27         # counts of how often each name appears
  28         self.first_count = defaultdict(lambda: 0)  # "Maria" "Victoria"
  29         self.first_full_count = defaultdict(lambda: 0)  # "Maria Victoria"
  30         self.last_count = defaultdict(lambda: 0)  # "van" "den" "Bosch"
  31         self.last_full_count = defaultdict(lambda: 0)  # "van den Bosch"
  32         self.first_total = 0
  33         self.last_total = 0
  34 
  35         self.count_names(anthology)
  36 
  37     # counts names in anthology database into global vars
  38     # first_count last_count (dicts)
  39     # first_full_count last_full_count (dicts)
  40     # first_total last_total (floats)
  41     def count_names(self, anthology):
  42         for person in anthology.people.personids():
  43             name = anthology.people.get_canonical_name(person)
  44             num_papers = len(anthology.people.get_papers(person)) + 0.0
  45             # print(name.last, ", ", name.first, num_papers)
  46             for w in name.first.split(" "):
  47                 self.first_count[w] += num_papers
  48             self.first_full_count[name.first] += num_papers
  49             self.first_total += num_papers
  50 
  51             for w in name.last.split(" "):
  52                 self.last_count[w] += num_papers
  53             self.last_full_count[name.last] += num_papers
  54             self.last_total += num_papers
  55 
  56     # takes "Maria Victoria Lopez Gonzalez"
  57     # returns ("Lopez Gonzalez", "Maria Victoria")
  58     # uses counts of words in first and last names in current database
  59     def best_split(self, name):
  60         if "," in name:
  61             # Short-circuit names that are already split
  62             surname, given_names = name.split(",")
  63             return (surname.strip(), given_names.strip())
  64 
  65         words = name.split(" ")
  66         best_score = -inf
  67         best = ("", "")
  68         # loop over possible split points between first/last
  69         for i in range(1, len(words)):  # at least one word in each part
  70             first = " ".join(words[0:i])
  71             last = " ".join(words[i:])
  72             # max of log prob of "Maria Victoria" and
  73             # log prob of "Maria" + log prob of "Victoria"
  74             first_probs = [
  75                 log((self.first_count[x] + 0.01) / self.first_total) for x in words[0:i]
  76             ]
  77             first_score = max(
  78                 log((self.first_full_count[first] + 0.000001) / self.first_total),
  79                 sum(first_probs),
  80             )
  81             last_probs = [
  82                 log((self.last_count[x] + 0.01) / self.last_total) for x in words[i:]
  83             ]
  84             last_score = max(
  85                 log((self.last_full_count[last] + 0.000001) / self.last_total),
  86                 sum(last_probs),
  87             )
  88 
  89             if first_score + last_score > best_score:
  90                 best_score = first_score + last_score
  91                 best = (last, first)
  92             # end of loop over split points
  93         return best
  94 
  95 
  96 if __name__ == "__main__":
  97     args = docopt(__doc__)
  98     scriptdir = os.path.dirname(os.path.abspath(__file__))
  99     if "{scriptdir}" in args["--importdir"]:
  100         args["--importdir"] = os.path.abspath(
  101             args["--importdir"].format(scriptdir=scriptdir)
  102         )
  103 
  104     anthology = Anthology(importdir=args["--importdir"])
  105     splitter = NameSplitter(anthology)
  106 
  107     # for all names currently in anthology,
  108     # see if they match what we predict
  109     for person in anthology.people.personids():
  110         name = anthology.people.get_canonical_name(person)
  111 
  112         # find our prediction of split
  113         best = splitter.best_split(name.first + " " + name.last)
  114 
  115         # if current split does not match our prediction
  116         if not (best[0] == name.last and best[1] == name.first):
  117             # print suggested replacement
  118             print(name.last, ",", name.first, "  ==>  ", best[0], ",", best[1])
  119
  ```
  --- 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/bin/likely_name_split.py b/bin/likely_name_split.py
  --- a/bin/likely_name_split.py
  +++ b/bin/likely_name_split.py
  @@ -57,8 +57,9 @@
       # returns ("Lopez Gonzalez", "Maria Victoria")
       # uses counts of words in first and last names in current database
       def best_split(self, name):
  -        if "," in name:
  +        if "," in name and not "Jr." in name:
               # Short-circuit names that are already split
  +            # comma in "William Baumgartner, Jr." does not count as a split
               surname, given_names = name.split(",")
               return (surname.strip(), given_names.strip())
  
verification_info: {"golden_diff": "diff --git a/bin/likely_name_split.py b/bin/likely_name_split.py\n--- a/bin/likely_name_split.py\n+++ b/bin/likely_name_split.py\n@@ -57,8 +57,9 @@\n     # returns (\"Lopez Gonzalez\", \"Maria Victoria\")\n     # uses counts of words in first and last names in current database\n     def best_split(self, name):\n-        if \",\" in name:\n+        if \",\" in name and not \"Jr.\" in name:\n             # Short-circuit names that are already split\n+            # comma in \"William Baumgartner, Jr.\" does not count as a split\n             surname, given_names = name.split(\",\")\n             return (surname.strip(), given_names.strip())\n", "issue": "Name parser\nAt ingestion time, we are often given data that is not split into BibTeX's \"surname, given name\" format. We therefore split it ourselves, heuristically, which often fails. Python has a [name parser](https://pypi.org/project/nameparser/) module, but it doesn't work on all Anthology names, either, e.g.,:\r\n\r\n- Jos\u00e9 Alejandro Lopez Gonzalez\r\n- Philippe Boula de Mare\u00fcil\r\n\r\nIt would be cool to implement our own name parser and train it on the Anthology data. (I imagine that applying the trained model would turn up some mistakes in our data).\n", "before_files": [{"content": "#!/usr/bin/env python3\n# Daniel Gildea, 2020\n\n\"\"\"Usage: likely_name_split.py [--importdir=DIR]\n\nCounts first and last names in anthology.\nPredicts best split into first and last.\nChecks whether current names match our predictions.\n\nOptions:\n  --importdir=DIR          Directory to import XML files from. [default: {scriptdir}/../data/]\n  -h, --help               Display this helpful text.\n\"\"\"\n\nfrom collections import defaultdict\nfrom docopt import docopt\nimport re\nimport os\nfrom math import *\n\nfrom anthology import Anthology\nfrom anthology.people import PersonName\n\n\nclass NameSplitter:\n    def __init__(self, anthology):\n        # counts of how often each name appears\n        self.first_count = defaultdict(lambda: 0)  # \"Maria\" \"Victoria\"\n        self.first_full_count = defaultdict(lambda: 0)  # \"Maria Victoria\"\n        self.last_count = defaultdict(lambda: 0)  # \"van\" \"den\" \"Bosch\"\n        self.last_full_count = defaultdict(lambda: 0)  # \"van den Bosch\"\n        self.first_total = 0\n        self.last_total = 0\n\n        self.count_names(anthology)\n\n    # counts names in anthology database into global vars\n    # first_count last_count (dicts)\n    # first_full_count last_full_count (dicts)\n    # first_total last_total (floats)\n    def count_names(self, anthology):\n        for person in anthology.people.personids():\n            name = anthology.people.get_canonical_name(person)\n            num_papers = len(anthology.people.get_papers(person)) + 0.0\n            # print(name.last, \", \", name.first, num_papers)\n            for w in name.first.split(\" \"):\n                self.first_count[w] += num_papers\n            self.first_full_count[name.first] += num_papers\n            self.first_total += num_papers\n\n            for w in name.last.split(\" \"):\n                self.last_count[w] += num_papers\n            self.last_full_count[name.last] += num_papers\n            self.last_total += num_papers\n\n    # takes \"Maria Victoria Lopez Gonzalez\"\n    # returns (\"Lopez Gonzalez\", \"Maria Victoria\")\n    # uses counts of words in first and last names in current database\n    def best_split(self, name):\n        if \",\" in name:\n            # Short-circuit names that are already split\n            surname, given_names = name.split(\",\")\n            return (surname.strip(), given_names.strip())\n\n        words = name.split(\" \")\n        best_score = -inf\n        best = (\"\", \"\")\n        # loop over possible split points between first/last\n        for i in range(1, len(words)):  # at least one word in each part\n            first = \" \".join(words[0:i])\n            last = \" \".join(words[i:])\n            # max of log prob of \"Maria Victoria\" and\n            # log prob of \"Maria\" + log prob of \"Victoria\"\n            first_probs = [\n                log((self.first_count[x] + 0.01) / self.first_total) for x in words[0:i]\n            ]\n            first_score = max(\n                log((self.first_full_count[first] + 0.000001) / self.first_total),\n                sum(first_probs),\n            )\n            last_probs = [\n                log((self.last_count[x] + 0.01) / self.last_total) for x in words[i:]\n            ]\n            last_score = max(\n                log((self.last_full_count[last] + 0.000001) / self.last_total),\n                sum(last_probs),\n            )\n\n            if first_score + last_score > best_score:\n                best_score = first_score + last_score\n                best = (last, first)\n            # end of loop over split points\n        return best\n\n\nif __name__ == \"__main__\":\n    args = docopt(__doc__)\n    scriptdir = os.path.dirname(os.path.abspath(__file__))\n    if \"{scriptdir}\" in args[\"--importdir\"]:\n        args[\"--importdir\"] = os.path.abspath(\n            args[\"--importdir\"].format(scriptdir=scriptdir)\n        )\n\n    anthology = Anthology(importdir=args[\"--importdir\"])\n    splitter = NameSplitter(anthology)\n\n    # for all names currently in anthology,\n    # see if they match what we predict\n    for person in anthology.people.personids():\n        name = anthology.people.get_canonical_name(person)\n\n        # find our prediction of split\n        best = splitter.best_split(name.first + \" \" + name.last)\n\n        # if current split does not match our prediction\n        if not (best[0] == name.last and best[1] == name.first):\n            # print suggested replacement\n            print(name.last, \",\", name.first, \"  ==>  \", best[0], \",\", best[1])\n", "path": "bin/likely_name_split.py"}], "after_files": [{"content": "#!/usr/bin/env python3\n# Daniel Gildea, 2020\n\n\"\"\"Usage: likely_name_split.py [--importdir=DIR]\n\nCounts first and last names in anthology.\nPredicts best split into first and last.\nChecks whether current names match our predictions.\n\nOptions:\n  --importdir=DIR          Directory to import XML files from. [default: {scriptdir}/../data/]\n  -h, --help               Display this helpful text.\n\"\"\"\n\nfrom collections import defaultdict\nfrom docopt import docopt\nimport re\nimport os\nfrom math import *\n\nfrom anthology import Anthology\nfrom anthology.people import PersonName\n\n\nclass NameSplitter:\n    def __init__(self, anthology):\n        # counts of how often each name appears\n        self.first_count = defaultdict(lambda: 0)  # \"Maria\" \"Victoria\"\n        self.first_full_count = defaultdict(lambda: 0)  # \"Maria Victoria\"\n        self.last_count = defaultdict(lambda: 0)  # \"van\" \"den\" \"Bosch\"\n        self.last_full_count = defaultdict(lambda: 0)  # \"van den Bosch\"\n        self.first_total = 0\n        self.last_total = 0\n\n        self.count_names(anthology)\n\n    # counts names in anthology database into global vars\n    # first_count last_count (dicts)\n    # first_full_count last_full_count (dicts)\n    # first_total last_total (floats)\n    def count_names(self, anthology):\n        for person in anthology.people.personids():\n            name = anthology.people.get_canonical_name(person)\n            num_papers = len(anthology.people.get_papers(person)) + 0.0\n            # print(name.last, \", \", name.first, num_papers)\n            for w in name.first.split(\" \"):\n                self.first_count[w] += num_papers\n            self.first_full_count[name.first] += num_papers\n            self.first_total += num_papers\n\n            for w in name.last.split(\" \"):\n                self.last_count[w] += num_papers\n            self.last_full_count[name.last] += num_papers\n            self.last_total += num_papers\n\n    # takes \"Maria Victoria Lopez Gonzalez\"\n    # returns (\"Lopez Gonzalez\", \"Maria Victoria\")\n    # uses counts of words in first and last names in current database\n    def best_split(self, name):\n        if \",\" in name and not \"Jr.\" in name:\n            # Short-circuit names that are already split\n            # comma in \"William Baumgartner, Jr.\" does not count as a split\n            surname, given_names = name.split(\",\")\n            return (surname.strip(), given_names.strip())\n\n        words = name.split(\" \")\n        best_score = -inf\n        best = (\"\", \"\")\n        # loop over possible split points between first/last\n        for i in range(1, len(words)):  # at least one word in each part\n            first = \" \".join(words[0:i])\n            last = \" \".join(words[i:])\n            # max of log prob of \"Maria Victoria\" and\n            # log prob of \"Maria\" + log prob of \"Victoria\"\n            first_probs = [\n                log((self.first_count[x] + 0.01) / self.first_total) for x in words[0:i]\n            ]\n            first_score = max(\n                log((self.first_full_count[first] + 0.000001) / self.first_total),\n                sum(first_probs),\n            )\n            last_probs = [\n                log((self.last_count[x] + 0.01) / self.last_total) for x in words[i:]\n            ]\n            last_score = max(\n                log((self.last_full_count[last] + 0.000001) / self.last_total),\n                sum(last_probs),\n            )\n\n            if first_score + last_score > best_score:\n                best_score = first_score + last_score\n                best = (last, first)\n            # end of loop over split points\n        return best\n\n\nif __name__ == \"__main__\":\n    args = docopt(__doc__)\n    scriptdir = os.path.dirname(os.path.abspath(__file__))\n    if \"{scriptdir}\" in args[\"--importdir\"]:\n        args[\"--importdir\"] = os.path.abspath(\n            args[\"--importdir\"].format(scriptdir=scriptdir)\n        )\n\n    anthology = Anthology(importdir=args[\"--importdir\"])\n    splitter = NameSplitter(anthology)\n\n    # for all names currently in anthology,\n    # see if they match what we predict\n    for person in anthology.people.personids():\n        name = anthology.people.get_canonical_name(person)\n\n        # find our prediction of split\n        best = splitter.best_split(name.first + \" \" + name.last)\n\n        # if current split does not match our prediction\n        if not (best[0] == name.last and best[1] == name.first):\n            # print suggested replacement\n            print(name.last, \",\", name.first, \"  ==>  \", best[0], \",\", best[1])\n", "path": "bin/likely_name_split.py"}]}