We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Support for Python 3.12
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Is your feature request related to a problem? Please describe.

Currently unable to use Sanic with Python 3.12

### Describe the solution you'd like

[uvloop 0.18.0 was just released](https://github.com/MagicStack/uvloop/releases/tag/v0.18.0) and supports Python 3.12

It'd be great to get support for Python 3.12 on the next release of Sanic along with the 2022.12 LTS release

### Additional context

_No response_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sanic/__version__.py`
Content:
```
1 __version__ = "23.12.0"
2
```

Path: `sanic/compat.py`
Content:
```
1 import asyncio
2 import os
3 import platform
4 import signal
5 import sys
6 
7 from contextlib import contextmanager
8 from enum import Enum
9 from typing import Awaitable, Union
10 
11 from multidict import CIMultiDict  # type: ignore
12 
13 from sanic.helpers import Default
14 from sanic.log import error_logger
15 
16 
17 if sys.version_info < (3, 8):  # no cov
18     StartMethod = Union[Default, str]
19 else:  # no cov
20     from typing import Literal
21 
22     StartMethod = Union[
23         Default, Literal["fork"], Literal["forkserver"], Literal["spawn"]
24     ]
25 
26 OS_IS_WINDOWS = os.name == "nt"
27 PYPY_IMPLEMENTATION = platform.python_implementation() == "PyPy"
28 UVLOOP_INSTALLED = False
29 
30 try:
31     import uvloop  # type: ignore # noqa
32 
33     UVLOOP_INSTALLED = True
34 except ImportError:
35     pass
36 
37 # Python 3.11 changed the way Enum formatting works for mixed-in types.
38 if sys.version_info < (3, 11, 0):
39 
40     class StrEnum(str, Enum):
41         pass
42 
43 else:
44     from enum import StrEnum  # type: ignore # noqa
45 
46 
47 class UpperStrEnum(StrEnum):
48     """Base class for string enums that are case insensitive."""
49 
50     def _generate_next_value_(name, start, count, last_values):
51         return name.upper()
52 
53     def __eq__(self, value: object) -> bool:
54         value = str(value).upper()
55         return super().__eq__(value)
56 
57     def __hash__(self) -> int:
58         return hash(self.value)
59 
60     def __str__(self) -> str:
61         return self.value
62 
63 
64 @contextmanager
65 def use_context(method: StartMethod):
66     from sanic import Sanic
67 
68     orig = Sanic.start_method
69     Sanic.start_method = method
70     yield
71     Sanic.start_method = orig
72 
73 
74 def enable_windows_color_support():
75     import ctypes
76 
77     kernel = ctypes.windll.kernel32
78     kernel.SetConsoleMode(kernel.GetStdHandle(-11), 7)
79 
80 
81 def pypy_os_module_patch() -> None:
82     """
83     The PyPy os module is missing the 'readlink' function, which causes issues
84     withaiofiles. This workaround replaces the missing 'readlink' function
85     with 'os.path.realpath', which serves the same purpose.
86     """
87     if hasattr(os, "readlink"):
88         error_logger.warning(
89             "PyPy: Skipping patching of the os module as it appears the "
90             "'readlink' function has been added."
91         )
92         return
93 
94     module = sys.modules["os"]
95     module.readlink = os.path.realpath  # type: ignore
96 
97 
98 def pypy_windows_set_console_cp_patch() -> None:
99     """
100     A patch function for PyPy on Windows that sets the console code page to
101     UTF-8 encodingto allow for proper handling of non-ASCII characters. This
102     function uses ctypes to call the Windows API functions SetConsoleCP and
103     SetConsoleOutputCP to set the code page.
104     """
105     from ctypes import windll  # type: ignore
106 
107     code: int = windll.kernel32.GetConsoleOutputCP()
108     if code != 65001:
109         windll.kernel32.SetConsoleCP(65001)
110         windll.kernel32.SetConsoleOutputCP(65001)
111 
112 
113 class Header(CIMultiDict):
114     """Container used for both request and response headers.
115     It is a subclass of  [CIMultiDict](https://multidict.readthedocs.io/en/stable/multidict.html#cimultidictproxy)
116 
117     It allows for multiple values for a single key in keeping with the HTTP
118     spec. Also, all keys are *case in-sensitive*.
119 
120     Please checkout [the MultiDict documentation](https://multidict.readthedocs.io/en/stable/multidict.html#multidict)
121     for more details about how to use the object. In general, it should work
122     very similar to a regular dictionary.
123     """  # noqa: E501
124 
125     def __getattr__(self, key: str) -> str:
126         if key.startswith("_"):
127             return self.__getattribute__(key)
128         key = key.rstrip("_").replace("_", "-")
129         return ",".join(self.getall(key, default=[]))
130 
131     def get_all(self, key: str):
132         """Convenience method mapped to ``getall()``."""
133         return self.getall(key, default=[])
134 
135 
136 use_trio = sys.argv[0].endswith("hypercorn") and "trio" in sys.argv
137 
138 if use_trio:  # pragma: no cover
139     import trio  # type: ignore
140 
141     def stat_async(path) -> Awaitable[os.stat_result]:
142         return trio.Path(path).stat()
143 
144     open_async = trio.open_file
145     CancelledErrors = tuple([asyncio.CancelledError, trio.Cancelled])
146 else:
147     if PYPY_IMPLEMENTATION:
148         pypy_os_module_patch()
149 
150         if OS_IS_WINDOWS:
151             pypy_windows_set_console_cp_patch()
152 
153     from aiofiles import open as aio_open  # type: ignore
154     from aiofiles.os import stat as stat_async  # type: ignore  # noqa: F401
155 
156     async def open_async(file, mode="r", **kwargs):
157         return aio_open(file, mode, **kwargs)
158 
159     CancelledErrors = tuple([asyncio.CancelledError])
160 
161 
162 def ctrlc_workaround_for_windows(app):
163     async def stay_active(app):
164         """Asyncio wakeups to allow receiving SIGINT in Python"""
165         while not die:
166             # If someone else stopped the app, just exit
167             if app.state.is_stopping:
168                 return
169             # Windows Python blocks signal handlers while the event loop is
170             # waiting for I/O. Frequent wakeups keep interrupts flowing.
171             await asyncio.sleep(0.1)
172         # Can't be called from signal handler, so call it from here
173         app.stop()
174 
175     def ctrlc_handler(sig, frame):
176         nonlocal die
177         if die:
178             raise KeyboardInterrupt("Non-graceful Ctrl+C")
179         die = True
180 
181     die = False
182     signal.signal(signal.SIGINT, ctrlc_handler)
183     app.add_task(stay_active)
184
```
--- 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/sanic/__version__.py b/sanic/__version__.py
--- a/sanic/__version__.py
+++ b/sanic/__version__.py
@@ -1 +1 @@
-__version__ = "23.12.0"
+__version__ = "23.12.1"
diff --git a/sanic/compat.py b/sanic/compat.py
--- a/sanic/compat.py
+++ b/sanic/compat.py
@@ -126,11 +126,11 @@
         if key.startswith("_"):
             return self.__getattribute__(key)
         key = key.rstrip("_").replace("_", "-")
-        return ",".join(self.getall(key, default=[]))
+        return ",".join(self.getall(key, []))
 
     def get_all(self, key: str):
         """Convenience method mapped to ``getall()``."""
-        return self.getall(key, default=[])
+        return self.getall(key, [])
 
 
 use_trio = sys.argv[0].endswith("hypercorn") and "trio" in sys.argv

{"golden_diff": "diff --git a/sanic/__version__.py b/sanic/__version__.py\n--- a/sanic/__version__.py\n+++ b/sanic/__version__.py\n@@ -1 +1 @@\n-__version__ = \"23.12.0\"\n+__version__ = \"23.12.1\"\ndiff --git a/sanic/compat.py b/sanic/compat.py\n--- a/sanic/compat.py\n+++ b/sanic/compat.py\n@@ -126,11 +126,11 @@\n         if key.startswith(\"_\"):\n             return self.__getattribute__(key)\n         key = key.rstrip(\"_\").replace(\"_\", \"-\")\n-        return \",\".join(self.getall(key, default=[]))\n+        return \",\".join(self.getall(key, []))\n \n     def get_all(self, key: str):\n         \"\"\"Convenience method mapped to ``getall()``.\"\"\"\n-        return self.getall(key, default=[])\n+        return self.getall(key, [])\n \n \n use_trio = sys.argv[0].endswith(\"hypercorn\") and \"trio\" in sys.argv\n", "issue": "Support for Python 3.12\n### Is there an existing issue for this?\n\n- [X] I have searched the existing issues\n\n### Is your feature request related to a problem? Please describe.\n\nCurrently unable to use Sanic with Python 3.12\n\n### Describe the solution you'd like\n\n[uvloop 0.18.0 was just released](https://github.com/MagicStack/uvloop/releases/tag/v0.18.0) and supports Python 3.12\r\n\r\nIt'd be great to get support for Python 3.12 on the next release of Sanic along with the 2022.12 LTS release\n\n### Additional context\n\n_No response_\n", "before_files": [{"content": "__version__ = \"23.12.0\"\n", "path": "sanic/__version__.py"}, {"content": "import asyncio\nimport os\nimport platform\nimport signal\nimport sys\n\nfrom contextlib import contextmanager\nfrom enum import Enum\nfrom typing import Awaitable, Union\n\nfrom multidict import CIMultiDict  # type: ignore\n\nfrom sanic.helpers import Default\nfrom sanic.log import error_logger\n\n\nif sys.version_info < (3, 8):  # no cov\n    StartMethod = Union[Default, str]\nelse:  # no cov\n    from typing import Literal\n\n    StartMethod = Union[\n        Default, Literal[\"fork\"], Literal[\"forkserver\"], Literal[\"spawn\"]\n    ]\n\nOS_IS_WINDOWS = os.name == \"nt\"\nPYPY_IMPLEMENTATION = platform.python_implementation() == \"PyPy\"\nUVLOOP_INSTALLED = False\n\ntry:\n    import uvloop  # type: ignore # noqa\n\n    UVLOOP_INSTALLED = True\nexcept ImportError:\n    pass\n\n# Python 3.11 changed the way Enum formatting works for mixed-in types.\nif sys.version_info < (3, 11, 0):\n\n    class StrEnum(str, Enum):\n        pass\n\nelse:\n    from enum import StrEnum  # type: ignore # noqa\n\n\nclass UpperStrEnum(StrEnum):\n    \"\"\"Base class for string enums that are case insensitive.\"\"\"\n\n    def _generate_next_value_(name, start, count, last_values):\n        return name.upper()\n\n    def __eq__(self, value: object) -> bool:\n        value = str(value).upper()\n        return super().__eq__(value)\n\n    def __hash__(self) -> int:\n        return hash(self.value)\n\n    def __str__(self) -> str:\n        return self.value\n\n\n@contextmanager\ndef use_context(method: StartMethod):\n    from sanic import Sanic\n\n    orig = Sanic.start_method\n    Sanic.start_method = method\n    yield\n    Sanic.start_method = orig\n\n\ndef enable_windows_color_support():\n    import ctypes\n\n    kernel = ctypes.windll.kernel32\n    kernel.SetConsoleMode(kernel.GetStdHandle(-11), 7)\n\n\ndef pypy_os_module_patch() -> None:\n    \"\"\"\n    The PyPy os module is missing the 'readlink' function, which causes issues\n    withaiofiles. This workaround replaces the missing 'readlink' function\n    with 'os.path.realpath', which serves the same purpose.\n    \"\"\"\n    if hasattr(os, \"readlink\"):\n        error_logger.warning(\n            \"PyPy: Skipping patching of the os module as it appears the \"\n            \"'readlink' function has been added.\"\n        )\n        return\n\n    module = sys.modules[\"os\"]\n    module.readlink = os.path.realpath  # type: ignore\n\n\ndef pypy_windows_set_console_cp_patch() -> None:\n    \"\"\"\n    A patch function for PyPy on Windows that sets the console code page to\n    UTF-8 encodingto allow for proper handling of non-ASCII characters. This\n    function uses ctypes to call the Windows API functions SetConsoleCP and\n    SetConsoleOutputCP to set the code page.\n    \"\"\"\n    from ctypes import windll  # type: ignore\n\n    code: int = windll.kernel32.GetConsoleOutputCP()\n    if code != 65001:\n        windll.kernel32.SetConsoleCP(65001)\n        windll.kernel32.SetConsoleOutputCP(65001)\n\n\nclass Header(CIMultiDict):\n    \"\"\"Container used for both request and response headers.\n    It is a subclass of  [CIMultiDict](https://multidict.readthedocs.io/en/stable/multidict.html#cimultidictproxy)\n\n    It allows for multiple values for a single key in keeping with the HTTP\n    spec. Also, all keys are *case in-sensitive*.\n\n    Please checkout [the MultiDict documentation](https://multidict.readthedocs.io/en/stable/multidict.html#multidict)\n    for more details about how to use the object. In general, it should work\n    very similar to a regular dictionary.\n    \"\"\"  # noqa: E501\n\n    def __getattr__(self, key: str) -> str:\n        if key.startswith(\"_\"):\n            return self.__getattribute__(key)\n        key = key.rstrip(\"_\").replace(\"_\", \"-\")\n        return \",\".join(self.getall(key, default=[]))\n\n    def get_all(self, key: str):\n        \"\"\"Convenience method mapped to ``getall()``.\"\"\"\n        return self.getall(key, default=[])\n\n\nuse_trio = sys.argv[0].endswith(\"hypercorn\") and \"trio\" in sys.argv\n\nif use_trio:  # pragma: no cover\n    import trio  # type: ignore\n\n    def stat_async(path) -> Awaitable[os.stat_result]:\n        return trio.Path(path).stat()\n\n    open_async = trio.open_file\n    CancelledErrors = tuple([asyncio.CancelledError, trio.Cancelled])\nelse:\n    if PYPY_IMPLEMENTATION:\n        pypy_os_module_patch()\n\n        if OS_IS_WINDOWS:\n            pypy_windows_set_console_cp_patch()\n\n    from aiofiles import open as aio_open  # type: ignore\n    from aiofiles.os import stat as stat_async  # type: ignore  # noqa: F401\n\n    async def open_async(file, mode=\"r\", **kwargs):\n        return aio_open(file, mode, **kwargs)\n\n    CancelledErrors = tuple([asyncio.CancelledError])\n\n\ndef ctrlc_workaround_for_windows(app):\n    async def stay_active(app):\n        \"\"\"Asyncio wakeups to allow receiving SIGINT in Python\"\"\"\n        while not die:\n            # If someone else stopped the app, just exit\n            if app.state.is_stopping:\n                return\n            # Windows Python blocks signal handlers while the event loop is\n            # waiting for I/O. Frequent wakeups keep interrupts flowing.\n            await asyncio.sleep(0.1)\n        # Can't be called from signal handler, so call it from here\n        app.stop()\n\n    def ctrlc_handler(sig, frame):\n        nonlocal die\n        if die:\n            raise KeyboardInterrupt(\"Non-graceful Ctrl+C\")\n        die = True\n\n    die = False\n    signal.signal(signal.SIGINT, ctrlc_handler)\n    app.add_task(stay_active)\n", "path": "sanic/compat.py"}], "after_files": [{"content": "__version__ = \"23.12.1\"\n", "path": "sanic/__version__.py"}, {"content": "import asyncio\nimport os\nimport platform\nimport signal\nimport sys\n\nfrom contextlib import contextmanager\nfrom enum import Enum\nfrom typing import Awaitable, Union\n\nfrom multidict import CIMultiDict  # type: ignore\n\nfrom sanic.helpers import Default\nfrom sanic.log import error_logger\n\n\nif sys.version_info < (3, 8):  # no cov\n    StartMethod = Union[Default, str]\nelse:  # no cov\n    from typing import Literal\n\n    StartMethod = Union[\n        Default, Literal[\"fork\"], Literal[\"forkserver\"], Literal[\"spawn\"]\n    ]\n\nOS_IS_WINDOWS = os.name == \"nt\"\nPYPY_IMPLEMENTATION = platform.python_implementation() == \"PyPy\"\nUVLOOP_INSTALLED = False\n\ntry:\n    import uvloop  # type: ignore # noqa\n\n    UVLOOP_INSTALLED = True\nexcept ImportError:\n    pass\n\n# Python 3.11 changed the way Enum formatting works for mixed-in types.\nif sys.version_info < (3, 11, 0):\n\n    class StrEnum(str, Enum):\n        pass\n\nelse:\n    from enum import StrEnum  # type: ignore # noqa\n\n\nclass UpperStrEnum(StrEnum):\n    \"\"\"Base class for string enums that are case insensitive.\"\"\"\n\n    def _generate_next_value_(name, start, count, last_values):\n        return name.upper()\n\n    def __eq__(self, value: object) -> bool:\n        value = str(value).upper()\n        return super().__eq__(value)\n\n    def __hash__(self) -> int:\n        return hash(self.value)\n\n    def __str__(self) -> str:\n        return self.value\n\n\n@contextmanager\ndef use_context(method: StartMethod):\n    from sanic import Sanic\n\n    orig = Sanic.start_method\n    Sanic.start_method = method\n    yield\n    Sanic.start_method = orig\n\n\ndef enable_windows_color_support():\n    import ctypes\n\n    kernel = ctypes.windll.kernel32\n    kernel.SetConsoleMode(kernel.GetStdHandle(-11), 7)\n\n\ndef pypy_os_module_patch() -> None:\n    \"\"\"\n    The PyPy os module is missing the 'readlink' function, which causes issues\n    withaiofiles. This workaround replaces the missing 'readlink' function\n    with 'os.path.realpath', which serves the same purpose.\n    \"\"\"\n    if hasattr(os, \"readlink\"):\n        error_logger.warning(\n            \"PyPy: Skipping patching of the os module as it appears the \"\n            \"'readlink' function has been added.\"\n        )\n        return\n\n    module = sys.modules[\"os\"]\n    module.readlink = os.path.realpath  # type: ignore\n\n\ndef pypy_windows_set_console_cp_patch() -> None:\n    \"\"\"\n    A patch function for PyPy on Windows that sets the console code page to\n    UTF-8 encodingto allow for proper handling of non-ASCII characters. This\n    function uses ctypes to call the Windows API functions SetConsoleCP and\n    SetConsoleOutputCP to set the code page.\n    \"\"\"\n    from ctypes import windll  # type: ignore\n\n    code: int = windll.kernel32.GetConsoleOutputCP()\n    if code != 65001:\n        windll.kernel32.SetConsoleCP(65001)\n        windll.kernel32.SetConsoleOutputCP(65001)\n\n\nclass Header(CIMultiDict):\n    \"\"\"Container used for both request and response headers.\n    It is a subclass of  [CIMultiDict](https://multidict.readthedocs.io/en/stable/multidict.html#cimultidictproxy)\n\n    It allows for multiple values for a single key in keeping with the HTTP\n    spec. Also, all keys are *case in-sensitive*.\n\n    Please checkout [the MultiDict documentation](https://multidict.readthedocs.io/en/stable/multidict.html#multidict)\n    for more details about how to use the object. In general, it should work\n    very similar to a regular dictionary.\n    \"\"\"  # noqa: E501\n\n    def __getattr__(self, key: str) -> str:\n        if key.startswith(\"_\"):\n            return self.__getattribute__(key)\n        key = key.rstrip(\"_\").replace(\"_\", \"-\")\n        return \",\".join(self.getall(key, []))\n\n    def get_all(self, key: str):\n        \"\"\"Convenience method mapped to ``getall()``.\"\"\"\n        return self.getall(key, [])\n\n\nuse_trio = sys.argv[0].endswith(\"hypercorn\") and \"trio\" in sys.argv\n\nif use_trio:  # pragma: no cover\n    import trio  # type: ignore\n\n    def stat_async(path) -> Awaitable[os.stat_result]:\n        return trio.Path(path).stat()\n\n    open_async = trio.open_file\n    CancelledErrors = tuple([asyncio.CancelledError, trio.Cancelled])\nelse:\n    if PYPY_IMPLEMENTATION:\n        pypy_os_module_patch()\n\n        if OS_IS_WINDOWS:\n            pypy_windows_set_console_cp_patch()\n\n    from aiofiles import open as aio_open  # type: ignore\n    from aiofiles.os import stat as stat_async  # type: ignore  # noqa: F401\n\n    async def open_async(file, mode=\"r\", **kwargs):\n        return aio_open(file, mode, **kwargs)\n\n    CancelledErrors = tuple([asyncio.CancelledError])\n\n\ndef ctrlc_workaround_for_windows(app):\n    async def stay_active(app):\n        \"\"\"Asyncio wakeups to allow receiving SIGINT in Python\"\"\"\n        while not die:\n            # If someone else stopped the app, just exit\n            if app.state.is_stopping:\n                return\n            # Windows Python blocks signal handlers while the event loop is\n            # waiting for I/O. Frequent wakeups keep interrupts flowing.\n            await asyncio.sleep(0.1)\n        # Can't be called from signal handler, so call it from here\n        app.stop()\n\n    def ctrlc_handler(sig, frame):\n        nonlocal die\n        if die:\n            raise KeyboardInterrupt(\"Non-graceful Ctrl+C\")\n        die = True\n\n    die = False\n    signal.signal(signal.SIGINT, ctrlc_handler)\n    app.add_task(stay_active)\n", "path": "sanic/compat.py"}]}