mirror of
https://github.com/LukeHagar/connexion.git
synced 2025-12-07 12:27:46 +00:00
Provide CLI support for runnning specifications
This commit is contained in:
56
connexion/cli.py
Normal file
56
connexion/cli.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
import click
|
||||||
|
from connexion import App
|
||||||
|
|
||||||
|
from clickclick import AliasedGroup
|
||||||
|
|
||||||
|
main = AliasedGroup(context_settings=dict(help_option_names=[
|
||||||
|
'-h', '--help']))
|
||||||
|
|
||||||
|
|
||||||
|
@main.command()
|
||||||
|
@click.argument('spec_file')
|
||||||
|
@click.argument('base_path', required=False)
|
||||||
|
@click.option('--port', '-p', default=5000, type=int, help='Port to listen.')
|
||||||
|
@click.option('--server', '-s', default='gevent',
|
||||||
|
type=click.Choice(['gevent', 'tornado']),
|
||||||
|
help='Which WSGI server to use.')
|
||||||
|
@click.option('--hide-spec',
|
||||||
|
help='Hides the API spec in JSON format which is by default available at `/swagger.json`.',
|
||||||
|
is_flag=True, default=True)
|
||||||
|
@click.option('--hide-swagger-ui',
|
||||||
|
help='Hides the the Swagger UI which is by default available at `/ui`.',
|
||||||
|
is_flag=True, default=True)
|
||||||
|
@click.option('--swagger-ui-url', metavar='URL',
|
||||||
|
help='Personalize what URL path the Swagger UI will be mounted.')
|
||||||
|
@click.option('--swagger-ui-from', metavar='PATH',
|
||||||
|
help='Path to a customized Swagger UI dashboard.')
|
||||||
|
@click.option('--auth-all-paths',
|
||||||
|
help='Enable authentication to paths not defined in the spec.',
|
||||||
|
is_flag=True, default=False)
|
||||||
|
@click.option('--debug', '-d', help='Show debugging information.',
|
||||||
|
is_flag=True, default=False)
|
||||||
|
def run(spec_file, base_path, port, server, debug):
|
||||||
|
"""
|
||||||
|
Runs a server using the passed OpenAPI/Swagger 2.0 Specification file.
|
||||||
|
|
||||||
|
Possible arguments:
|
||||||
|
|
||||||
|
- SPEC_FILE: specification file of the API to run.
|
||||||
|
|
||||||
|
- BASE_PATH (optional): filesystem path from where to import the API handlers.
|
||||||
|
"""
|
||||||
|
logging_level = logging.ERROR
|
||||||
|
if debug:
|
||||||
|
logging_level = logging.DEBUG
|
||||||
|
logging.basicConfig(level=logging_level)
|
||||||
|
|
||||||
|
sys.path.insert(1, path.abspath(base_path or '.'))
|
||||||
|
|
||||||
|
app = App(__name__)
|
||||||
|
app.add_api(path.abspath(spec_file))
|
||||||
|
click.echo('Running at http://localhost:{}/...'.format(port))
|
||||||
|
app.run(port=port, server=server)
|
||||||
@@ -20,7 +20,6 @@ import string
|
|||||||
import flask
|
import flask
|
||||||
import werkzeug.wrappers
|
import werkzeug.wrappers
|
||||||
|
|
||||||
|
|
||||||
PATH_PARAMETER = re.compile(r'\{([^}]*)\}')
|
PATH_PARAMETER = re.compile(r'\{([^}]*)\}')
|
||||||
|
|
||||||
# map Swagger type to flask path converter
|
# map Swagger type to flask path converter
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ requests>=2.9.1
|
|||||||
six>=1.7
|
six>=1.7
|
||||||
strict-rfc3339>=0.6
|
strict-rfc3339>=0.6
|
||||||
swagger_spec_validator>=2.0.2
|
swagger_spec_validator>=2.0.2
|
||||||
|
clickclick>=1.1
|
||||||
|
|||||||
3
setup.py
3
setup.py
@@ -88,5 +88,6 @@ setup(
|
|||||||
'Topic :: Software Development :: Libraries :: Application Frameworks'
|
'Topic :: Software Development :: Libraries :: Application Frameworks'
|
||||||
],
|
],
|
||||||
include_package_data=True, # needed to include swagger-ui (see MANIFEST.in)
|
include_package_data=True, # needed to include swagger-ui (see MANIFEST.in)
|
||||||
|
entry_points={'console_scripts': ['connexion = connexion.cli:main',
|
||||||
|
'cnx = connexion.cli:main']}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -287,5 +287,3 @@ def test_args_kwargs(simple_app):
|
|||||||
resp = app_client.get('/v1.0/query-params-as-kwargs?foo=a&bar=b')
|
resp = app_client.get('/v1.0/query-params-as-kwargs?foo=a&bar=b')
|
||||||
assert resp.status_code == 200
|
assert resp.status_code == 200
|
||||||
assert json.loads(resp.data.decode()) == {'foo': 'a'}
|
assert json.loads(resp.data.decode()) == {'foo': 'a'}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
52
tests/test_cli.py
Normal file
52
tests/test_cli.py
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from click.testing import CliRunner
|
||||||
|
from connexion import App, __version__
|
||||||
|
from connexion.cli import main
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from conftest import FIXTURES_FOLDER
|
||||||
|
from mock import MagicMock
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def mock_app_run(monkeypatch):
|
||||||
|
test_server = MagicMock(wraps=App(__name__))
|
||||||
|
test_server.run = MagicMock(return_value=True)
|
||||||
|
test_app = MagicMock(return_value=test_server)
|
||||||
|
monkeypatch.setattr('connexion.cli.App', test_app)
|
||||||
|
return test_server
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_missing_spec():
|
||||||
|
runner = CliRunner()
|
||||||
|
result = runner.invoke(main, ['run'], catch_exceptions=False)
|
||||||
|
assert "Missing argument" in result.output
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_simple_spec(mock_app_run):
|
||||||
|
spec_file = str(FIXTURES_FOLDER / 'simple/swagger.yaml')
|
||||||
|
default_port = 5000
|
||||||
|
default_server = 'gevent'
|
||||||
|
runner = CliRunner()
|
||||||
|
result = runner.invoke(main,
|
||||||
|
['run', spec_file],
|
||||||
|
catch_exceptions=False)
|
||||||
|
|
||||||
|
mock_app_run.run.assert_called_with(port=default_port, server=default_server)
|
||||||
|
assert 'Running at' in result.output
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_in_debug_mode(mock_app_run, monkeypatch):
|
||||||
|
spec_file = str(FIXTURES_FOLDER / 'simple/swagger.yaml')
|
||||||
|
|
||||||
|
logging_config = MagicMock(name='connexion.cli.logging.basicConfig')
|
||||||
|
monkeypatch.setattr('connexion.cli.logging.basicConfig',
|
||||||
|
logging_config)
|
||||||
|
|
||||||
|
runner = CliRunner()
|
||||||
|
result = runner.invoke(main,
|
||||||
|
['run', spec_file, '-d'],
|
||||||
|
catch_exceptions=False)
|
||||||
|
|
||||||
|
logging_config.assert_called_with(level=logging.DEBUG)
|
||||||
Reference in New Issue
Block a user