We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[V3 Config] Config does not reject bad keys
Including a `.` or starting a keyname with `$` needs to be invalid in config because of mongoDB backend support. 

Config will work just fine for this on the json backend, but not with the mongodb one because these characters are not allowed in field names for mongo. Instead, it works with json, and throws uncaught exceptions on mongo.

I'd be in favor of limiting keynames to alpha-numeric and space, underscore, and hyphens. to prevent future issues like this with other future possible backends without possibly breaking cogs twice for this.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `redbot/core/drivers/red_mongo.py`
Content:
```
1 import motor.motor_asyncio
2 from .red_base import BaseDriver
3 from urllib.parse import quote_plus
4 
5 __all__ = ["Mongo"]
6 
7 
8 _conn = None
9 
10 
11 def _initialize(**kwargs):
12     uri = kwargs.get("URI", "mongodb")
13     host = kwargs["HOST"]
14     port = kwargs["PORT"]
15     admin_user = kwargs["USERNAME"]
16     admin_pass = kwargs["PASSWORD"]
17     db_name = kwargs.get("DB_NAME", "default_db")
18 
19     if port is 0:
20         ports = ""
21     else:
22         ports = ":{}".format(port)
23 
24     if admin_user is not None and admin_pass is not None:
25         url = "{}://{}:{}@{}{}/{}".format(
26             uri, quote_plus(admin_user), quote_plus(admin_pass), host, ports, db_name
27         )
28     else:
29         url = "{}://{}{}/{}".format(uri, host, ports, db_name)
30 
31     global _conn
32     _conn = motor.motor_asyncio.AsyncIOMotorClient(url)
33 
34 
35 class Mongo(BaseDriver):
36     """
37     Subclass of :py:class:`.red_base.BaseDriver`.
38     """
39 
40     def __init__(self, cog_name, identifier, **kwargs):
41         super().__init__(cog_name, identifier)
42 
43         if _conn is None:
44             _initialize(**kwargs)
45 
46     @property
47     def db(self) -> motor.core.Database:
48         """
49         Gets the mongo database for this cog's name.
50 
51         .. warning::
52 
53             Right now this will cause a new connection to be made every time the
54             database is accessed. We will want to create a connection pool down the
55             line to limit the number of connections.
56 
57         :return:
58             PyMongo Database object.
59         """
60         return _conn.get_database()
61 
62     def get_collection(self) -> motor.core.Collection:
63         """
64         Gets a specified collection within the PyMongo database for this cog.
65 
66         Unless you are doing custom stuff ``collection_name`` should be one of the class
67         attributes of :py:class:`core.config.Config`.
68 
69         :param str collection_name:
70         :return:
71             PyMongo collection object.
72         """
73         return self.db[self.cog_name]
74 
75     @staticmethod
76     def _parse_identifiers(identifiers):
77         uuid, identifiers = identifiers[0], identifiers[1:]
78         return uuid, identifiers
79 
80     async def get(self, *identifiers: str):
81         mongo_collection = self.get_collection()
82 
83         dot_identifiers = ".".join(identifiers)
84 
85         partial = await mongo_collection.find_one(
86             filter={"_id": self.unique_cog_identifier}, projection={dot_identifiers: True}
87         )
88 
89         if partial is None:
90             raise KeyError("No matching document was found and Config expects a KeyError.")
91 
92         for i in identifiers:
93             partial = partial[i]
94         return partial
95 
96     async def set(self, *identifiers: str, value=None):
97         dot_identifiers = ".".join(identifiers)
98 
99         mongo_collection = self.get_collection()
100 
101         await mongo_collection.update_one(
102             {"_id": self.unique_cog_identifier},
103             update={"$set": {dot_identifiers: value}},
104             upsert=True,
105         )
106 
107     async def clear(self, *identifiers: str):
108         dot_identifiers = ".".join(identifiers)
109         mongo_collection = self.get_collection()
110 
111         if len(identifiers) > 0:
112             await mongo_collection.update_one(
113                 {"_id": self.unique_cog_identifier}, update={"$unset": {dot_identifiers: 1}}
114             )
115         else:
116             await mongo_collection.delete_one({"_id": self.unique_cog_identifier})
117 
118 
119 def get_config_details():
120     uri = None
121     while True:
122         uri = input("Enter URI scheme (mongodb or mongodb+srv): ")
123         if uri is "":
124             uri = "mongodb"
125 
126         if uri in ["mongodb", "mongodb+srv"]:
127             break
128         else:
129             print("Invalid URI scheme")
130 
131     host = input("Enter host address: ")
132     if uri is "mongodb":
133         port = int(input("Enter host port: "))
134     else:
135         port = 0
136 
137     admin_uname = input("Enter login username: ")
138     admin_password = input("Enter login password: ")
139 
140     db_name = input("Enter mongodb database name: ")
141 
142     if admin_uname == "":
143         admin_uname = admin_password = None
144 
145     ret = {
146         "HOST": host,
147         "PORT": port,
148         "USERNAME": admin_uname,
149         "PASSWORD": admin_password,
150         "DB_NAME": db_name,
151         "URI": uri,
152     }
153     return ret
154
```
--- 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/redbot/core/drivers/red_mongo.py b/redbot/core/drivers/red_mongo.py
--- a/redbot/core/drivers/red_mongo.py
+++ b/redbot/core/drivers/red_mongo.py
@@ -1,6 +1,11 @@
+import re
+from typing import Match, Pattern
+from urllib.parse import quote_plus
+
+import motor.core
 import motor.motor_asyncio
