We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Circular import in target file accidentally triggers 'No module named ... found'
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Describe the bug

While developing it appears that I accidentally caused a circular import which Python traces back to starting in the file I have my app in. As a result, Python outputs an error such as the following:
```
ImportError: cannot import name 'constants' from partially initialized module 'app' (most likely due to a circular import) (/api/app/__init__.py)
```
In this case my module I pass to the sanic server is `app:app`, from within `/api`.

### Code snippet

_No response_

### Expected Behavior

I had this in the back of my mind the entire time, but found it very difficult to troubleshoot due to Sanic swallowing the error. As a result I ended up the rabbit hole of accidental breaking changes and tried commenting out different changes. An hour later I finally found the right import.

It would help if Sanic continued to output the specific import error, on the off-chance that it isn't an incorrectly setup module. The alternative would be to use more fine-grained `importlib` and manually call some functions rather than use their help functions. As a result there should be a different call which finds the file (an `ImportError` here hints at an incorrectly setup module), than the one which loads it (user error).

### How do you run Sanic?

Sanic CLI

### Operating System

Windows (Docker, Python:3.11)

### Sanic Version

23.3

### Additional context

_No response_
Circular import in target file accidentally triggers 'No module named ... found'
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Describe the bug

While developing it appears that I accidentally caused a circular import which Python traces back to starting in the file I have my app in. As a result, Python outputs an error such as the following:
```
ImportError: cannot import name 'constants' from partially initialized module 'app' (most likely due to a circular import) (/api/app/__init__.py)
```
In this case my module I pass to the sanic server is `app:app`, from within `/api`.

### Code snippet

_No response_

### Expected Behavior

I had this in the back of my mind the entire time, but found it very difficult to troubleshoot due to Sanic swallowing the error. As a result I ended up the rabbit hole of accidental breaking changes and tried commenting out different changes. An hour later I finally found the right import.

It would help if Sanic continued to output the specific import error, on the off-chance that it isn't an incorrectly setup module. The alternative would be to use more fine-grained `importlib` and manually call some functions rather than use their help functions. As a result there should be a different call which finds the file (an `ImportError` here hints at an incorrectly setup module), than the one which loads it (user error).

### How do you run Sanic?

Sanic CLI

### Operating System

Windows (Docker, Python:3.11)

### Sanic Version

23.3

