support app factory patten in CLI (#2157)
* support app factory patten in CLI * Update sanic/__main__.py * fix mypy errors * Update mypy further * Update sanic/utils.py * Update sanic/utils.py * support hypercorn/gunicorn style 'asgi.app:create_app()' * add test for app factory
This commit is contained in:
parent
141be0028d
commit
48f8b37b74
|
@ -75,6 +75,14 @@ def main():
|
|||
action="store_true",
|
||||
help="Watch source directory for file changes and reload on changes",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--factory",
|
||||
action="store_true",
|
||||
help=(
|
||||
"Treat app as an application factory, "
|
||||
"i.e. a () -> <Sanic app> callable."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--version",
|
||||
|
@ -97,13 +105,20 @@ def main():
|
|||
delimiter = ":" if ":" in args.module else "."
|
||||
module_name, app_name = args.module.rsplit(delimiter, 1)
|
||||
|
||||
if app_name.endswith("()"):
|
||||
args.factory = True
|
||||
app_name = app_name[:-2]
|
||||
|
||||
module = import_module(module_name)
|
||||
app = getattr(module, app_name, None)
|
||||
app_name = type(app).__name__
|
||||
if args.factory:
|
||||
app = app()
|
||||
|
||||
app_type_name = type(app).__name__
|
||||
|
||||
if not isinstance(app, Sanic):
|
||||
raise ValueError(
|
||||
f"Module is not a Sanic app, it is a {app_name}. "
|
||||
f"Module is not a Sanic app, it is a {app_type_name}. "
|
||||
f"Perhaps you meant {args.module}.app?"
|
||||
)
|
||||
if args.cert is not None or args.key is not None:
|
||||
|
|
|
@ -105,6 +105,7 @@ def load_module_from_file_location(
|
|||
_mod_spec = spec_from_file_location(
|
||||
name, location, *args, **kwargs
|
||||
)
|
||||
assert _mod_spec is not None # type assertion for mypy
|
||||
module = module_from_spec(_mod_spec)
|
||||
_mod_spec.loader.exec_module(module) # type: ignore
|
||||
|
||||
|
|
|
@ -30,3 +30,7 @@ async def app_info_dump(app: Sanic, _):
|
|||
@app.after_server_start
|
||||
async def shutdown(app: Sanic, _):
|
||||
app.stop()
|
||||
|
||||
|
||||
def create_app():
|
||||
return app
|
||||
|
|
|
@ -26,7 +26,15 @@ def capture(command):
|
|||
return out, err, proc.returncode
|
||||
|
||||
|
||||
@pytest.mark.parametrize("appname", ("fake.server.app", "fake.server:app"))
|
||||
@pytest.mark.parametrize(
|
||||
"appname",
|
||||
(
|
||||
"fake.server.app",
|
||||
"fake.server:app",
|
||||
"fake.server:create_app()",
|
||||
"fake.server.create_app()",
|
||||
)
|
||||
)
|
||||
def test_server_run(appname):
|
||||
command = ["sanic", appname]
|
||||
out, err, exitcode = capture(command)
|
||||
|
|
Loading…
Reference in New Issue
Block a user