prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Add delimiter between paragraphs and bullets in open graph descriptions
  Split from #12178 
  
  > I think we might want to make consider making bulleted lists have some sort of delimeter between the bullets (see the Slack preview, which is long enough to run into this, above). Possibly just converting those back into * might be a good idea. Maybe new paragraph into |, and bullets into *?
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `zerver/lib/html_to_text.py`
  Content:
  ```
  1 from typing import List, Optional
  2 
  3 from bs4 import BeautifulSoup
  4 from django.http import HttpRequest
  5 from django.utils.html import escape
  6 
  7 from zerver.lib.cache import cache_with_key, open_graph_description_cache_key
  8 
  9 def html_to_text(content: str, tags: Optional[List[str]]=None) -> str:
  10     bs = BeautifulSoup(content, features='lxml')
  11     # Skip any admonition (warning) blocks, since they're
  12     # usually something about users needing to be an
  13     # organization administrator, and not useful for
  14     # describing the page.
  15     for tag in bs.find_all('div', class_="admonition"):
  16         tag.clear()
  17 
  18     # Skip code-sections, which just contains navigation instructions.
  19     for tag in bs.find_all('div', class_="code-section"):
  20         tag.clear()
  21 
  22     text = ''
  23     if tags is None:
  24         tags = ['p']
  25     for paragraph in bs.find_all(tags):
  26         # .text converts it from HTML to text
  27         text = text + paragraph.text + ' '
  28         if len(text) > 500:
  29             break
  30     return escape(' '.join(text.split()))
  31 
  32 @cache_with_key(open_graph_description_cache_key, timeout=3600*24)
  33 def get_content_description(content: bytes, request: HttpRequest) -> str:
  34     str_content = content.decode("utf-8")
  35     return html_to_text(str_content)
  36
  ```
  
  Path: `zerver/lib/realm_description.py`
  Content:
  ```
  1 from zerver.models import Realm
  2 from zerver.lib.cache import cache_with_key, realm_rendered_description_cache_key, \
  3     realm_text_description_cache_key
  4 from zerver.lib.bugdown import convert as bugdown_convert
  5 from zerver.lib.html_to_text import html_to_text
  6 
  7 @cache_with_key(realm_rendered_description_cache_key, timeout=3600*24*7)
  8 def get_realm_rendered_description(realm: Realm) -> str:
  9     realm_description_raw = realm.description or "The coolest place in the universe."
  10     return bugdown_convert(realm_description_raw, message_realm=realm,
  11                            no_previews=True)
  12 
  13 @cache_with_key(realm_text_description_cache_key, timeout=3600*24*7)
  14 def get_realm_text_description(realm: Realm) -> str:
  15     html_description = get_realm_rendered_description(realm)
  16     return html_to_text(html_description, ['p', 'li'])
  17
  ```
  --- 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/zerver/lib/html_to_text.py b/zerver/lib/html_to_text.py
  --- a/zerver/lib/html_to_text.py
  +++ b/zerver/lib/html_to_text.py
  @@ -1,4 +1,4 @@
  -from typing import List, Optional
  +from typing import Dict, Optional
   
   from bs4 import BeautifulSoup
   from django.http import HttpRequest
  @@ -6,7 +6,7 @@
   
   from zerver.lib.cache import cache_with_key, open_graph_description_cache_key
   
  -def html_to_text(content: str, tags: Optional[List[str]]=None) -> str:
  +def html_to_text(content: str, tags: Optional[Dict[str, str]]=None) -> str:
       bs = BeautifulSoup(content, features='lxml')
       # Skip any admonition (warning) blocks, since they're
       # usually something about users needing to be an
  @@ -21,10 +21,15 @@
   
       text = ''
       if tags is None:
  -        tags = ['p']
  -    for paragraph in bs.find_all(tags):
  +        tags = {'p': ' | '}
  +    for element in bs.find_all(tags.keys()):
  +        # Ignore empty elements
  +        if not element.text:
  +            continue
           # .text converts it from HTML to text
  -        text = text + paragraph.text + ' '
  +        if text:
  +            text += tags[element.name]
  +        text += element.text
           if len(text) > 500:
               break
       return escape(' '.join(text.split()))
  diff --git a/zerver/lib/realm_description.py b/zerver/lib/realm_description.py
  --- a/zerver/lib/realm_description.py
  +++ b/zerver/lib/realm_description.py
  @@ -13,4 +13,4 @@
   @cache_with_key(realm_text_description_cache_key, timeout=3600*24*7)
   def get_realm_text_description(realm: Realm) -> str:
       html_description = get_realm_rendered_description(realm)
  -    return html_to_text(html_description, ['p', 'li'])
  +    return html_to_text(html_description, {'p': ' | ', 'li': ' * '})
  