+
 from .red_base import BaseDriver
-from urllib.parse import quote_plus
 
 __all__ = ["Mongo"]
 
@@ -80,6 +85,7 @@
     async def get(self, *identifiers: str):
         mongo_collection = self.get_collection()
 
+        identifiers = (*map(self._escape_key, identifiers),)
         dot_identifiers = ".".join(identifiers)
 
         partial = await mongo_collection.find_one(
@@ -91,10 +97,14 @@
 
         for i in identifiers:
             partial = partial[i]
+        if isinstance(partial, dict):
+            return self._unescape_dict_keys(partial)
         return partial
 
     async def set(self, *identifiers: str, value=None):
-        dot_identifiers = ".".join(identifiers)
+        dot_identifiers = ".".join(map(self._escape_key, identifiers))
+        if isinstance(value, dict):
+            value = self._escape_dict_keys(value)
 
         mongo_collection = self.get_collection()
 
@@ -105,7 +115,7 @@
         )
 
     async def clear(self, *identifiers: str):
-        dot_identifiers = ".".join(identifiers)
+        dot_identifiers = ".".join(map(self._escape_key, identifiers))
         mongo_collection = self.get_collection()
 
         if len(identifiers) > 0:
@@ -115,6 +125,62 @@
         else:
             await mongo_collection.delete_one({"_id": self.unique_cog_identifier})
 
+    @staticmethod
+    def _escape_key(key: str) -> str:
+        return _SPECIAL_CHAR_PATTERN.sub(_replace_with_escaped, key)
+
+    @staticmethod
+    def _unescape_key(key: str) -> str:
+        return _CHAR_ESCAPE_PATTERN.sub(_replace_with_unescaped, key)
+
+    @classmethod
+    def _escape_dict_keys(cls, data: dict) -> dict:
+        """Recursively escape all keys in a dict."""
+        ret = {}
+        for key, value in data.items():
+            key = cls._escape_key(key)
+            if isinstance(value, dict):
+                value = cls._escape_dict_keys(value)
+            ret[key] = value
+        return ret
+
+    @classmethod
+    def _unescape_dict_keys(cls, data: dict) -> dict:
+        """Recursively unescape all keys in a dict."""
+        ret = {}
+        for key, value in data.items():
+            key = cls._unescape_key(key)
+            if isinstance(value, dict):
+                value = cls._unescape_dict_keys(value)
+            ret[key] = value
+        return ret
+
+
+_SPECIAL_CHAR_PATTERN: Pattern[str] = re.compile(r"([.$]|\\U0000002E|\\U00000024)")
+_SPECIAL_CHARS = {
+    ".": "\\U0000002E",
+    "$": "\\U00000024",
+    "\\U0000002E": "\\U&0000002E",
+    "\\U00000024": "\\U&00000024",
+}
+
+
+def _replace_with_escaped(match: Match[str]) -> str:
+    return _SPECIAL_CHARS[match[0]]
+
+
+_CHAR_ESCAPE_PATTERN: Pattern[str] = re.compile(r"(\\U0000002E|\\U00000024)")
+_CHAR_ESCAPES = {
+    "\\U0000002E": ".",
+    "\\U00000024": "$",
+    "\\U&0000002E": "\\U0000002E",
+    "\\U&00000024": "\\U00000024",
+}
+
+
+def _replace_with_unescaped(match: Match[str]) -> str:
+    return _CHAR_ESCAPES[match[0]]
+
 
 def get_config_details():
     uri = None

