From 0030425c8c9c8aef43e30201646e544fdca738d7 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Wed, 23 Mar 2022 12:00:41 +0200 Subject: [PATCH] Conditionally inject CLI arguments into factory (#2402) --- sanic/cli/app.py | 12 ++++++++++- tests/fake/factory.py | 6 ------ tests/fake/server.py | 9 +++++++++ tests/test_cli.py | 46 ++++++++++++++++++++++++++++++++++--------- 4 files changed, 57 insertions(+), 16 deletions(-) delete mode 100644 tests/fake/factory.py diff --git a/sanic/cli/app.py b/sanic/cli/app.py index db830e09..c5d937c6 100644 --- a/sanic/cli/app.py +++ b/sanic/cli/app.py @@ -68,6 +68,13 @@ Or, a path to a directory to run as a simple HTTP server: legacy_version = len(sys.argv) == 2 and sys.argv[-1] == "-v" parse_args = ["--version"] if legacy_version else None + if not parse_args: + parsed, unknown = self.parser.parse_known_args() + if unknown and parsed.factory: + for arg in unknown: + if arg.startswith("--"): + self.parser.add_argument(arg.split("=")[0]) + self.args = self.parser.parse_args(args=parse_args) self._precheck() @@ -128,7 +135,10 @@ Or, a path to a directory to run as a simple HTTP server: module = import_module(module_name) app = getattr(module, app_name, None) if self.args.factory: - app = app() + try: + app = app(self.args) + except TypeError: + app = app() app_type_name = type(app).__name__ diff --git a/tests/fake/factory.py b/tests/fake/factory.py deleted file mode 100644 index 17a815cd..00000000 --- a/tests/fake/factory.py +++ /dev/null @@ -1,6 +0,0 @@ -from sanic import Sanic - - -def run(): - app = Sanic("FactoryTest") - return app diff --git a/tests/fake/server.py b/tests/fake/server.py index 1220c23e..f7941fa3 100644 --- a/tests/fake/server.py +++ b/tests/fake/server.py @@ -34,3 +34,12 @@ async def shutdown(app: Sanic, _): def create_app(): return app + + +def create_app_with_args(args): + try: + print(f"foo={args.foo}") + except AttributeError: + print(f"module={args.module}") + + return app diff --git a/tests/test_cli.py b/tests/test_cli.py index b12bb414..f77e3453 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -39,16 +39,17 @@ def read_app_info(lines): @pytest.mark.parametrize( - "appname", + "appname,extra", ( - "fake.server.app", - "fake.server:app", - "fake.server:create_app()", - "fake.server.create_app()", + ("fake.server.app", None), + ("fake.server:create_app", "--factory"), + ("fake.server.create_app()", None), ), ) -def test_server_run(appname): +def test_server_run(appname, extra): command = ["sanic", appname] + if extra: + command.append(extra) out, err, exitcode = capture(command) lines = out.split(b"\n") firstline = lines[starting_line(lines) + 1] @@ -57,10 +58,37 @@ def test_server_run(appname): assert firstline == b"Goin' Fast @ http://127.0.0.1:8000" -def test_error_with_function_as_instance_without_factory_arg(): - command = ["sanic", "fake.factory.run"] +def test_server_run_factory_with_args(): + command = [ + "sanic", + "fake.server.create_app_with_args", + "--factory", + ] out, err, exitcode = capture(command) - assert b"try: \nsanic fake.factory.run --factory" in err + lines = out.split(b"\n") + + assert exitcode != 1, lines + assert b"module=fake.server.create_app_with_args" in lines + + +def test_server_run_factory_with_args_arbitrary(): + command = [ + "sanic", + "fake.server.create_app_with_args", + "--factory", + "--foo=bar", + ] + out, err, exitcode = capture(command) + lines = out.split(b"\n") + + assert exitcode != 1, lines + assert b"foo=bar" in lines + + +def test_error_with_function_as_instance_without_factory_arg(): + command = ["sanic", "fake.server.create_app"] + out, err, exitcode = capture(command) + assert b"try: \nsanic fake.server.create_app --factory" in err assert exitcode != 1