### 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/cli/app.py`
Content:
```
1 import os
2 import shutil
3 import sys
4 
5 from argparse import Namespace
6 from functools import partial
7 from textwrap import indent
8 from typing import List, Union
9 
10 from sanic.app import Sanic
11 from sanic.application.logo import get_logo
12 from sanic.cli.arguments import Group
13 from sanic.cli.base import SanicArgumentParser, SanicHelpFormatter
14 from sanic.cli.inspector import make_inspector_parser
15 from sanic.cli.inspector_client import InspectorClient
16 from sanic.log import error_logger
17 from sanic.worker.loader import AppLoader
18 
19 
20 class SanicCLI:
21     DESCRIPTION = indent(
22         f"""
23 {get_logo(True)}
24 
25 To start running a Sanic application, provide a path to the module, where
26 app is a Sanic() instance in the global scope:
27 
28     $ sanic path.to.server:app
29 
30 If the Sanic instance variable is called 'app', you can leave off the last
31 part, and only provide a path to the module where the instance is:
32 
33     $ sanic path.to.server
34 
35 Or, a path to a callable that returns a Sanic() instance:
36 
37     $ sanic path.to.factory:create_app
38 
39 Or, a path to a directory to run as a simple HTTP server:
40 
41     $ sanic ./path/to/static
42 """,
43         prefix=" ",
44     )
45 
46     def __init__(self) -> None:
47         width = shutil.get_terminal_size().columns
48         self.parser = SanicArgumentParser(
49             prog="sanic",
50             description=self.DESCRIPTION,
51             formatter_class=lambda prog: SanicHelpFormatter(
52                 prog,
53                 max_help_position=36 if width > 96 else 24,
54                 indent_increment=4,
55                 width=None,
56             ),
57         )
58         self.parser._positionals.title = "Required\n========\n  Positional"
59         self.parser._optionals.title = "Optional\n========\n  General"
60         self.main_process = (
61             os.environ.get("SANIC_RELOADER_PROCESS", "") != "true"
62         )
63         self.args: Namespace = Namespace()
64         self.groups: List[Group] = []
65         self.inspecting = False
66 
67     def attach(self):
68         if len(sys.argv) > 1 and sys.argv[1] == "inspect":
69             self.inspecting = True
70             self.parser.description = get_logo(True)
71             make_inspector_parser(self.parser)
72             return
73 
74         for group in Group._registry:
75             instance = group.create(self.parser)
76             instance.attach()
77             self.groups.append(instance)
78 
79     def run(self, parse_args=None):
80         if self.inspecting:
81             self._inspector()
82             return
83 
84         legacy_version = False
85         if not parse_args:
86             # This is to provide backwards compat -v to display version
87             legacy_version = len(sys.argv) == 2 and sys.argv[-1] == "-v"
88             parse_args = ["--version"] if legacy_version else None
89         elif parse_args == ["-v"]:
90             parse_args = ["--version"]
91 
92         if not legacy_version:
93             parsed, unknown = self.parser.parse_known_args(args=parse_args)
94             if unknown and parsed.factory:
95                 for arg in unknown:
96                     if arg.startswith("--"):
97                         self.parser.add_argument(arg.split("=")[0])
98 
99         self.args = self.parser.parse_args(args=parse_args)
100         self._precheck()
101         app_loader = AppLoader(
102             self.args.target, self.args.factory, self.args.simple, self.args
103         )
104 
105         try:
106             app = self._get_app(app_loader)
107             kwargs = self._build_run_kwargs()
108         except ValueError as e:
109             error_logger.exception(f"Failed to run app: {e}")
110         else:
111             for http_version in self.args.http:
112                 app.prepare(**kwargs, version=http_version)
113             if self.args.single:
114                 serve = Sanic.serve_single
115             else:
116                 serve = partial(Sanic.serve, app_loader=app_loader)
117             serve(app)
118 
119     def _inspector(self):
120         args = sys.argv[2:]
121         self.args, unknown = self.parser.parse_known_args(args=args)
122         if unknown:
123             for arg in unknown:
124                 if arg.startswith("--"):
125                     try:
126                         key, value = arg.split("=")
127                         key = key.lstrip("-")
128                     except ValueError:
129                         value = False if arg.startswith("--no-") else True
130                         key = (
131                             arg.replace("--no-", "")
132                             .lstrip("-")
133                             .replace("-", "_")
134                         )
135                     setattr(self.args, key, value)
136 
137         kwargs = {**self.args.__dict__}
138         host = kwargs.pop("host")
139         port = kwargs.pop("port")
140         secure = kwargs.pop("secure")
141         raw = kwargs.pop("raw")
142         action = kwargs.pop("action") or "info"
143         api_key = kwargs.pop("api_key")
144         positional = kwargs.pop("positional", None)
145         if action == "<custom>" and positional:
146             action = positional[0]
147             if len(positional) > 1:
148                 kwargs["args"] = positional[1:]
149         InspectorClient(host, port, secure, raw, api_key).do(action, **kwargs)
150 
151     def _precheck(self):
152         # Custom TLS mismatch handling for better diagnostics
153         if self.main_process and (
154             # one of cert/key missing
155             bool(self.args.cert) != bool(self.args.key)
156             # new and old style self.args used together
157             or self.args.tls
158             and self.args.cert
159             # strict host checking without certs would always fail
160             or self.args.tlshost
161             and not self.args.tls
162             and not self.args.cert
163         ):
164             self.parser.print_usage(sys.stderr)
165             message = (
166                 "TLS certificates must be specified by either of:\n"
167                 "  --cert certdir/fullchain.pem --key certdir/privkey.pem\n"
168                 "  --tls certdir  (equivalent to the above)"
169             )
170             error_logger.error(message)
171             sys.exit(1)
172 
173     def _get_app(self, app_loader: AppLoader):
174         try:
175             app = app_loader.load()
176         except ImportError as e:
177             if app_loader.module_name.startswith(e.name):  # type: ignore
178                 error_logger.error(
179                     f"No module named {e.name} found.\n"
180                     "  Example File: project/sanic_server.py -> app\n"
181                     "  Example Module: project.sanic_server.app"
182                 )
183                 sys.exit(1)
184             else:
185                 raise e
186         return app
187 
188     def _build_run_kwargs(self):
189         for group in self.groups:
190             group.prepare(self.args)
191         ssl: Union[None, dict, str, list] = []
192         if self.args.tlshost:
193             ssl.append(None)
194         if self.args.cert is not None or self.args.key is not None:
195             ssl.append(dict(cert=self.args.cert, key=self.args.key))
196         if self.args.tls:
197             ssl += self.args.tls
198         if not ssl:
199             ssl = None
200         elif len(ssl) == 1 and ssl[0] is not None:
201             # Use only one cert, no TLSSelector.
202             ssl = ssl[0]
203 
204         kwargs = {
205             "access_log": self.args.access_log,
206             "coffee": self.args.coffee,
207             "debug": self.args.debug,
208             "fast": self.args.fast,
209             "host": self.args.host,
210             "motd": self.args.motd,
211             "noisy_exceptions": self.args.noisy_exceptions,
212             "port": self.args.port,
213             "ssl": ssl,
214             "unix": self.args.unix,
215             "verbosity": self.args.verbosity or 0,
216             "workers": self.args.workers,
217             "auto_tls": self.args.auto_tls,
218             "single_process": self.args.single,
219         }
220 
221         for maybe_arg in ("auto_reload", "dev"):
222             if getattr(self.args, maybe_arg, False):
223                 kwargs[maybe_arg] = True
224 
225         if self.args.path:
226             kwargs["auto_reload"] = True
227             kwargs["reload_dir"] = self.args.path
228 
229         return kwargs
230
```
--- 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/cli/app.py b/sanic/cli/app.py
--- a/sanic/cli/app.py
+++ b/sanic/cli/app.py
@@ -180,6 +180,10 @@
                     "  Example File: project/sanic_server.py -> app\n"
                     "  Example Module: project.sanic_server.app"
                 )