verification_info: {"golden_diff": "diff --git a/zerver/lib/html_to_text.py b/zerver/lib/html_to_text.py\n--- a/zerver/lib/html_to_text.py\n+++ b/zerver/lib/html_to_text.py\n@@ -1,4 +1,4 @@\n-from typing import List, Optional\n+from typing import Dict, Optional\n \n from bs4 import BeautifulSoup\n from django.http import HttpRequest\n@@ -6,7 +6,7 @@\n \n from zerver.lib.cache import cache_with_key, open_graph_description_cache_key\n \n-def html_to_text(content: str, tags: Optional[List[str]]=None) -> str:\n+def html_to_text(content: str, tags: Optional[Dict[str, str]]=None) -> str:\n     bs = BeautifulSoup(content, features='lxml')\n     # Skip any admonition (warning) blocks, since they're\n     # usually something about users needing to be an\n@@ -21,10 +21,15 @@\n \n     text = ''\n     if tags is None:\n-        tags = ['p']\n-    for paragraph in bs.find_all(tags):\n+        tags = {'p': ' | '}\n+    for element in bs.find_all(tags.keys()):\n+        # Ignore empty elements\n+        if not element.text:\n+            continue\n         # .text converts it from HTML to text\n-        text = text + paragraph.text + ' '\n+        if text:\n+            text += tags[element.name]\n+        text += element.text\n         if len(text) > 500:\n             break\n     return escape(' '.join(text.split()))\ndiff --git a/zerver/lib/realm_description.py b/zerver/lib/realm_description.py\n--- a/zerver/lib/realm_description.py\n+++ b/zerver/lib/realm_description.py\n@@ -13,4 +13,4 @@\n @cache_with_key(realm_text_description_cache_key, timeout=3600*24*7)\n def get_realm_text_description(realm: Realm) -> str:\n     html_description = get_realm_rendered_description(realm)\n-    return html_to_text(html_description, ['p', 'li'])\n+    return html_to_text(html_description, {'p': ' | ', 'li': ' * '})\n", "issue": "Add delimiter between paragraphs and bullets in open graph descriptions\nSplit from #12178 \r\n\r\n> I think we might want to make consider making bulleted lists have some sort of delimeter between the bullets (see the Slack preview, which is long enough to run into this, above). Possibly just converting those back into * might be a good idea. Maybe new paragraph into |, and bullets into *?\n", "before_files": [{"content": "from typing import List, Optional\n\nfrom bs4 import BeautifulSoup\nfrom django.http import HttpRequest\nfrom django.utils.html import escape\n\nfrom zerver.lib.cache import cache_with_key, open_graph_description_cache_key\n\ndef html_to_text(content: str, tags: Optional[List[str]]=None) -> str:\n    bs = BeautifulSoup(content, features='lxml')\n    # Skip any admonition (warning) blocks, since they're\n    # usually something about users needing to be an\n    # organization administrator, and not useful for\n    # describing the page.\n    for tag in bs.find_all('div', class_=\"admonition\"):\n        tag.clear()\n\n    # Skip code-sections, which just contains navigation instructions.\n    for tag in bs.find_all('div', class_=\"code-section\"):\n        tag.clear()\n\n    text = ''\n    if tags is None:\n        tags = ['p']\n    for paragraph in bs.find_all(tags):\n        # .text converts it from HTML to text\n        text = text + paragraph.text + ' '\n        if len(text) > 500:\n            break\n    return escape(' '.join(text.split()))\n\n@cache_with_key(open_graph_description_cache_key, timeout=3600*24)\ndef get_content_description(content: bytes, request: HttpRequest) -> str:\n    str_content = content.decode(\"utf-8\")\n    return html_to_text(str_content)\n", "path": "zerver/lib/html_to_text.py"}, {"content": "from zerver.models import Realm\nfrom zerver.lib.cache import cache_with_key, realm_rendered_description_cache_key, \\\n    realm_text_description_cache_key\nfrom zerver.lib.bugdown import convert as bugdown_convert\nfrom zerver.lib.html_to_text import html_to_text\n\n@cache_with_key(realm_rendered_description_cache_key, timeout=3600*24*7)\ndef get_realm_rendered_description(realm: Realm) -> str:\n    realm_description_raw = realm.description or \"The coolest place in the universe.\"\n    return bugdown_convert(realm_description_raw, message_realm=realm,\n                           no_previews=True)\n\n@cache_with_key(realm_text_description_cache_key, timeout=3600*24*7)\ndef get_realm_text_description(realm: Realm) -> str:\n    html_description = get_realm_rendered_description(realm)\n    return html_to_text(html_description, ['p', 'li'])\n", "path": "zerver/lib/realm_description.py"}], "after_files": [{"content": "from typing import Dict, Optional\n\nfrom bs4 import BeautifulSoup\nfrom django.http import HttpRequest\nfrom django.utils.html import escape\n\nfrom zerver.lib.cache import cache_with_key, open_graph_description_cache_key\n\ndef html_to_text(content: str, tags: Optional[Dict[str, str]]=None) -> str:\n    bs = BeautifulSoup(content, features='lxml')\n    # Skip any admonition (warning) blocks, since they're\n    # usually something about users needing to be an\n    # organization administrator, and not useful for\n    # describing the page.\n    for tag in bs.find_all('div', class_=\"admonition\"):\n        tag.clear()\n\n    # Skip code-sections, which just contains navigation instructions.\n    for tag in bs.find_all('div', class_=\"code-section\"):\n        tag.clear()\n\n    text = ''\n    if tags is None:\n        tags = {'p': ' | '}\n    for element in bs.find_all(tags.keys()):\n        # Ignore empty elements\n        if not element.text:\n            continue\n        # .text converts it from HTML to text\n        if text:\n            text += tags[element.name]\n        text += element.text\n        if len(text) > 500:\n            break\n    return escape(' '.join(text.split()))\n\n@cache_with_key(open_graph_description_cache_key, timeout=3600*24)\ndef get_content_description(content: bytes, request: HttpRequest) -> str:\n    str_content = content.decode(\"utf-8\")\n    return html_to_text(str_content)\n", "path": "zerver/lib/html_to_text.py"}, {"content": "from zerver.models import Realm\nfrom zerver.lib.cache import cache_with_key, realm_rendered_description_cache_key, \\\n    realm_text_description_cache_key\nfrom zerver.lib.bugdown import convert as bugdown_convert\nfrom zerver.lib.html_to_text import html_to_text\n\n@cache_with_key(realm_rendered_description_cache_key, timeout=3600*24*7)\ndef get_realm_rendered_description(realm: Realm) -> str:\n    realm_description_raw = realm.description or \"The coolest place in the universe.\"\n    return bugdown_convert(realm_description_raw, message_realm=realm,\n                           no_previews=True)\n\n@cache_with_key(realm_text_description_cache_key, timeout=3600*24*7)\ndef get_realm_text_description(realm: Realm) -> str:\n    html_description = get_realm_rendered_description(realm)\n    return html_to_text(html_description, {'p': ' | ', 'li': ' * '})\n", "path": "zerver/lib/realm_description.py"}]}