{"golden_diff": "diff --git a/redbot/core/drivers/red_mongo.py b/redbot/core/drivers/red_mongo.py\n--- a/redbot/core/drivers/red_mongo.py\n+++ b/redbot/core/drivers/red_mongo.py\n@@ -1,6 +1,11 @@\n+import re\n+from typing import Match, Pattern\n+from urllib.parse import quote_plus\n+\n+import motor.core\n import motor.motor_asyncio\n+\n from .red_base import BaseDriver\n-from urllib.parse import quote_plus\n \n __all__ = [\"Mongo\"]\n \n@@ -80,6 +85,7 @@\n     async def get(self, *identifiers: str):\n         mongo_collection = self.get_collection()\n \n+        identifiers = (*map(self._escape_key, identifiers),)\n         dot_identifiers = \".\".join(identifiers)\n \n         partial = await mongo_collection.find_one(\n@@ -91,10 +97,14 @@\n \n         for i in identifiers:\n             partial = partial[i]\n+        if isinstance(partial, dict):\n+            return self._unescape_dict_keys(partial)\n         return partial\n \n     async def set(self, *identifiers: str, value=None):\n-        dot_identifiers = \".\".join(identifiers)\n+        dot_identifiers = \".\".join(map(self._escape_key, identifiers))\n+        if isinstance(value, dict):\n+            value = self._escape_dict_keys(value)\n \n         mongo_collection = self.get_collection()\n \n@@ -105,7 +115,7 @@\n         )\n \n     async def clear(self, *identifiers: str):\n-        dot_identifiers = \".\".join(identifiers)\n+        dot_identifiers = \".\".join(map(self._escape_key, identifiers))\n         mongo_collection = self.get_collection()\n \n         if len(identifiers) > 0:\n@@ -115,6 +125,62 @@\n         else:\n             await mongo_collection.delete_one({\"_id\": self.unique_cog_identifier})\n \n+    @staticmethod\n+    def _escape_key(key: str) -> str:\n+        return _SPECIAL_CHAR_PATTERN.sub(_replace_with_escaped, key)\n+\n+    @staticmethod\n+    def _unescape_key(key: str) -> str:\n+        return _CHAR_ESCAPE_PATTERN.sub(_replace_with_unescaped, key)\n+\n+    @classmethod\n+    def _escape_dict_keys(cls, data: dict) -> dict:\n+        \"\"\"Recursively escape all keys in a dict.\"\"\"\n+        ret = {}\n+        for key, value in data.items():\n+            key = cls._escape_key(key)\n+            if isinstance(value, dict):\n+                value = cls._escape_dict_keys(value)\n+            ret[key] = value\n+        return ret\n+\n+    @classmethod\n+    def _unescape_dict_keys(cls, data: dict) -> dict:\n+        \"\"\"Recursively unescape all keys in a dict.\"\"\"\n+        ret = {}\n+        for key, value in data.items():\n+            key = cls._unescape_key(key)\n+            if isinstance(value, dict):\n+                value = cls._unescape_dict_keys(value)\n+            ret[key] = value\n+        return ret\n+\n+\n+_SPECIAL_CHAR_PATTERN: Pattern[str] = re.compile(r\"([.$]|\\\\U0000002E|\\\\U00000024)\")\n+_SPECIAL_CHARS = {\n+    \".\": \"\\\\U0000002E\",\n+    \"$\": \"\\\\U00000024\",\n+    \"\\\\U0000002E\": \"\\\\U&0000002E\",\n+    \"\\\\U00000024\": \"\\\\U&00000024\",\n+}\n+\n+\n+def _replace_with_escaped(match: Match[str]) -> str:\n+    return _SPECIAL_CHARS[match[0]]\n+\n+\n+_CHAR_ESCAPE_PATTERN: Pattern[str] = re.compile(r\"(\\\\U0000002E|\\\\U00000024)\")\n+_CHAR_ESCAPES = {\n+    \"\\\\U0000002E\": \".\",\n+    \"\\\\U00000024\": \"$\",\n+    \"\\\\U&0000002E\": \"\\\\U0000002E\",\n+    \"\\\\U&00000024\": \"\\\\U00000024\",\n+}\n+\n+\n+def _replace_with_unescaped(match: Match[str]) -> str:\n+    return _CHAR_ESCAPES[match[0]]\n+\n \n def get_config_details():\n     uri = None\n", "issue": "[V3 Config] Config does not reject bad keys\nIncluding a `.` or starting a keyname with `$` needs to be invalid in config because of mongoDB backend support. \r\n\r\nConfig will work just fine for this on the json backend, but not with the mongodb one because these characters are not allowed in field names for mongo. Instead, it works with json, and throws uncaught exceptions on mongo.\r\n\r\nI'd be in favor of limiting keynames to alpha-numeric and space, underscore, and hyphens. to prevent future issues like this with other future possible backends without possibly breaking cogs twice for this.\n", "before_files": [{"content": "import motor.motor_asyncio\nfrom .red_base import BaseDriver\nfrom urllib.parse import quote_plus\n\n__all__ = [\"Mongo\"]\n\n\n_conn = None\n\n\ndef _initialize(**kwargs):\n    uri = kwargs.get(\"URI\", \"mongodb\")\n    host = kwargs[\"HOST\"]\n    port = kwargs[\"PORT\"]\n    admin_user = kwargs[\"USERNAME\"]\n    admin_pass = kwargs[\"PASSWORD\"]\n    db_name = kwargs.get(\"DB_NAME\", \"default_db\")\n\n    if port is 0:\n        ports = \"\"\n    else:\n        ports = \":{}\".format(port)\n\n    if admin_user is not None and admin_pass is not None:\n        url = \"{}://{}:{}@{}{}/{}\".format(\n            uri, quote_plus(admin_user), quote_plus(admin_pass), host, ports, db_name\n        )\n    else:\n        url = \"{}://{}{}/{}\".format(uri, host, ports, db_name)\n\n    global _conn\n    _conn = motor.motor_asyncio.AsyncIOMotorClient(url)\n\n\nclass Mongo(BaseDriver):\n    \"\"\"\n    Subclass of :py:class:`.red_base.BaseDriver`.\n    \"\"\"\n\n    def __init__(self, cog_name, identifier, **kwargs):\n        super().__init__(cog_name, identifier)\n\n        if _conn is None:\n            _initialize(**kwargs)\n\n    @property\n    def db(self) -> motor.core.Database:\n        \"\"\"\n        Gets the mongo database for this cog's name.\n\n        .. warning::\n\n            Right now this will cause a new connection to be made every time the\n            database is accessed. We will want to create a connection pool down the\n            line to limit the number of connections.\n\n        :return:\n            PyMongo Database object.\n        \"\"\"\n        return _conn.get_database()\n\n    def get_collection(self) -> motor.core.Collection:\n        \"\"\"\n        Gets a specified collection within the PyMongo database for this cog.\n\n        Unless you are doing custom stuff ``collection_name`` should be one of the class\n        attributes of :py:class:`core.config.Config`.\n\n        :param str collection_name:\n        :return:\n            PyMongo collection object.\n        \"\"\"\n        return self.db[self.cog_name]\n\n    @staticmethod\n    def _parse_identifiers(identifiers):\n        uuid, identifiers = identifiers[0], identifiers[1:]\n        return uuid, identifiers\n\n    async def get(self, *identifiers: str):\n        mongo_collection = self.get_collection()\n\n        dot_identifiers = \".\".join(identifiers)\n\n        partial = await mongo_collection.find_one(\n            filter={\"_id\": self.unique_cog_identifier}, projection={dot_identifiers: True}\n        )\n\n        if partial is None:\n            raise KeyError(\"No matching document was found and Config expects a KeyError.\")\n\n        for i in identifiers:\n            partial = partial[i]\n        return partial\n\n    async def set(self, *identifiers: str, value=None):\n        dot_identifiers = \".\".join(identifiers)\n\n        mongo_collection = self.get_collection()\n\n        await mongo_collection.update_one(\n            {\"_id\": self.unique_cog_identifier},\n            update={\"$set\": {dot_identifiers: value}},\n            upsert=True,\n        )\n\n    async def clear(self, *identifiers: str):\n        dot_identifiers = \".\".join(identifiers)\n        mongo_collection = self.get_collection()\n\n        if len(identifiers) > 0:\n            await mongo_collection.update_one(\n                {\"_id\": self.unique_cog_identifier}, update={\"$unset\": {dot_identifiers: 1}}\n            )\n        else:\n            await mongo_collection.delete_one({\"_id\": self.unique_cog_identifier})\n\n\ndef get_config_details():\n    uri = None\n    while True:\n        uri = input(\"Enter URI scheme (mongodb or mongodb+srv): \")\n        if uri is \"\":\n            uri = \"mongodb\"\n\n        if uri in [\"mongodb\", \"mongodb+srv\"]:\n            break\n        else:\n            print(\"Invalid URI scheme\")\n\n    host = input(\"Enter host address: \")\n    if uri is \"mongodb\":\n        port = int(input(\"Enter host port: \"))\n    else:\n        port = 0\n\n    admin_uname = input(\"Enter login username: \")\n    admin_password = input(\"Enter login password: \")\n\n    db_name = input(\"Enter mongodb database name: \")\n\n    if admin_uname == \"\":\n        admin_uname = admin_password = None\n\n    ret = {\n        \"HOST\": host,\n        \"PORT\": port,\n        \"USERNAME\": admin_uname,\n        \"PASSWORD\": admin_password,\n        \"DB_NAME\": db_name,\n        \"URI\": uri,\n    }\n    return ret\n", "path": "redbot/core/drivers/red_mongo.py"}], "after_files": [{"content": "import re\nfrom typing import Match, Pattern\nfrom urllib.parse import quote_plus\n\nimport motor.core\nimport motor.motor_asyncio\n\nfrom .red_base import BaseDriver\n\n__all__ = [\"Mongo\"]\n\n\n_conn = None\n\n\ndef _initialize(**kwargs):\n    uri = kwargs.get(\"URI\", \"mongodb\")\n    host = kwargs[\"HOST\"]\n    port = kwargs[\"PORT\"]\n    admin_user = kwargs[\"USERNAME\"]\n    admin_pass = kwargs[\"PASSWORD\"]\n    db_name = kwargs.get(\"DB_NAME\", \"default_db\")\n\n    if port is 0:\n        ports = \"\"\n    else:\n        ports = \":{}\".format(port)\n\n    if admin_user is not None and admin_pass is not None:\n        url = \"{}://{}:{}@{}{}/{}\".format(\n            uri, quote_plus(admin_user), quote_plus(admin_pass), host, ports, db_name\n        )\n    else:\n        url = \"{}://{}{}/{}\".format(uri, host, ports, db_name)\n\n    global _conn\n    _conn = motor.motor_asyncio.AsyncIOMotorClient(url)\n\n\nclass Mongo(BaseDriver):\n    \"\"\"\n    Subclass of :py:class:`.red_base.BaseDriver`.\n    \"\"\"\n\n    def __init__(self, cog_name, identifier, **kwargs):\n        super().__init__(cog_name, identifier)\n\n        if _conn is None:\n            _initialize(**kwargs)\n\n    @property\n    def db(self) -> motor.core.Database:\n        \"\"\"\n        Gets the mongo database for this cog's name.\n\n        .. warning::\n\n            Right now this will cause a new connection to be made every time the\n            database is accessed. We will want to create a connection pool down the\n            line to limit the number of connections.\n\n        :return:\n            PyMongo Database object.\n        \"\"\"\n        return _conn.get_database()\n\n    def get_collection(self) -> motor.core.Collection:\n        \"\"\"\n        Gets a specified collection within the PyMongo database for this cog.\n\n        Unless you are doing custom stuff ``collection_name`` should be one of the class\n        attributes of :py:class:`core.config.Config`.\n\n        :param str collection_name:\n        :return:\n            PyMongo collection object.\n        \"\"\"\n        return self.db[self.cog_name]\n\n    @staticmethod\n    def _parse_identifiers(identifiers):\n        uuid, identifiers = identifiers[0], identifiers[1:]\n        return uuid, identifiers\n\n    async def get(self, *identifiers: str):\n        mongo_collection = self.get_collection()\n\n        identifiers = (*map(self._escape_key, identifiers),)\n        dot_identifiers = \".\".join(identifiers)\n\n        partial = await mongo_collection.find_one(\n            filter={\"_id\": self.unique_cog_identifier}, projection={dot_identifiers: True}\n        )\n\n        if partial is None:\n            raise KeyError(\"No matching document was found and Config expects a KeyError.\")\n\n        for i in identifiers:\n            partial = partial[i]\n        if isinstance(partial, dict):\n            return self._unescape_dict_keys(partial)\n        return partial\n\n    async def set(self, *identifiers: str, value=None):\n        dot_identifiers = \".\".join(map(self._escape_key, identifiers))\n        if isinstance(value, dict):\n            value = self._escape_dict_keys(value)\n\n        mongo_collection = self.get_collection()\n\n        await mongo_collection.update_one(\n            {\"_id\": self.unique_cog_identifier},\n            update={\"$set\": {dot_identifiers: value}},\n            upsert=True,\n        )\n\n    async def clear(self, *identifiers: str):\n        dot_identifiers = \".\".join(map(self._escape_key, identifiers))\n        mongo_collection = self.get_collection()\n\n        if len(identifiers) > 0:\n            await mongo_collection.update_one(\n                {\"_id\": self.unique_cog_identifier}, update={\"$unset\": {dot_identifiers: 1}}\n            )\n        else:\n            await mongo_collection.delete_one({\"_id\": self.unique_cog_identifier})\n\n    @staticmethod\n    def _escape_key(key: str) -> str:\n        return _SPECIAL_CHAR_PATTERN.sub(_replace_with_escaped, key)\n\n    @staticmethod\n    def _unescape_key(key: str) -> str:\n        return _CHAR_ESCAPE_PATTERN.sub(_replace_with_unescaped, key)\n\n    @classmethod\n    def _escape_dict_keys(cls, data: dict) -> dict:\n        \"\"\"Recursively escape all keys in a dict.\"\"\"\n        ret = {}\n        for key, value in data.items():\n            key = cls._escape_key(key)\n            if isinstance(value, dict):\n                value = cls._escape_dict_keys(value)\n            ret[key] = value\n        return ret\n\n    @classmethod\n    def _unescape_dict_keys(cls, data: dict) -> dict:\n        \"\"\"Recursively unescape all keys in a dict.\"\"\"\n        ret = {}\n        for key, value in data.items():\n            key = cls._unescape_key(key)\n            if isinstance(value, dict):\n                value = cls._unescape_dict_keys(value)\n            ret[key] = value\n        return ret\n\n\n_SPECIAL_CHAR_PATTERN: Pattern[str] = re.compile(r\"([.$]|\\\\U0000002E|\\\\U00000024)\")\n_SPECIAL_CHARS = {\n    \".\": \"\\\\U0000002E\",\n    \"$\": \"\\\\U00000024\",\n    \"\\\\U0000002E\": \"\\\\U&0000002E\",\n    \"\\\\U00000024\": \"\\\\U&00000024\",\n}\n\n\ndef _replace_with_escaped(match: Match[str]) -> str:\n    return _SPECIAL_CHARS[match[0]]\n\n\n_CHAR_ESCAPE_PATTERN: Pattern[str] = re.compile(r\"(\\\\U0000002E|\\\\U00000024)\")\n_CHAR_ESCAPES = {\n    \"\\\\U0000002E\": \".\",\n    \"\\\\U00000024\": \"$\",\n    \"\\\\U&0000002E\": \"\\\\U0000002E\",\n    \"\\\\U&00000024\": \"\\\\U00000024\",\n}\n\n\ndef _replace_with_unescaped(match: Match[str]) -> str:\n    return _CHAR_ESCAPES[match[0]]\n\n\ndef get_config_details():\n    uri = None\n    while True:\n        uri = input(\"Enter URI scheme (mongodb or mongodb+srv): \")\n        if uri is \"\":\n            uri = \"mongodb\"\n\n        if uri in [\"mongodb\", \"mongodb+srv\"]:\n            break\n        else:\n            print(\"Invalid URI scheme\")\n\n    host = input(\"Enter host address: \")\n    if uri is \"mongodb\":\n        port = int(input(\"Enter host port: \"))\n    else:\n        port = 0\n\n    admin_uname = input(\"Enter login username: \")\n    admin_password = input(\"Enter login password: \")\n\n    db_name = input(\"Enter mongodb database name: \")\n\n    if admin_uname == \"\":\n        admin_uname = admin_password = None\n\n    ret = {\n        \"HOST\": host,\n        \"PORT\": port,\n        \"USERNAME\": admin_uname,\n        \"PASSWORD\": admin_password,\n        \"DB_NAME\": db_name,\n        \"URI\": uri,\n    }\n    return ret\n", "path": "redbot/core/drivers/red_mongo.py"}]}