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 | 44 +++++++++++++++++++++++++++++++++++-------- 4 files changed, 56 insertions(+), 15 deletions(-) delete mode 100644 tests/fake/factory.py diff --git a/sanic/cli/app.py b/sanic/cli/app.py index db830e09a5..c5d937c685 100644 --- a/sanic/cli/app.py +++ b/sanic/cli/app.py @@ -68,6 +68,13 @@ def run(self): 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 @@ def _get_app(self): 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 17a815cd97..0000000000 --- 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 1220c23e84..f7941fa374 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 b12bb41454..f77e345355 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_server_run_factory_with_args(): + command = [ + "sanic", + "fake.server.create_app_with_args", + "--factory", + ] + out, err, exitcode = capture(command) + 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.factory.run"] + command = ["sanic", "fake.server.create_app"] out, err, exitcode = capture(command) - assert b"try: \nsanic fake.factory.run --factory" in err + assert b"try: \nsanic fake.server.create_app --factory" in err assert exitcode != 1