prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Fix `safely_reserve_a_username`
  This function keeps using a cursor after an `IntegrityError` exception is raised, that's invalid and raises another exception. See https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65266388.
  
  Fix `safely_reserve_a_username`
  This function keeps using a cursor after an `IntegrityError` exception is raised, that's invalid and raises another exception. See https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65266388.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `gratipay/utils/username.py`
  Content:
  ```
  1 from psycopg2 import IntegrityError
  2 import random
  3 
  4 
  5 class FailedToReserveUsername(Exception): pass
  6 class RanOutOfUsernameAttempts(Exception): pass
  7 
  8 
  9 def gen_random_usernames():
  10     """Yield random 12-hex-digit unicodes.
  11     """
  12     while 1:
  13         yield hex(int(random.random() * 16**12))[2:].zfill(12).decode('ASCII')
  14 
  15 
  16 def insert_into_participants(cursor, username):
  17     return cursor.one( "INSERT INTO participants (username, username_lower) "
  18                        "VALUES (%s, %s) RETURNING username"
  19                      , (username, username.lower())
  20                       )
  21 
  22 
  23 def safely_reserve_a_username(cursor, gen_usernames=gen_random_usernames,
  24                                                                  reserve=insert_into_participants):
  25     """Safely reserve a username.
  26 
  27     :param cursor: a :py:class:`psycopg2.cursor` managed as a :py:mod:`postgres`
  28         transaction
  29     :param gen_usernames: a generator of usernames to try
  30     :param reserve: a function that takes the cursor and does the SQL
  31         stuff
  32     :database: one ``INSERT`` on average
  33     :returns: a 12-hex-digit unicode
  34     :raises: :py:class:`FailedToReserveUsername` if no acceptable username is found
  35         within 100 attempts, or :py:class:`RanOutOfUsernameAttempts` if the username
  36         generator runs out first
  37 
  38     The returned value is guaranteed to have been reserved in the database.
  39 
  40     """
  41     seatbelt = 0
  42     for username in gen_usernames():
  43         seatbelt += 1
  44         if seatbelt > 100:
  45             raise FailedToReserveUsername
  46 
  47         try:
  48             check = reserve(cursor, username)
  49         except IntegrityError:  # Collision, try again with another value.
  50             continue
  51         else:
  52             assert check == username
  53             break
  54     else:
  55         raise RanOutOfUsernameAttempts
  56     return username
  57
  ```
  --- 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/gratipay/utils/username.py b/gratipay/utils/username.py
  --- a/gratipay/utils/username.py
  +++ b/gratipay/utils/username.py
  @@ -38,6 +38,8 @@
       The returned value is guaranteed to have been reserved in the database.
   
       """
  +    cursor.execute("SAVEPOINT safely_reserve_a_username")
  +
       seatbelt = 0
       for username in gen_usernames():
           seatbelt += 1
  @@ -47,10 +49,13 @@
           try:
               check = reserve(cursor, username)
           except IntegrityError:  # Collision, try again with another value.
  +            cursor.execute("ROLLBACK TO safely_reserve_a_username")
               continue
           else:
               assert check == username
               break
       else:
           raise RanOutOfUsernameAttempts
  +
  +    cursor.execute("RELEASE safely_reserve_a_username")
       return username
  
verification_info: {"golden_diff": "diff --git a/gratipay/utils/username.py b/gratipay/utils/username.py\n--- a/gratipay/utils/username.py\n+++ b/gratipay/utils/username.py\n@@ -38,6 +38,8 @@\n     The returned value is guaranteed to have been reserved in the database.\n \n     \"\"\"\n+    cursor.execute(\"SAVEPOINT safely_reserve_a_username\")\n+\n     seatbelt = 0\n     for username in gen_usernames():\n         seatbelt += 1\n@@ -47,10 +49,13 @@\n         try:\n             check = reserve(cursor, username)\n         except IntegrityError:  # Collision, try again with another value.\n+            cursor.execute(\"ROLLBACK TO safely_reserve_a_username\")\n             continue\n         else:\n             assert check == username\n             break\n     else:\n         raise RanOutOfUsernameAttempts\n+\n+    cursor.execute(\"RELEASE safely_reserve_a_username\")\n     return username\n", "issue": "Fix `safely_reserve_a_username`\nThis function keeps using a cursor after an `IntegrityError` exception is raised, that's invalid and raises another exception. See https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65266388.\n\nFix `safely_reserve_a_username`\nThis function keeps using a cursor after an `IntegrityError` exception is raised, that's invalid and raises another exception. See https://github.com/gratipay/gratipay.com/pull/2752#issuecomment-65266388.\n\n", "before_files": [{"content": "from psycopg2 import IntegrityError\nimport random\n\n\nclass FailedToReserveUsername(Exception): pass\nclass RanOutOfUsernameAttempts(Exception): pass\n\n\ndef gen_random_usernames():\n    \"\"\"Yield random 12-hex-digit unicodes.\n    \"\"\"\n    while 1:\n        yield hex(int(random.random() * 16**12))[2:].zfill(12).decode('ASCII')\n\n\ndef insert_into_participants(cursor, username):\n    return cursor.one( \"INSERT INTO participants (username, username_lower) \"\n                       \"VALUES (%s, %s) RETURNING username\"\n                     , (username, username.lower())\n                      )\n\n\ndef safely_reserve_a_username(cursor, gen_usernames=gen_random_usernames,\n                                                                 reserve=insert_into_participants):\n    \"\"\"Safely reserve a username.\n\n    :param cursor: a :py:class:`psycopg2.cursor` managed as a :py:mod:`postgres`\n        transaction\n    :param gen_usernames: a generator of usernames to try\n    :param reserve: a function that takes the cursor and does the SQL\n        stuff\n    :database: one ``INSERT`` on average\n    :returns: a 12-hex-digit unicode\n    :raises: :py:class:`FailedToReserveUsername` if no acceptable username is found\n        within 100 attempts, or :py:class:`RanOutOfUsernameAttempts` if the username\n        generator runs out first\n\n    The returned value is guaranteed to have been reserved in the database.\n\n    \"\"\"\n    seatbelt = 0\n    for username in gen_usernames():\n        seatbelt += 1\n        if seatbelt > 100:\n            raise FailedToReserveUsername\n\n        try:\n            check = reserve(cursor, username)\n        except IntegrityError:  # Collision, try again with another value.\n            continue\n        else:\n            assert check == username\n            break\n    else:\n        raise RanOutOfUsernameAttempts\n    return username\n", "path": "gratipay/utils/username.py"}], "after_files": [{"content": "from psycopg2 import IntegrityError\nimport random\n\n\nclass FailedToReserveUsername(Exception): pass\nclass RanOutOfUsernameAttempts(Exception): pass\n\n\ndef gen_random_usernames():\n    \"\"\"Yield random 12-hex-digit unicodes.\n    \"\"\"\n    while 1:\n        yield hex(int(random.random() * 16**12))[2:].zfill(12).decode('ASCII')\n\n\ndef insert_into_participants(cursor, username):\n    return cursor.one( \"INSERT INTO participants (username, username_lower) \"\n                       \"VALUES (%s, %s) RETURNING username\"\n                     , (username, username.lower())\n                      )\n\n\ndef safely_reserve_a_username(cursor, gen_usernames=gen_random_usernames,\n                                                                 reserve=insert_into_participants):\n    \"\"\"Safely reserve a username.\n\n    :param cursor: a :py:class:`psycopg2.cursor` managed as a :py:mod:`postgres`\n        transaction\n    :param gen_usernames: a generator of usernames to try\n    :param reserve: a function that takes the cursor and does the SQL\n        stuff\n    :database: one ``INSERT`` on average\n    :returns: a 12-hex-digit unicode\n    :raises: :py:class:`FailedToReserveUsername` if no acceptable username is found\n        within 100 attempts, or :py:class:`RanOutOfUsernameAttempts` if the username\n        generator runs out first\n\n    The returned value is guaranteed to have been reserved in the database.\n\n    \"\"\"\n    cursor.execute(\"SAVEPOINT safely_reserve_a_username\")\n\n    seatbelt = 0\n    for username in gen_usernames():\n        seatbelt += 1\n        if seatbelt > 100:\n            raise FailedToReserveUsername\n\n        try:\n            check = reserve(cursor, username)\n        except IntegrityError:  # Collision, try again with another value.\n            cursor.execute(\"ROLLBACK TO safely_reserve_a_username\")\n            continue\n        else:\n            assert check == username\n            break\n    else:\n        raise RanOutOfUsernameAttempts\n\n    cursor.execute(\"RELEASE safely_reserve_a_username\")\n    return username\n", "path": "gratipay/utils/username.py"}]}