Update CLI for 3.0 (#1687)

Fixes #1684
This commit is contained in:
Robbe Sneyders
2023-04-21 12:11:38 +02:00
committed by GitHub
parent d9b699bf65
commit bcdd26ba0d
2 changed files with 22 additions and 101 deletions

View File

@@ -9,40 +9,23 @@ from os import path
import click
import importlib_metadata
from clickclick import AliasedGroup, fatal_error
from clickclick import AliasedGroup
import connexion
from connexion.mock import MockResolver
logger = logging.getLogger("connexion.cli")
CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
FLASK_APP = "flask"
AVAILABLE_SERVERS = {
"flask": [FLASK_APP],
"gevent": [FLASK_APP],
"tornado": [FLASK_APP],
}
ASYNC_APP = "async"
AVAILABLE_APPS = {
FLASK_APP: "connexion.apps.flask_app.FlaskApp",
}
DEFAULT_SERVERS = {
FLASK_APP: FLASK_APP,
FLASK_APP: "connexion.apps.flask.FlaskApp",
ASYNC_APP: "connexion.apps.asynchronous.AsyncApp",
}
def validate_server_requirements(ctx, param, value):
if value == "gevent":
try:
import gevent # NOQA
except ImportError:
fatal_error("gevent library is not installed")
elif value == "tornado":
try:
import tornado # NOQA
except ImportError:
fatal_error("tornado library is not installed")
else:
return value
# app is defined globally so it can be passed as an import_string to `app.run`, which is needed
# to enable reloading
app = None
def print_version(ctx, param, value):
@@ -52,7 +35,7 @@ def print_version(ctx, param, value):
ctx.exit()
@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS)
@click.group(cls=AliasedGroup, context_settings={"help_option_names": ["-h", "--help"]})
@click.option(
"-V",
"--version",
@@ -70,20 +53,8 @@ def main():
@click.argument("spec_file")
@click.argument("base_module_path", required=False)
@click.option("--port", "-p", default=5000, type=int, help="Port to listen.")
@click.option("--host", "-H", type=str, help="Host interface to bind on.")
@click.option(
"--wsgi-server",
"-w",
type=click.Choice(list(AVAILABLE_SERVERS)),
callback=validate_server_requirements,
help="Which WSGI server container to use. (deprecated, use --server instead)",
)
@click.option(
"--server",
"-s",
type=click.Choice(list(AVAILABLE_SERVERS)),
callback=validate_server_requirements,
help="Which server container to use.",
"--host", "-H", default="127.0.0.1", type=str, help="Host interface to bind on."
)
@click.option(
"--stub",
@@ -147,7 +118,7 @@ def main():
@click.option(
"--app-framework",
"-f",
default=FLASK_APP,
default=ASYNC_APP,
type=click.Choice(list(AVAILABLE_APPS)),
help="The app framework used to run the server",
)
@@ -156,8 +127,6 @@ def run(
base_module_path,
port,
host,
wsgi_server,
server,
stub,
mock,
hide_spec,
@@ -181,23 +150,6 @@ def run(
- BASE_MODULE_PATH (optional): filesystem path where the API endpoints handlers are going to be imported from.
"""
if wsgi_server and server:
raise click.BadParameter(
"these options are mutually exclusive",
param_hint="'wsgi-server' and 'server'",
)
elif wsgi_server:
server = wsgi_server
if server is None:
server = DEFAULT_SERVERS[app_framework]
if app_framework not in AVAILABLE_SERVERS[server]:
message = "Invalid server '{}' for app-framework '{}'".format(
server, app_framework
)
raise click.UsageError(message)
logging_level = logging.WARN
if verbose > 0:
logging_level = logging.INFO
@@ -224,14 +176,17 @@ def run(
app_cls = connexion.utils.get_function_from_name(AVAILABLE_APPS[app_framework])
options = {
swagger_ui_options = {
"serve_spec": not hide_spec,
"swagger_path": console_ui_from or None,
"swagger_ui": not hide_console_ui,
"swagger_url": console_ui_url or None,
}
app = app_cls(__name__, auth_all_paths=auth_all_paths, options=options)
global app
app = app_cls(
__name__, auth_all_paths=auth_all_paths, swagger_ui_options=swagger_ui_options
)
app.add_api(
spec_file_full_path,
@@ -242,7 +197,7 @@ def run(
**api_extra_args,
)
app.run(port=port, host=host, server=server, debug=debug)
app.run("connexion.cli:app", port=port, host=host, debug=debug)
if __name__ == "__main__": # pragma: no cover

View File

@@ -35,7 +35,7 @@ def expected_arguments():
Default values arguments used to call `connexion.App` by cli.
"""
return {
"options": {
"swagger_ui_options": {
"serve_spec": True,
"swagger_ui": True,
"swagger_path": None,
@@ -90,7 +90,7 @@ def test_run_using_option_hide_spec(mock_app_run, expected_arguments, spec_file)
runner = CliRunner()
runner.invoke(main, ["run", spec_file, "--hide-spec"], catch_exceptions=False)
expected_arguments["options"]["serve_spec"] = False
expected_arguments["swagger_ui_options"]["serve_spec"] = False
mock_app_run.assert_called_with("connexion.cli", **expected_arguments)
@@ -98,7 +98,7 @@ def test_run_using_option_hide_console_ui(mock_app_run, expected_arguments, spec
runner = CliRunner()
runner.invoke(main, ["run", spec_file, "--hide-console-ui"], catch_exceptions=False)
expected_arguments["options"]["swagger_ui"] = False
expected_arguments["swagger_ui_options"]["swagger_ui"] = False
mock_app_run.assert_called_with("connexion.cli", **expected_arguments)
@@ -109,7 +109,7 @@ def test_run_using_option_console_ui_from(mock_app_run, expected_arguments, spec
main, ["run", spec_file, "--console-ui-from", user_path], catch_exceptions=False
)
expected_arguments["options"]["swagger_path"] = user_path
expected_arguments["swagger_ui_options"]["swagger_path"] = user_path
mock_app_run.assert_called_with("connexion.cli", **expected_arguments)
@@ -120,7 +120,7 @@ def test_run_using_option_console_ui_url(mock_app_run, expected_arguments, spec_
main, ["run", spec_file, "--console-ui-url", user_url], catch_exceptions=False
)
expected_arguments["options"]["swagger_url"] = user_url
expected_arguments["swagger_ui_options"]["swagger_url"] = user_url
mock_app_run.assert_called_with("connexion.cli", **expected_arguments)
@@ -202,37 +202,3 @@ def test_run_unimplemented_operations_and_mock(mock_app_run):
main, ["run", spec_file, "--mock=all"], catch_exceptions=False
)
assert result.exit_code == 0
def test_run_with_wsgi_containers(mock_app_run, spec_file):
runner = CliRunner()
# missing gevent
result = runner.invoke(
main, ["run", spec_file, "-w", "gevent"], catch_exceptions=False
)
assert "gevent library is not installed" in result.output
assert result.exit_code == 1
# missing tornado
result = runner.invoke(
main, ["run", spec_file, "-w", "tornado"], catch_exceptions=False
)
assert "tornado library is not installed" in result.output
assert result.exit_code == 1
# using flask
result = runner.invoke(
main, ["run", spec_file, "-w", "flask"], catch_exceptions=False
)
assert result.exit_code == 0
def test_run_with_wsgi_server_and_server_opts(mock_app_run, spec_file):
runner = CliRunner()
result = runner.invoke(
main, ["run", spec_file, "-w", "flask", "-s", "flask"], catch_exceptions=False
)
assert "these options are mutually exclusive" in result.output
assert result.exit_code == 2