+                error_logger.error(
+                    "\nThe error below might have caused the above one:\n"
+                    f"{e.msg}"
+                )
                 sys.exit(1)
             else:
                 raise e

{"golden_diff": "diff --git a/sanic/cli/app.py b/sanic/cli/app.py\n--- a/sanic/cli/app.py\n+++ b/sanic/cli/app.py\n@@ -180,6 +180,10 @@\n                     \"  Example File: project/sanic_server.py -> app\\n\"\n                     \"  Example Module: project.sanic_server.app\"\n                 )\n+                error_logger.error(\n+                    \"\\nThe error below might have caused the above one:\\n\"\n+                    f\"{e.msg}\"\n+                )\n                 sys.exit(1)\n             else:\n                 raise e\n", "issue": "Circular import in target file accidentally triggers 'No module named ... found'\n### Is there an existing issue for this?\n\n- [X] I have searched the existing issues\n\n### Describe the bug\n\nWhile developing it appears that I accidentally caused a circular import which Python traces back to starting in the file I have my app in. As a result, Python outputs an error such as the following:\r\n```\r\nImportError: cannot import name 'constants' from partially initialized module 'app' (most likely due to a circular import) (/api/app/__init__.py)\r\n```\r\nIn this case my module I pass to the sanic server is `app:app`, from within `/api`.\n\n### Code snippet\n\n_No response_\n\n### Expected Behavior\n\nI had this in the back of my mind the entire time, but found it very difficult to troubleshoot due to Sanic swallowing the error. As a result I ended up the rabbit hole of accidental breaking changes and tried commenting out different changes. An hour later I finally found the right import.\r\n\r\nIt would help if Sanic continued to output the specific import error, on the off-chance that it isn't an incorrectly setup module. The alternative would be to use more fine-grained `importlib` and manually call some functions rather than use their help functions. As a result there should be a different call which finds the file (an `ImportError` here hints at an incorrectly setup module), than the one which loads it (user error).\n\n### How do you run Sanic?\n\nSanic CLI\n\n### Operating System\n\nWindows (Docker, Python:3.11)\n\n### Sanic Version\n\n23.3\n\n### Additional context\n\n_No response_\nCircular import in target file accidentally triggers 'No module named ... found'\n### Is there an existing issue for this?\n\n- [X] I have searched the existing issues\n\n### Describe the bug\n\nWhile developing it appears that I accidentally caused a circular import which Python traces back to starting in the file I have my app in. As a result, Python outputs an error such as the following:\r\n```\r\nImportError: cannot import name 'constants' from partially initialized module 'app' (most likely due to a circular import) (/api/app/__init__.py)\r\n```\r\nIn this case my module I pass to the sanic server is `app:app`, from within `/api`.\n\n### Code snippet\n\n_No response_\n\n### Expected Behavior\n\nI had this in the back of my mind the entire time, but found it very difficult to troubleshoot due to Sanic swallowing the error. As a result I ended up the rabbit hole of accidental breaking changes and tried commenting out different changes. An hour later I finally found the right import.\r\n\r\nIt would help if Sanic continued to output the specific import error, on the off-chance that it isn't an incorrectly setup module. The alternative would be to use more fine-grained `importlib` and manually call some functions rather than use their help functions. As a result there should be a different call which finds the file (an `ImportError` here hints at an incorrectly setup module), than the one which loads it (user error).\n\n### How do you run Sanic?\n\nSanic CLI\n\n### Operating System\n\nWindows (Docker, Python:3.11)\n\n### Sanic Version\n\n23.3\n\n### Additional context\n\n_No response_\n", "before_files": [{"content": "import os\nimport shutil\nimport sys\n\nfrom argparse import Namespace\nfrom functools import partial\nfrom textwrap import indent\nfrom typing import List, Union\n\nfrom sanic.app import Sanic\nfrom sanic.application.logo import get_logo\nfrom sanic.cli.arguments import Group\nfrom sanic.cli.base import SanicArgumentParser, SanicHelpFormatter\nfrom sanic.cli.inspector import make_inspector_parser\nfrom sanic.cli.inspector_client import InspectorClient\nfrom sanic.log import error_logger\nfrom sanic.worker.loader import AppLoader\n\n\nclass SanicCLI:\n    DESCRIPTION = indent(\n        f\"\"\"\n{get_logo(True)}\n\nTo start running a Sanic application, provide a path to the module, where\napp is a Sanic() instance in the global scope:\n\n    $ sanic path.to.server:app\n\nIf the Sanic instance variable is called 'app', you can leave off the last\npart, and only provide a path to the module where the instance is:\n\n    $ sanic path.to.server\n\nOr, a path to a callable that returns a Sanic() instance:\n\n    $ sanic path.to.factory:create_app\n\nOr, a path to a directory to run as a simple HTTP server:\n\n    $ sanic ./path/to/static\n\"\"\",\n        prefix=\" \",\n    )\n\n    def __init__(self) -> None:\n        width = shutil.get_terminal_size().columns\n        self.parser = SanicArgumentParser(\n            prog=\"sanic\",\n            description=self.DESCRIPTION,\n            formatter_class=lambda prog: SanicHelpFormatter(\n                prog,\n                max_help_position=36 if width > 96 else 24,\n                indent_increment=4,\n                width=None,\n            ),\n        )\n        self.parser._positionals.title = \"Required\\n========\\n  Positional\"\n        self.parser._optionals.title = \"Optional\\n========\\n  General\"\n        self.main_process = (\n            os.environ.get(\"SANIC_RELOADER_PROCESS\", \"\") != \"true\"\n        )\n        self.args: Namespace = Namespace()\n        self.groups: List[Group] = []\n        self.inspecting = False\n\n    def attach(self):\n        if len(sys.argv) > 1 and sys.argv[1] == \"inspect\":\n            self.inspecting = True\n            self.parser.description = get_logo(True)\n            make_inspector_parser(self.parser)\n            return\n\n        for group in Group._registry:\n            instance = group.create(self.parser)\n            instance.attach()\n            self.groups.append(instance)\n\n    def run(self, parse_args=None):\n        if self.inspecting:\n            self._inspector()\n            return\n\n        legacy_version = False\n        if not parse_args:\n            # This is to provide backwards compat -v to display version\n            legacy_version = len(sys.argv) == 2 and sys.argv[-1] == \"-v\"\n            parse_args = [\"--version\"] if legacy_version else None\n        elif parse_args == [\"-v\"]:\n            parse_args = [\"--version\"]\n\n        if not legacy_version:\n            parsed, unknown = self.parser.parse_known_args(args=parse_args)\n            if unknown and parsed.factory:\n                for arg in unknown:\n                    if arg.startswith(\"--\"):\n                        self.parser.add_argument(arg.split(\"=\")[0])\n\n        self.args = self.parser.parse_args(args=parse_args)\n        self._precheck()\n        app_loader = AppLoader(\n            self.args.target, self.args.factory, self.args.simple, self.args\n        )\n\n        try:\n            app = self._get_app(app_loader)\n            kwargs = self._build_run_kwargs()\n        except ValueError as e:\n            error_logger.exception(f\"Failed to run app: {e}\")\n        else:\n            for http_version in self.args.http:\n                app.prepare(**kwargs, version=http_version)\n            if self.args.single:\n                serve = Sanic.serve_single\n            else:\n                serve = partial(Sanic.serve, app_loader=app_loader)\n            serve(app)\n\n    def _inspector(self):\n        args = sys.argv[2:]\n        self.args, unknown = self.parser.parse_known_args(args=args)\n        if unknown:\n            for arg in unknown:\n                if arg.startswith(\"--\"):\n                    try:\n                        key, value = arg.split(\"=\")\n                        key = key.lstrip(\"-\")\n                    except ValueError:\n                        value = False if arg.startswith(\"--no-\") else True\n                        key = (\n                            arg.replace(\"--no-\", \"\")\n                            .lstrip(\"-\")\n                            .replace(\"-\", \"_\")\n                        )\n                    setattr(self.args, key, value)\n\n        kwargs = {**self.args.__dict__}\n        host = kwargs.pop(\"host\")\n        port = kwargs.pop(\"port\")\n        secure = kwargs.pop(\"secure\")\n        raw = kwargs.pop(\"raw\")\n        action = kwargs.pop(\"action\") or \"info\"\n        api_key = kwargs.pop(\"api_key\")\n        positional = kwargs.pop(\"positional\", None)\n        if action == \"<custom>\" and positional:\n            action = positional[0]\n            if len(positional) > 1:\n                kwargs[\"args\"] = positional[1:]\n        InspectorClient(host, port, secure, raw, api_key).do(action, **kwargs)\n\n    def _precheck(self):\n        # Custom TLS mismatch handling for better diagnostics\n        if self.main_process and (\n            # one of cert/key missing\n            bool(self.args.cert) != bool(self.args.key)\n            # new and old style self.args used together\n            or self.args.tls\n            and self.args.cert\n            # strict host checking without certs would always fail\n            or self.args.tlshost\n            and not self.args.tls\n            and not self.args.cert\n        ):\n            self.parser.print_usage(sys.stderr)\n            message = (\n                \"TLS certificates must be specified by either of:\\n\"\n                \"  --cert certdir/fullchain.pem --key certdir/privkey.pem\\n\"\n                \"  --tls certdir  (equivalent to the above)\"\n            )\n            error_logger.error(message)\n            sys.exit(1)\n\n    def _get_app(self, app_loader: AppLoader):\n        try:\n            app = app_loader.load()\n        except ImportError as e:\n            if app_loader.module_name.startswith(e.name):  # type: ignore\n                error_logger.error(\n                    f\"No module named {e.name} found.\\n\"\n                    \"  Example File: project/sanic_server.py -> app\\n\"\n                    \"  Example Module: project.sanic_server.app\"\n                )\n                sys.exit(1)\n            else:\n                raise e\n        return app\n\n    def _build_run_kwargs(self):\n        for group in self.groups:\n            group.prepare(self.args)\n        ssl: Union[None, dict, str, list] = []\n        if self.args.tlshost:\n            ssl.append(None)\n        if self.args.cert is not None or self.args.key is not None:\n            ssl.append(dict(cert=self.args.cert, key=self.args.key))\n        if self.args.tls:\n            ssl += self.args.tls\n        if not ssl:\n            ssl = None\n        elif len(ssl) == 1 and ssl[0] is not None:\n            # Use only one cert, no TLSSelector.\n            ssl = ssl[0]\n\n        kwargs = {\n            \"access_log\": self.args.access_log,\n            \"coffee\": self.args.coffee,\n            \"debug\": self.args.debug,\n            \"fast\": self.args.fast,\n            \"host\": self.args.host,\n            \"motd\": self.args.motd,\n            \"noisy_exceptions\": self.args.noisy_exceptions,\n            \"port\": self.args.port,\n            \"ssl\": ssl,\n            \"unix\": self.args.unix,\n            \"verbosity\": self.args.verbosity or 0,\n            \"workers\": self.args.workers,\n            \"auto_tls\": self.args.auto_tls,\n            \"single_process\": self.args.single,\n        }\n\n        for maybe_arg in (\"auto_reload\", \"dev\"):\n            if getattr(self.args, maybe_arg, False):\n                kwargs[maybe_arg] = True\n\n        if self.args.path:\n            kwargs[\"auto_reload\"] = True\n            kwargs[\"reload_dir\"] = self.args.path\n\n        return kwargs\n", "path": "sanic/cli/app.py"}], "after_files": [{"content": "import os\nimport shutil\nimport sys\n\nfrom argparse import Namespace\nfrom functools import partial\nfrom textwrap import indent\nfrom typing import List, Union\n\nfrom sanic.app import Sanic\nfrom sanic.application.logo import get_logo\nfrom sanic.cli.arguments import Group\nfrom sanic.cli.base import SanicArgumentParser, SanicHelpFormatter\nfrom sanic.cli.inspector import make_inspector_parser\nfrom sanic.cli.inspector_client import InspectorClient\nfrom sanic.log import error_logger\nfrom sanic.worker.loader import AppLoader\n\n\nclass SanicCLI:\n    DESCRIPTION = indent(\n        f\"\"\"\n{get_logo(True)}\n\nTo start running a Sanic application, provide a path to the module, where\napp is a Sanic() instance in the global scope:\n\n    $ sanic path.to.server:app\n\nIf the Sanic instance variable is called 'app', you can leave off the last\npart, and only provide a path to the module where the instance is:\n\n    $ sanic path.to.server\n\nOr, a path to a callable that returns a Sanic() instance:\n\n    $ sanic path.to.factory:create_app\n\nOr, a path to a directory to run as a simple HTTP server:\n\n    $ sanic ./path/to/static\n\"\"\",\n        prefix=\" \",\n    )\n\n    def __init__(self) -> None:\n        width = shutil.get_terminal_size().columns\n        self.parser = SanicArgumentParser(\n            prog=\"sanic\",\n            description=self.DESCRIPTION,\n            formatter_class=lambda prog: SanicHelpFormatter(\n                prog,\n                max_help_position=36 if width > 96 else 24,\n                indent_increment=4,\n                width=None,\n            ),\n        )\n        self.parser._positionals.title = \"Required\\n========\\n  Positional\"\n        self.parser._optionals.title = \"Optional\\n========\\n  General\"\n        self.main_process = (\n            os.environ.get(\"SANIC_RELOADER_PROCESS\", \"\") != \"true\"\n        )\n        self.args: Namespace = Namespace()\n        self.groups: List[Group] = []\n        self.inspecting = False\n\n    def attach(self):\n        if len(sys.argv) > 1 and sys.argv[1] == \"inspect\":\n            self.inspecting = True\n            self.parser.description = get_logo(True)\n            make_inspector_parser(self.parser)\n            return\n\n        for group in Group._registry:\n            instance = group.create(self.parser)\n            instance.attach()\n            self.groups.append(instance)\n\n    def run(self, parse_args=None):\n        if self.inspecting:\n            self._inspector()\n            return\n\n        legacy_version = False\n        if not parse_args:\n            # This is to provide backwards compat -v to display version\n            legacy_version = len(sys.argv) == 2 and sys.argv[-1] == \"-v\"\n            parse_args = [\"--version\"] if legacy_version else None\n        elif parse_args == [\"-v\"]:\n            parse_args = [\"--version\"]\n\n        if not legacy_version:\n            parsed, unknown = self.parser.parse_known_args(args=parse_args)\n            if unknown and parsed.factory:\n                for arg in unknown:\n                    if arg.startswith(\"--\"):\n                        self.parser.add_argument(arg.split(\"=\")[0])\n\n        self.args = self.parser.parse_args(args=parse_args)\n        self._precheck()\n        app_loader = AppLoader(\n            self.args.target, self.args.factory, self.args.simple, self.args\n        )\n\n        try:\n            app = self._get_app(app_loader)\n            kwargs = self._build_run_kwargs()\n        except ValueError as e:\n            error_logger.exception(f\"Failed to run app: {e}\")\n        else:\n            for http_version in self.args.http:\n                app.prepare(**kwargs, version=http_version)\n            if self.args.single:\n                serve = Sanic.serve_single\n            else:\n                serve = partial(Sanic.serve, app_loader=app_loader)\n            serve(app)\n\n    def _inspector(self):\n        args = sys.argv[2:]\n        self.args, unknown = self.parser.parse_known_args(args=args)\n        if unknown:\n            for arg in unknown:\n                if arg.startswith(\"--\"):\n                    try:\n                        key, value = arg.split(\"=\")\n                        key = key.lstrip(\"-\")\n                    except ValueError:\n                        value = False if arg.startswith(\"--no-\") else True\n                        key = (\n                            arg.replace(\"--no-\", \"\")\n                            .lstrip(\"-\")\n                            .replace(\"-\", \"_\")\n                        )\n                    setattr(self.args, key, value)\n\n        kwargs = {**self.args.__dict__}\n        host = kwargs.pop(\"host\")\n        port = kwargs.pop(\"port\")\n        secure = kwargs.pop(\"secure\")\n        raw = kwargs.pop(\"raw\")\n        action = kwargs.pop(\"action\") or \"info\"\n        api_key = kwargs.pop(\"api_key\")\n        positional = kwargs.pop(\"positional\", None)\n        if action == \"<custom>\" and positional:\n            action = positional[0]\n            if len(positional) > 1:\n                kwargs[\"args\"] = positional[1:]\n        InspectorClient(host, port, secure, raw, api_key).do(action, **kwargs)\n\n    def _precheck(self):\n        # Custom TLS mismatch handling for better diagnostics\n        if self.main_process and (\n            # one of cert/key missing\n            bool(self.args.cert) != bool(self.args.key)\n            # new and old style self.args used together\n            or self.args.tls\n            and self.args.cert\n            # strict host checking without certs would always fail\n            or self.args.tlshost\n            and not self.args.tls\n            and not self.args.cert\n        ):\n            self.parser.print_usage(sys.stderr)\n            message = (\n                \"TLS certificates must be specified by either of:\\n\"\n                \"  --cert certdir/fullchain.pem --key certdir/privkey.pem\\n\"\n                \"  --tls certdir  (equivalent to the above)\"\n            )\n            error_logger.error(message)\n            sys.exit(1)\n\n    def _get_app(self, app_loader: AppLoader):\n        try:\n            app = app_loader.load()\n        except ImportError as e:\n            if app_loader.module_name.startswith(e.name):  # type: ignore\n                error_logger.error(\n                    f\"No module named {e.name} found.\\n\"\n                    \"  Example File: project/sanic_server.py -> app\\n\"\n                    \"  Example Module: project.sanic_server.app\"\n                )\n                error_logger.error(\n                    \"\\nThe error below might have caused the above one:\\n\"\n                    f\"{e.msg}\"\n                )\n                sys.exit(1)\n            else:\n                raise e\n        return app\n\n    def _build_run_kwargs(self):\n        for group in self.groups:\n            group.prepare(self.args)\n        ssl: Union[None, dict, str, list] = []\n        if self.args.tlshost:\n            ssl.append(None)\n        if self.args.cert is not None or self.args.key is not None:\n            ssl.append(dict(cert=self.args.cert, key=self.args.key))\n        if self.args.tls:\n            ssl += self.args.tls\n        if not ssl:\n            ssl = None\n        elif len(ssl) == 1 and ssl[0] is not None:\n            # Use only one cert, no TLSSelector.\n            ssl = ssl[0]\n\n        kwargs = {\n            \"access_log\": self.args.access_log,\n            \"coffee\": self.args.coffee,\n            \"debug\": self.args.debug,\n            \"fast\": self.args.fast,\n            \"host\": self.args.host,\n            \"motd\": self.args.motd,\n            \"noisy_exceptions\": self.args.noisy_exceptions,\n            \"port\": self.args.port,\n            \"ssl\": ssl,\n            \"unix\": self.args.unix,\n            \"verbosity\": self.args.verbosity or 0,\n            \"workers\": self.args.workers,\n            \"auto_tls\": self.args.auto_tls,\n            \"single_process\": self.args.single,\n        }\n\n        for maybe_arg in (\"auto_reload\", \"dev\"):\n            if getattr(self.args, maybe_arg, False):\n                kwargs[maybe_arg] = True\n\n        if self.args.path:\n            kwargs[\"auto_reload\"] = True\n            kwargs[\"reload_dir\"] = self.args.path\n\n        return kwargs\n", "path": "sanic/cli/app.py"}]}