prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  `manage.py change_user_role --help` should self-document the set of roles it supports
  Right now, the only way it self-documents this is when you try an invalid role:
  
  ```
  manage.py change_user_role: error: argument <new_role>: invalid choice: 'is_billing_administrator' (choose from 'owner', 'admin', 'moderator', 'member', 'guest', 'can_forge_sender', 'can_create_users', 'is_billing_admin')
  ```
  
  </issue>
  <code>
  [start of zerver/management/commands/change_user_role.py]
  1 from argparse import ArgumentParser
  2 from typing import Any
  3 
  4 from django.core.management.base import CommandError
  5 from typing_extensions import override
  6 
  7 from zerver.actions.users import (
  8     do_change_can_create_users,
  9     do_change_can_forge_sender,
  10     do_change_is_billing_admin,
  11     do_change_user_role,
  12 )
  13 from zerver.lib.management import ZulipBaseCommand
  14 from zerver.models import UserProfile
  15 
  16 
  17 class Command(ZulipBaseCommand):
  18     help = """Change role of an existing user in their (own) Realm.
  19 
  20 ONLY perform this on customer request from an authorized person.
  21 """
  22 
  23     @override
  24     def add_arguments(self, parser: ArgumentParser) -> None:
  25         parser.add_argument("email", metavar="<email>", help="email of user to change role")
  26         parser.add_argument(
  27             "new_role",
  28             metavar="<new_role>",
  29             choices=[
  30                 "owner",
  31                 "admin",
  32                 "moderator",
  33                 "member",
  34                 "guest",
  35                 "can_forge_sender",
  36                 "can_create_users",
  37                 "is_billing_admin",
  38             ],
  39             help="new role of the user",
  40         )
  41         parser.add_argument(
  42             "--revoke",
  43             dest="grant",
  44             action="store_false",
  45             help="Remove can_forge_sender or can_create_users permission.",
  46         )
  47         self.add_realm_args(parser, required=True)
  48 
  49     @override
  50     def handle(self, *args: Any, **options: Any) -> None:
  51         email = options["email"]
  52         realm = self.get_realm(options)
  53 
  54         user = self.get_user(email, realm)
  55 
  56         user_role_map = {
  57             "owner": UserProfile.ROLE_REALM_OWNER,
  58             "admin": UserProfile.ROLE_REALM_ADMINISTRATOR,
  59             "moderator": UserProfile.ROLE_MODERATOR,
  60             "member": UserProfile.ROLE_MEMBER,
  61             "guest": UserProfile.ROLE_GUEST,
  62         }
  63 
  64         if options["new_role"] not in ["can_forge_sender", "can_create_users", "is_billing_admin"]:
  65             new_role = user_role_map[options["new_role"]]
  66             if not options["grant"]:
  67                 raise CommandError(
  68                     "Revoke not supported with this permission; please specify new role."
  69                 )
  70             if new_role == user.role:
  71                 raise CommandError("User already has this role.")
  72             old_role_name = UserProfile.ROLE_ID_TO_NAME_MAP[user.role]
  73             do_change_user_role(user, new_role, acting_user=None)
  74             new_role_name = UserProfile.ROLE_ID_TO_NAME_MAP[user.role]
  75             print(
  76                 f"Role for {user.delivery_email} changed from {old_role_name} to {new_role_name}."
  77             )
  78             return
  79 
  80         if options["new_role"] == "can_forge_sender":
  81             if user.can_forge_sender and options["grant"]:
  82                 raise CommandError("User can already forge messages for this realm.")
  83             elif not user.can_forge_sender and not options["grant"]:
  84                 raise CommandError("User can't forge messages for this realm.")
  85             do_change_can_forge_sender(user, options["grant"])
  86 
  87             granted_text = "have" if options["grant"] else "not have"
  88             print(
  89                 f"{user.delivery_email} changed to {granted_text} {options['new_role']} permission."
  90             )
  91         elif options["new_role"] == "can_create_users":
  92             if user.can_create_users and options["grant"]:
  93                 raise CommandError("User can already create users for this realm.")
  94             elif not user.can_create_users and not options["grant"]:
  95                 raise CommandError("User can't create users for this realm.")
  96             do_change_can_create_users(user, options["grant"])
  97         else:
  98             assert options["new_role"] == "is_billing_admin"
  99             if user.is_billing_admin and options["grant"]:
  100                 raise CommandError("User already is a billing admin for this realm.")
  101             elif not user.is_billing_admin and not options["grant"]:
  102                 raise CommandError("User is not a billing admin for this realm.")
  103 
  104             do_change_is_billing_admin(user, options["grant"])
  105
  [end of zerver/management/commands/change_user_role.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/zerver/management/commands/change_user_role.py b/zerver/management/commands/change_user_role.py
  --- a/zerver/management/commands/change_user_role.py
  +++ b/zerver/management/commands/change_user_role.py
  @@ -13,6 +13,17 @@
   from zerver.lib.management import ZulipBaseCommand
   from zerver.models import UserProfile
   
  +ROLE_CHOICES = [
  +    "owner",
  +    "admin",
  +    "moderator",
  +    "member",
  +    "guest",
  +    "can_forge_sender",
  +    "can_create_users",
  +    "is_billing_admin",
  +]
  +
   
   class Command(ZulipBaseCommand):
       help = """Change role of an existing user in their (own) Realm.
  @@ -26,17 +37,8 @@
           parser.add_argument(
               "new_role",
               metavar="<new_role>",
  -            choices=[
  -                "owner",
  -                "admin",
  -                "moderator",
  -                "member",
  -                "guest",
  -                "can_forge_sender",
  -                "can_create_users",
  -                "is_billing_admin",
  -            ],
  -            help="new role of the user",
  +            choices=ROLE_CHOICES,
  +            help="new role of the user; choose from " + ", ".join(ROLE_CHOICES),
           )
           parser.add_argument(
               "--revoke",
  
verification_info: {"golden_diff": "diff --git a/zerver/management/commands/change_user_role.py b/zerver/management/commands/change_user_role.py\n--- a/zerver/management/commands/change_user_role.py\n+++ b/zerver/management/commands/change_user_role.py\n@@ -13,6 +13,17 @@\n from zerver.lib.management import ZulipBaseCommand\n from zerver.models import UserProfile\n \n+ROLE_CHOICES = [\n+    \"owner\",\n+    \"admin\",\n+    \"moderator\",\n+    \"member\",\n+    \"guest\",\n+    \"can_forge_sender\",\n+    \"can_create_users\",\n+    \"is_billing_admin\",\n+]\n+\n \n class Command(ZulipBaseCommand):\n     help = \"\"\"Change role of an existing user in their (own) Realm.\n@@ -26,17 +37,8 @@\n         parser.add_argument(\n             \"new_role\",\n             metavar=\"<new_role>\",\n-            choices=[\n-                \"owner\",\n-                \"admin\",\n-                \"moderator\",\n-                \"member\",\n-                \"guest\",\n-                \"can_forge_sender\",\n-                \"can_create_users\",\n-                \"is_billing_admin\",\n-            ],\n-            help=\"new role of the user\",\n+            choices=ROLE_CHOICES,\n+            help=\"new role of the user; choose from \" + \", \".join(ROLE_CHOICES),\n         )\n         parser.add_argument(\n             \"--revoke\",\n", "issue": "`manage.py change_user_role --help` should self-document the set of roles it supports\nRight now, the only way it self-documents this is when you try an invalid role:\r\n\r\n```\r\nmanage.py change_user_role: error: argument <new_role>: invalid choice: 'is_billing_administrator' (choose from 'owner', 'admin', 'moderator', 'member', 'guest', 'can_forge_sender', 'can_create_users', 'is_billing_admin')\r\n```\n", "before_files": [{"content": "from argparse import ArgumentParser\nfrom typing import Any\n\nfrom django.core.management.base import CommandError\nfrom typing_extensions import override\n\nfrom zerver.actions.users import (\n    do_change_can_create_users,\n    do_change_can_forge_sender,\n    do_change_is_billing_admin,\n    do_change_user_role,\n)\nfrom zerver.lib.management import ZulipBaseCommand\nfrom zerver.models import UserProfile\n\n\nclass Command(ZulipBaseCommand):\n    help = \"\"\"Change role of an existing user in their (own) Realm.\n\nONLY perform this on customer request from an authorized person.\n\"\"\"\n\n    @override\n    def add_arguments(self, parser: ArgumentParser) -> None:\n        parser.add_argument(\"email\", metavar=\"<email>\", help=\"email of user to change role\")\n        parser.add_argument(\n            \"new_role\",\n            metavar=\"<new_role>\",\n            choices=[\n                \"owner\",\n                \"admin\",\n                \"moderator\",\n                \"member\",\n                \"guest\",\n                \"can_forge_sender\",\n                \"can_create_users\",\n                \"is_billing_admin\",\n            ],\n            help=\"new role of the user\",\n        )\n        parser.add_argument(\n            \"--revoke\",\n            dest=\"grant\",\n            action=\"store_false\",\n            help=\"Remove can_forge_sender or can_create_users permission.\",\n        )\n        self.add_realm_args(parser, required=True)\n\n    @override\n    def handle(self, *args: Any, **options: Any) -> None:\n        email = options[\"email\"]\n        realm = self.get_realm(options)\n\n        user = self.get_user(email, realm)\n\n        user_role_map = {\n            \"owner\": UserProfile.ROLE_REALM_OWNER,\n            \"admin\": UserProfile.ROLE_REALM_ADMINISTRATOR,\n            \"moderator\": UserProfile.ROLE_MODERATOR,\n            \"member\": UserProfile.ROLE_MEMBER,\n            \"guest\": UserProfile.ROLE_GUEST,\n        }\n\n        if options[\"new_role\"] not in [\"can_forge_sender\", \"can_create_users\", \"is_billing_admin\"]:\n            new_role = user_role_map[options[\"new_role\"]]\n            if not options[\"grant\"]:\n                raise CommandError(\n                    \"Revoke not supported with this permission; please specify new role.\"\n                )\n            if new_role == user.role:\n                raise CommandError(\"User already has this role.\")\n            old_role_name = UserProfile.ROLE_ID_TO_NAME_MAP[user.role]\n            do_change_user_role(user, new_role, acting_user=None)\n            new_role_name = UserProfile.ROLE_ID_TO_NAME_MAP[user.role]\n            print(\n                f\"Role for {user.delivery_email} changed from {old_role_name} to {new_role_name}.\"\n            )\n            return\n\n        if options[\"new_role\"] == \"can_forge_sender\":\n            if user.can_forge_sender and options[\"grant\"]:\n                raise CommandError(\"User can already forge messages for this realm.\")\n            elif not user.can_forge_sender and not options[\"grant\"]:\n                raise CommandError(\"User can't forge messages for this realm.\")\n            do_change_can_forge_sender(user, options[\"grant\"])\n\n            granted_text = \"have\" if options[\"grant\"] else \"not have\"\n            print(\n                f\"{user.delivery_email} changed to {granted_text} {options['new_role']} permission.\"\n            )\n        elif options[\"new_role\"] == \"can_create_users\":\n            if user.can_create_users and options[\"grant\"]:\n                raise CommandError(\"User can already create users for this realm.\")\n            elif not user.can_create_users and not options[\"grant\"]:\n                raise CommandError(\"User can't create users for this realm.\")\n            do_change_can_create_users(user, options[\"grant\"])\n        else:\n            assert options[\"new_role\"] == \"is_billing_admin\"\n            if user.is_billing_admin and options[\"grant\"]:\n                raise CommandError(\"User already is a billing admin for this realm.\")\n            elif not user.is_billing_admin and not options[\"grant\"]:\n                raise CommandError(\"User is not a billing admin for this realm.\")\n\n            do_change_is_billing_admin(user, options[\"grant\"])\n", "path": "zerver/management/commands/change_user_role.py"}]}