We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Improve the message in Parquet conversion discussions
see https://huggingface.slack.com/archives/C02V51Q3800/p1707388935912969 (internal)

> Would it make sense to add some message in Parquet PRs (e.g. https://huggingface.co/datasets/huggan/smithsonian_butterflies_subset/discussions/2#65c41c1580497543ca3f8a5a) for less technical people?
> As an aside, I don't think the docs really mention the advantages of Parquet even if we link there for advantages (https://huggingface.co/docs/datasets-server/parquet)
> For example
> ```
> [bot] [No action needed] Conversion to Parquet
> 
> The parquet-converter bot has created a version of this dataset in the Parquet format in the `refs/convert/parquet` branch. This will allow X, Y, Z.
> 
> You can learn more about the advantages associated with this format in the documentation.
> ```

related to https://github.com/huggingface/datasets-server/issues/2349#issuecomment-1916292176


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `jobs/cache_maintenance/src/cache_maintenance/discussions.py`
Content:
```
1 # SPDX-License-Identifier: Apache-2.0
2 # Copyright 2023 The HuggingFace Authors.
3 
4 import logging
5 from dataclasses import dataclass
6 from typing import Literal, Optional
7 from urllib import parse
8 
9 from huggingface_hub import HfApi
10 from huggingface_hub.constants import REPO_TYPE_DATASET
11 from libcommon.simple_cache import get_datasets_with_last_updated_kind
12 
13 PARQUET_CACHE_KIND = "config-parquet"
14 DAYS = 1
15 
16 
17 @dataclass
18 class ParquetCounters:
19     datasets: int = 0
20     new_discussions: int = 0
21     dismissed_discussions: int = 0
22     errors: int = 0
23 
24 
25 @dataclass
26 class Counters:
27     parquet: ParquetCounters
28 
29 
30 def post_messages(
31     hf_endpoint: str, bot_associated_user_name: Optional[str], bot_token: Optional[str], parquet_revision: str
32 ) -> Counters:
33     """
34     Post messages in Hub discussions to notify users.
35     """
36     if not (bot_associated_user_name and bot_token):
37         raise Exception("No bot token or user name provided, skipping posting messages.")
38 
39     return Counters(
40         parquet=post_messages_on_parquet_conversion(
41             hf_endpoint=hf_endpoint,
42             bot_associated_user_name=bot_associated_user_name,
43             bot_token=bot_token,
44             parquet_revision=parquet_revision,
45         )
46     )
47 
48 
49 def post_messages_on_parquet_conversion(
50     hf_endpoint: str,
51     bot_associated_user_name: str,
52     bot_token: str,
53     parquet_revision: str,
54 ) -> ParquetCounters:
55     logging.info("Create a Hub discussion to notify about parquet conversion")
56     datasets = limit_to_one_dataset_per_namespace(
57         get_datasets_with_last_updated_kind(kind=PARQUET_CACHE_KIND, days=DAYS)
58     )
59 
60     logging.info(f"Creating discussions for {len(datasets)} datasets")
61     log_batch = 100
62     counters = ParquetCounters()
63 
64     def get_log() -> str:
65         return (
66             f" [{counters.datasets}/{len(datasets)}] {counters.new_discussions} discussions"
67             f" have been opened, {counters.dismissed_discussions} datasets"
68             f" already had a discussion (open or closed). {counters.errors} errors."
69         )
70 
71     hf_api = HfApi(endpoint=hf_endpoint, token=bot_token)
72 
73     for dataset in datasets:
74         counters.datasets += 1
75         prefix = f"[{counters.datasets}/{len(datasets)}]"
76         logging.info(f"{prefix} Processing dataset {dataset}")
77         try:
78             try:
79                 next(
80                     hf_api.get_repo_discussions(
81                         repo_id=dataset, repo_type=REPO_TYPE_DATASET, token=bot_token, author=bot_associated_user_name
82                     )
83                 )
84                 # if we get here, the bot has already opened a discussion for this dataset
85                 counters.dismissed_discussions += 1
86                 logging.info(f"{prefix} [dismissed] Dataset {dataset} already has a discussion, skipping")
87             except StopIteration:
88                 hf_api.create_discussion(
89                     repo_id=dataset,
90                     repo_type=REPO_TYPE_DATASET,
91                     title="[bot] Conversion to Parquet",
92                     description=create_discussion_description(
93                         dataset=dataset,
94                         hf_endpoint=hf_endpoint,
95                         parquet_revision=parquet_revision,
96                         bot_associated_user_name=bot_associated_user_name,
97                     ),
98                     token=bot_token,
99                 )
100                 counters.new_discussions += 1
101                 logging.info(f"{prefix} [new] Dataset {dataset} has a new discussion")
102         except Exception as e:
103             counters.errors += 1
104             logging.warning(f"{prefix} [error] Failed to process dataset {dataset}: {e}")
105 
106         logging.debug(get_log())
107         if (counters.datasets) % log_batch == 0:
108             logging.info(get_log())
109 
110     logging.info(get_log())
111     logging.info("All the messages about parquet conversion have been posted.")
112 
113     return counters
114 
115 
116 def create_discussion_description(
117     dataset: str, hf_endpoint: str, parquet_revision: str, bot_associated_user_name: str
118 ) -> str:
119     link_parquet = create_link(
120         text=parquet_revision,
121         dataset=dataset,
122         hf_endpoint=hf_endpoint,
123         revision_type="tree",
124         revision=parquet_revision,
125     )
126     return (
127         f"The {bot_associated_user_name} bot has created a version of this dataset in the [Parquet"
128         " format](https://parquet.apache.org/). You can learn more about the advantages associated with this format"
129         f""" in the [documentation](https://huggingface.co/docs/datasets-server/parquet).
130 
131 The Parquet files are published in the {link_parquet} branch."""
132     )
133 
134 
135 def create_link(
136     text: str, dataset: str, hf_endpoint: str, revision_type: Literal["commit", "tree"], revision: str
137 ) -> str:
138     return f"[`{text}`]({hf_endpoint}/datasets/{dataset}/{revision_type}/{parse.quote(revision, safe='')})"
139 
140 
141 def limit_to_one_dataset_per_namespace(datasets: list[str]) -> list[str]:
142     """
143     Limit the number of datasets to one per namespace.
144 
145     For instance, if we have `a/b` and `a/c`, we will only keep one of them.
146     The choice is arbitrary. The filtered list has no particular order.
147 
148     Args:
149         datasets (`list[str]`): The list of datasets to filter.
150 
151     Returns:
152         `list[str]`: The filtered list of datasets.
153     """
154     namespaces: set[str] = set()
155     selected_datasets: list[str] = []
156     for dataset in datasets:
157         namespace = get_namespace(dataset)
158         if (namespace is None) or (namespace in namespaces):
159             continue
160         namespaces.add(namespace)
161         selected_datasets.append(dataset)
162     return selected_datasets
163 
164 
165 def get_namespace(dataset: str) -> Optional[str]:
166     splits = dataset.split("/")
167     return splits[0] if len(splits) == 2 else None
168
```
--- 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()

```

diff --git a/jobs/cache_maintenance/src/cache_maintenance/discussions.py b/jobs/cache_maintenance/src/cache_maintenance/discussions.py
--- a/jobs/cache_maintenance/src/cache_maintenance/discussions.py
+++ b/jobs/cache_maintenance/src/cache_maintenance/discussions.py
@@ -13,6 +13,35 @@
 PARQUET_CACHE_KIND = "config-parquet"
 DAYS = 1
 
+DISCUSSION_TITLE = "[bot] [No action needed] Conversion to Parquet"
+DISCUSSION_DESCRIPTION = """The {bot_name} bot has created a version of this dataset in the Parquet format in the {parquet_link} branch.
+
+## What is Parquet?
+
+Apache Parquet is a popular columnar storage format known for:
+
+- reduced memory requirement,
+- fast data retrieval and filtering,
+- efficient storage.
+
+It powers the Dataset Viewer (random access, search, filter) and every dataset on the Hub can be accessed with the same code (use HF Datasets, ClickHouse, DuckDB, Pandas or Polars, [you tell](https://huggingface.co/docs/datasets-server/parquet_process)). 
+
+You can learn more about the advantages associated with Parquet in the [documentation](https://huggingface.co/docs/datasets-server/parquet).
+
+## How to access the Parquet version of the dataset?
+
+You can access the Parquet version of the dataset by following this link: {parquet_link}
+
+## What if my dataset was already in Parquet?
+
+When the dataset is already in Parquet format, the data are not converted and the files in `refs/convert/parquet` are links to the original files. This rule suffers an exception to ensure the Datasets Server API to stay fast: if the row group size of the original Parquet files is too big, new Parquet files are generated.
+
+## What should I do?
+
+You don't need to do anything. The Parquet version of the dataset is available for you to use. Refer to the [documentation](https://huggingface.co/docs/datasets-server/parquet_process) for examples and code snippets on how to query the Parquet files with ClickHouse, DuckDB, Pandas or Polars.
+
+If you have any questions or concerns, feel free to ask in the discussion below. You can also close the discussion if you don't have any questions."""
+
 
 @dataclass
 class ParquetCounters:
@@ -116,20 +145,14 @@
 def create_discussion_description(
     dataset: str, hf_endpoint: str, parquet_revision: str, bot_associated_user_name: str
 ) -> str:
-    link_parquet = create_link(
+    parquet_link = create_link(
         text=parquet_revision,
         dataset=dataset,
         hf_endpoint=hf_endpoint,
         revision_type="tree",
         revision=parquet_revision,
     )
-    return (
-        f"The {bot_associated_user_name} bot has created a version of this dataset in the [Parquet"
-        " format](https://parquet.apache.org/). You can learn more about the advantages associated with this format"
-        f""" in the [documentation](https://huggingface.co/docs/datasets-server/parquet).
-
-The Parquet files are published in the {link_parquet} branch."""
-    )
+    return DISCUSSION_DESCRIPTION.format(bot_name=bot_associated_user_name, parquet_link=parquet_link)
 
 
 def create_link(

{"golden_diff": "diff --git a/jobs/cache_maintenance/src/cache_maintenance/discussions.py b/jobs/cache_maintenance/src/cache_maintenance/discussions.py\n--- a/jobs/cache_maintenance/src/cache_maintenance/discussions.py\n+++ b/jobs/cache_maintenance/src/cache_maintenance/discussions.py\n@@ -13,6 +13,35 @@\n PARQUET_CACHE_KIND = \"config-parquet\"\n DAYS = 1\n \n+DISCUSSION_TITLE = \"[bot] [No action needed] Conversion to Parquet\"\n+DISCUSSION_DESCRIPTION = \"\"\"The {bot_name} bot has created a version of this dataset in the Parquet format in the {parquet_link} branch.\n+\n+## What is Parquet?\n+\n+Apache Parquet is a popular columnar storage format known for:\n+\n+- reduced memory requirement,\n+- fast data retrieval and filtering,\n+- efficient storage.\n+\n+It powers the Dataset Viewer (random access, search, filter) and every dataset on the Hub can be accessed with the same code (use HF Datasets, ClickHouse, DuckDB, Pandas or Polars, [you tell](https://huggingface.co/docs/datasets-server/parquet_process)). \n+\n+You can learn more about the advantages associated with Parquet in the [documentation](https://huggingface.co/docs/datasets-server/parquet).\n+\n+## How to access the Parquet version of the dataset?\n+\n+You can access the Parquet version of the dataset by following this link: {parquet_link}\n+\n+## What if my dataset was already in Parquet?\n+\n+When the dataset is already in Parquet format, the data are not converted and the files in `refs/convert/parquet` are links to the original files. This rule suffers an exception to ensure the Datasets Server API to stay fast: if the row group size of the original Parquet files is too big, new Parquet files are generated.\n+\n+## What should I do?\n+\n+You don't need to do anything. The Parquet version of the dataset is available for you to use. Refer to the [documentation](https://huggingface.co/docs/datasets-server/parquet_process) for examples and code snippets on how to query the Parquet files with ClickHouse, DuckDB, Pandas or Polars.\n+\n+If you have any questions or concerns, feel free to ask in the discussion below. You can also close the discussion if you don't have any questions.\"\"\"\n+\n \n @dataclass\n class ParquetCounters:\n@@ -116,20 +145,14 @@\n def create_discussion_description(\n     dataset: str, hf_endpoint: str, parquet_revision: str, bot_associated_user_name: str\n ) -> str:\n-    link_parquet = create_link(\n+    parquet_link = create_link(\n         text=parquet_revision,\n         dataset=dataset,\n         hf_endpoint=hf_endpoint,\n         revision_type=\"tree\",\n         revision=parquet_revision,\n     )\n-    return (\n-        f\"The {bot_associated_user_name} bot has created a version of this dataset in the [Parquet\"\n-        \" format](https://parquet.apache.org/). You can learn more about the advantages associated with this format\"\n-        f\"\"\" in the [documentation](https://huggingface.co/docs/datasets-server/parquet).\n-\n-The Parquet files are published in the {link_parquet} branch.\"\"\"\n-    )\n+    return DISCUSSION_DESCRIPTION.format(bot_name=bot_associated_user_name, parquet_link=parquet_link)\n \n \n def create_link(\n", "issue": "Improve the message in Parquet conversion discussions\nsee https://huggingface.slack.com/archives/C02V51Q3800/p1707388935912969 (internal)\r\n\r\n> Would it make sense to add some message in Parquet PRs (e.g. https://huggingface.co/datasets/huggan/smithsonian_butterflies_subset/discussions/2#65c41c1580497543ca3f8a5a) for less technical people?\r\n> As an aside, I don't think the docs really mention the advantages of Parquet even if we link there for advantages (https://huggingface.co/docs/datasets-server/parquet)\r\n> For example\r\n> ```\r\n> [bot] [No action needed] Conversion to Parquet\r\n> \r\n> The parquet-converter bot has created a version of this dataset in the Parquet format in the `refs/convert/parquet` branch. This will allow X, Y, Z.\r\n> \r\n> You can learn more about the advantages associated with this format in the documentation.\r\n> ```\r\n\r\nrelated to https://github.com/huggingface/datasets-server/issues/2349#issuecomment-1916292176\r\n\n", "before_files": [{"content": "# SPDX-License-Identifier: Apache-2.0\n# Copyright 2023 The HuggingFace Authors.\n\nimport logging\nfrom dataclasses import dataclass\nfrom typing import Literal, Optional\nfrom urllib import parse\n\nfrom huggingface_hub import HfApi\nfrom huggingface_hub.constants import REPO_TYPE_DATASET\nfrom libcommon.simple_cache import get_datasets_with_last_updated_kind\n\nPARQUET_CACHE_KIND = \"config-parquet\"\nDAYS = 1\n\n\n@dataclass\nclass ParquetCounters:\n    datasets: int = 0\n    new_discussions: int = 0\n    dismissed_discussions: int = 0\n    errors: int = 0\n\n\n@dataclass\nclass Counters:\n    parquet: ParquetCounters\n\n\ndef post_messages(\n    hf_endpoint: str, bot_associated_user_name: Optional[str], bot_token: Optional[str], parquet_revision: str\n) -> Counters:\n    \"\"\"\n    Post messages in Hub discussions to notify users.\n    \"\"\"\n    if not (bot_associated_user_name and bot_token):\n        raise Exception(\"No bot token or user name provided, skipping posting messages.\")\n\n    return Counters(\n        parquet=post_messages_on_parquet_conversion(\n            hf_endpoint=hf_endpoint,\n            bot_associated_user_name=bot_associated_user_name,\n            bot_token=bot_token,\n            parquet_revision=parquet_revision,\n        )\n    )\n\n\ndef post_messages_on_parquet_conversion(\n    hf_endpoint: str,\n    bot_associated_user_name: str,\n    bot_token: str,\n    parquet_revision: str,\n) -> ParquetCounters:\n    logging.info(\"Create a Hub discussion to notify about parquet conversion\")\n    datasets = limit_to_one_dataset_per_namespace(\n        get_datasets_with_last_updated_kind(kind=PARQUET_CACHE_KIND, days=DAYS)\n    )\n\n    logging.info(f\"Creating discussions for {len(datasets)} datasets\")\n    log_batch = 100\n    counters = ParquetCounters()\n\n    def get_log() -> str:\n        return (\n            f\" [{counters.datasets}/{len(datasets)}] {counters.new_discussions} discussions\"\n            f\" have been opened, {counters.dismissed_discussions} datasets\"\n            f\" already had a discussion (open or closed). {counters.errors} errors.\"\n        )\n\n    hf_api = HfApi(endpoint=hf_endpoint, token=bot_token)\n\n    for dataset in datasets:\n        counters.datasets += 1\n        prefix = f\"[{counters.datasets}/{len(datasets)}]\"\n        logging.info(f\"{prefix} Processing dataset {dataset}\")\n        try:\n            try:\n                next(\n                    hf_api.get_repo_discussions(\n                        repo_id=dataset, repo_type=REPO_TYPE_DATASET, token=bot_token, author=bot_associated_user_name\n                    )\n                )\n                # if we get here, the bot has already opened a discussion for this dataset\n                counters.dismissed_discussions += 1\n                logging.info(f\"{prefix} [dismissed] Dataset {dataset} already has a discussion, skipping\")\n            except StopIteration:\n                hf_api.create_discussion(\n                    repo_id=dataset,\n                    repo_type=REPO_TYPE_DATASET,\n                    title=\"[bot] Conversion to Parquet\",\n                    description=create_discussion_description(\n                        dataset=dataset,\n                        hf_endpoint=hf_endpoint,\n                        parquet_revision=parquet_revision,\n                        bot_associated_user_name=bot_associated_user_name,\n                    ),\n                    token=bot_token,\n                )\n                counters.new_discussions += 1\n                logging.info(f\"{prefix} [new] Dataset {dataset} has a new discussion\")\n        except Exception as e:\n            counters.errors += 1\n            logging.warning(f\"{prefix} [error] Failed to process dataset {dataset}: {e}\")\n\n        logging.debug(get_log())\n        if (counters.datasets) % log_batch == 0:\n            logging.info(get_log())\n\n    logging.info(get_log())\n    logging.info(\"All the messages about parquet conversion have been posted.\")\n\n    return counters\n\n\ndef create_discussion_description(\n    dataset: str, hf_endpoint: str, parquet_revision: str, bot_associated_user_name: str\n) -> str:\n    link_parquet = create_link(\n        text=parquet_revision,\n        dataset=dataset,\n        hf_endpoint=hf_endpoint,\n        revision_type=\"tree\",\n        revision=parquet_revision,\n    )\n    return (\n        f\"The {bot_associated_user_name} bot has created a version of this dataset in the [Parquet\"\n        \" format](https://parquet.apache.org/). You can learn more about the advantages associated with this format\"\n        f\"\"\" in the [documentation](https://huggingface.co/docs/datasets-server/parquet).\n\nThe Parquet files are published in the {link_parquet} branch.\"\"\"\n    )\n\n\ndef create_link(\n    text: str, dataset: str, hf_endpoint: str, revision_type: Literal[\"commit\", \"tree\"], revision: str\n) -> str:\n    return f\"[`{text}`]({hf_endpoint}/datasets/{dataset}/{revision_type}/{parse.quote(revision, safe='')})\"\n\n\ndef limit_to_one_dataset_per_namespace(datasets: list[str]) -> list[str]:\n    \"\"\"\n    Limit the number of datasets to one per namespace.\n\n    For instance, if we have `a/b` and `a/c`, we will only keep one of them.\n    The choice is arbitrary. The filtered list has no particular order.\n\n    Args:\n        datasets (`list[str]`): The list of datasets to filter.\n\n    Returns:\n        `list[str]`: The filtered list of datasets.\n    \"\"\"\n    namespaces: set[str] = set()\n    selected_datasets: list[str] = []\n    for dataset in datasets:\n        namespace = get_namespace(dataset)\n        if (namespace is None) or (namespace in namespaces):\n            continue\n        namespaces.add(namespace)\n        selected_datasets.append(dataset)\n    return selected_datasets\n\n\ndef get_namespace(dataset: str) -> Optional[str]:\n    splits = dataset.split(\"/\")\n    return splits[0] if len(splits) == 2 else None\n", "path": "jobs/cache_maintenance/src/cache_maintenance/discussions.py"}], "after_files": [{"content": "# SPDX-License-Identifier: Apache-2.0\n# Copyright 2023 The HuggingFace Authors.\n\nimport logging\nfrom dataclasses import dataclass\nfrom typing import Literal, Optional\nfrom urllib import parse\n\nfrom huggingface_hub import HfApi\nfrom huggingface_hub.constants import REPO_TYPE_DATASET\nfrom libcommon.simple_cache import get_datasets_with_last_updated_kind\n\nPARQUET_CACHE_KIND = \"config-parquet\"\nDAYS = 1\n\nDISCUSSION_TITLE = \"[bot] [No action needed] Conversion to Parquet\"\nDISCUSSION_DESCRIPTION = \"\"\"The {bot_name} bot has created a version of this dataset in the Parquet format in the {parquet_link} branch.\n\n## What is Parquet?\n\nApache Parquet is a popular columnar storage format known for:\n\n- reduced memory requirement,\n- fast data retrieval and filtering,\n- efficient storage.\n\nIt powers the Dataset Viewer (random access, search, filter) and every dataset on the Hub can be accessed with the same code (use HF Datasets, ClickHouse, DuckDB, Pandas or Polars, [you tell](https://huggingface.co/docs/datasets-server/parquet_process)). \n\nYou can learn more about the advantages associated with Parquet in the [documentation](https://huggingface.co/docs/datasets-server/parquet).\n\n## How to access the Parquet version of the dataset?\n\nYou can access the Parquet version of the dataset by following this link: {parquet_link}\n\n## What if my dataset was already in Parquet?\n\nWhen the dataset is already in Parquet format, the data are not converted and the files in `refs/convert/parquet` are links to the original files. This rule suffers an exception to ensure the Datasets Server API to stay fast: if the row group size of the original Parquet files is too big, new Parquet files are generated.\n\n## What should I do?\n\nYou don't need to do anything. The Parquet version of the dataset is available for you to use. Refer to the [documentation](https://huggingface.co/docs/datasets-server/parquet_process) for examples and code snippets on how to query the Parquet files with ClickHouse, DuckDB, Pandas or Polars.\n\nIf you have any questions or concerns, feel free to ask in the discussion below. You can also close the discussion if you don't have any questions.\"\"\"\n\n\n@dataclass\nclass ParquetCounters:\n    datasets: int = 0\n    new_discussions: int = 0\n    dismissed_discussions: int = 0\n    errors: int = 0\n\n\n@dataclass\nclass Counters:\n    parquet: ParquetCounters\n\n\ndef post_messages(\n    hf_endpoint: str, bot_associated_user_name: Optional[str], bot_token: Optional[str], parquet_revision: str\n) -> Counters:\n    \"\"\"\n    Post messages in Hub discussions to notify users.\n    \"\"\"\n    if not (bot_associated_user_name and bot_token):\n        raise Exception(\"No bot token or user name provided, skipping posting messages.\")\n\n    return Counters(\n        parquet=post_messages_on_parquet_conversion(\n            hf_endpoint=hf_endpoint,\n            bot_associated_user_name=bot_associated_user_name,\n            bot_token=bot_token,\n            parquet_revision=parquet_revision,\n        )\n    )\n\n\ndef post_messages_on_parquet_conversion(\n    hf_endpoint: str,\n    bot_associated_user_name: str,\n    bot_token: str,\n    parquet_revision: str,\n) -> ParquetCounters:\n    logging.info(\"Create a Hub discussion to notify about parquet conversion\")\n    datasets = limit_to_one_dataset_per_namespace(\n        get_datasets_with_last_updated_kind(kind=PARQUET_CACHE_KIND, days=DAYS)\n    )\n\n    logging.info(f\"Creating discussions for {len(datasets)} datasets\")\n    log_batch = 100\n    counters = ParquetCounters()\n\n    def get_log() -> str:\n        return (\n            f\" [{counters.datasets}/{len(datasets)}] {counters.new_discussions} discussions\"\n            f\" have been opened, {counters.dismissed_discussions} datasets\"\n            f\" already had a discussion (open or closed). {counters.errors} errors.\"\n        )\n\n    hf_api = HfApi(endpoint=hf_endpoint, token=bot_token)\n\n    for dataset in datasets:\n        counters.datasets += 1\n        prefix = f\"[{counters.datasets}/{len(datasets)}]\"\n        logging.info(f\"{prefix} Processing dataset {dataset}\")\n        try:\n            try:\n                next(\n                    hf_api.get_repo_discussions(\n                        repo_id=dataset, repo_type=REPO_TYPE_DATASET, token=bot_token, author=bot_associated_user_name\n                    )\n                )\n                # if we get here, the bot has already opened a discussion for this dataset\n                counters.dismissed_discussions += 1\n                logging.info(f\"{prefix} [dismissed] Dataset {dataset} already has a discussion, skipping\")\n            except StopIteration:\n                hf_api.create_discussion(\n                    repo_id=dataset,\n                    repo_type=REPO_TYPE_DATASET,\n                    title=\"[bot] Conversion to Parquet\",\n                    description=create_discussion_description(\n                        dataset=dataset,\n                        hf_endpoint=hf_endpoint,\n                        parquet_revision=parquet_revision,\n                        bot_associated_user_name=bot_associated_user_name,\n                    ),\n                    token=bot_token,\n                )\n                counters.new_discussions += 1\n                logging.info(f\"{prefix} [new] Dataset {dataset} has a new discussion\")\n        except Exception as e:\n            counters.errors += 1\n            logging.warning(f\"{prefix} [error] Failed to process dataset {dataset}: {e}\")\n\n        logging.debug(get_log())\n        if (counters.datasets) % log_batch == 0:\n            logging.info(get_log())\n\n    logging.info(get_log())\n    logging.info(\"All the messages about parquet conversion have been posted.\")\n\n    return counters\n\n\ndef create_discussion_description(\n    dataset: str, hf_endpoint: str, parquet_revision: str, bot_associated_user_name: str\n) -> str:\n    parquet_link = create_link(\n        text=parquet_revision,\n        dataset=dataset,\n        hf_endpoint=hf_endpoint,\n        revision_type=\"tree\",\n        revision=parquet_revision,\n    )\n    return DISCUSSION_DESCRIPTION.format(bot_name=bot_associated_user_name, parquet_link=parquet_link)\n\n\ndef create_link(\n    text: str, dataset: str, hf_endpoint: str, revision_type: Literal[\"commit\", \"tree\"], revision: str\n) -> str:\n    return f\"[`{text}`]({hf_endpoint}/datasets/{dataset}/{revision_type}/{parse.quote(revision, safe='')})\"\n\n\ndef limit_to_one_dataset_per_namespace(datasets: list[str]) -> list[str]:\n    \"\"\"\n    Limit the number of datasets to one per namespace.\n\n    For instance, if we have `a/b` and `a/c`, we will only keep one of them.\n    The choice is arbitrary. The filtered list has no particular order.\n\n    Args:\n        datasets (`list[str]`): The list of datasets to filter.\n\n    Returns:\n        `list[str]`: The filtered list of datasets.\n    \"\"\"\n    namespaces: set[str] = set()\n    selected_datasets: list[str] = []\n    for dataset in datasets:\n        namespace = get_namespace(dataset)\n        if (namespace is None) or (namespace in namespaces):\n            continue\n        namespaces.add(namespace)\n        selected_datasets.append(dataset)\n    return selected_datasets\n\n\ndef get_namespace(dataset: str) -> Optional[str]:\n    splits = dataset.split(\"/\")\n    return splits[0] if len(splits) == 2 else None\n", "path": "jobs/cache_maintenance/src/cache_maintenance/discussions.py"}]}