Skip to content

Commit

Permalink
Merge branch 'main' into feature/name-api
Browse files Browse the repository at this point in the history
  • Loading branch information
RobbeSneyders authored Oct 17, 2023
2 parents 2eec92f + 17fcad0 commit 53cbe50
Show file tree
Hide file tree
Showing 36 changed files with 1,363 additions and 834 deletions.
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ build:
- poetry config virtualenvs.create false
post_install:
# Install dependencies with 'docs' dependency group
- poetry install --with docs
- poetry install --with docs --all-extras
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ supports collection formats "pipes" and "csv". The default format is "csv".
Connexion is opinionated about how the URI is parsed for ``array`` types.
The default behavior for query parameters that have been defined multiple
times is to use the right-most value. For example, if you provide a URI with
the the query string ``?letters=a,b,c&letters=d,e,f``, connexion will set
the query string ``?letters=a,b,c&letters=d,e,f``, connexion will set
``letters = ['d', 'e', 'f']``.

You can override this behavior by specifying the URI parser in the app or
Expand Down
17 changes: 9 additions & 8 deletions connexion/apps/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from connexion.jsonifier import Jsonifier
from connexion.middleware import ConnexionMiddleware, MiddlewarePosition, SpecMiddleware
from connexion.middleware.lifespan import Lifespan
from connexion.options import SwaggerUIOptions
from connexion.resolver import Resolver
from connexion.uri_parsing import AbstractURIParser

Expand All @@ -23,7 +24,7 @@ class AbstractApp:
interface, it delegates most of the work to the middleware and framework application.
"""

middleware_app: SpecMiddleware
_middleware_app: SpecMiddleware
"""
The application wrapped by the ConnexionMiddleware, which in its turn wraps the framework
application.
Expand All @@ -43,7 +44,7 @@ def __init__(
resolver: t.Optional[t.Union[Resolver, t.Callable]] = None,
resolver_error: t.Optional[int] = None,
strict_validation: t.Optional[bool] = None,
swagger_ui_options: t.Optional[dict] = None,
swagger_ui_options: t.Optional[SwaggerUIOptions] = None,
uri_parser_class: t.Optional[AbstractURIParser] = None,
validate_responses: t.Optional[bool] = None,
validator_map: t.Optional[dict] = None,
Expand Down Expand Up @@ -72,8 +73,8 @@ def __init__(
start.
:param strict_validation: When True, extra form or query parameters not defined in the
specification result in a validation error. Defaults to False.
:param swagger_ui_options: A dict with configuration options for the swagger ui. See
:class:`options.ConnexionOptions`.
:param swagger_ui_options: Instance of :class:`options.ConnexionOptions` with
configuration options for the swagger ui.
:param uri_parser_class: Class to use for uri parsing. See :mod:`uri_parsing`.
:param validate_responses: Whether to validate responses against the specification. This has
an impact on performance. Defaults to False.
Expand All @@ -83,7 +84,7 @@ def __init__(
:obj:`security.SECURITY_HANDLERS`
"""
self.middleware = ConnexionMiddleware(
self.middleware_app,
self._middleware_app,
import_name=import_name,
lifespan=lifespan,
middlewares=middlewares,
Expand Down Expand Up @@ -129,7 +130,7 @@ def add_api(
resolver: t.Optional[t.Union[Resolver, t.Callable]] = None,
resolver_error: t.Optional[int] = None,
strict_validation: t.Optional[bool] = None,
swagger_ui_options: t.Optional[dict] = None,
swagger_ui_options: t.Optional[SwaggerUIOptions] = None,
uri_parser_class: t.Optional[AbstractURIParser] = None,
validate_responses: t.Optional[bool] = None,
validator_map: t.Optional[dict] = None,
Expand Down Expand Up @@ -218,7 +219,7 @@ def index():
:param endpoint: the name of the endpoint for the registered URL rule, which is used for
reverse lookup. Flask defaults to the name of the view function.
:param view_func: the function to call when serving a request to the provided endpoint.
:param options: the options to be forwarded to the underlying `werkzeug.routing.Rule`
:param options: the options to be forwarded to the underlying ``werkzeug.routing.Rule``
object. A change to Werkzeug is handling of method options. methods is a list of
methods this rule should be limited to (`GET`, `POST` etc.). By default a rule just
listens for `GET` (and implicitly `HEAD`).
Expand All @@ -235,7 +236,7 @@ def index():
return 'Hello World'
:param rule: the URL rule as string
:param options: the options to be forwarded to the underlying `werkzeug.routing.Rule`
:param options: the options to be forwarded to the underlying ``werkzeug.routing.Rule``
object. A change to Werkzeug is handling of method options. methods is a
list of methods this rule should be limited to (`GET`, `POST` etc.).
By default a rule just listens for `GET` (and implicitly `HEAD`).
Expand Down
11 changes: 6 additions & 5 deletions connexion/apps/asynchronous.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from connexion.middleware.abstract import RoutedAPI, RoutedMiddleware
from connexion.middleware.lifespan import Lifespan
from connexion.operations import AbstractOperation
from connexion.options import SwaggerUIOptions
from connexion.resolver import Resolver
from connexion.uri_parsing import AbstractURIParser

Expand Down Expand Up @@ -135,7 +136,7 @@ def __init__(
resolver: t.Optional[t.Union[Resolver, t.Callable]] = None,
resolver_error: t.Optional[int] = None,
strict_validation: t.Optional[bool] = None,
swagger_ui_options: t.Optional[dict] = None,
swagger_ui_options: t.Optional[SwaggerUIOptions] = None,
uri_parser_class: t.Optional[AbstractURIParser] = None,
validate_responses: t.Optional[bool] = None,
validator_map: t.Optional[dict] = None,
Expand Down Expand Up @@ -165,8 +166,8 @@ def __init__(
start.
:param strict_validation: When True, extra form or query parameters not defined in the
specification result in a validation error. Defaults to False.
:param swagger_ui_options: A dict with configuration options for the swagger ui. See
:class:`options.ConnexionOptions`.
:param swagger_ui_options: Instance of :class:`options.ConnexionOptions` with
configuration options for the swagger ui.
:param uri_parser_class: Class to use for uri parsing. See :mod:`uri_parsing`.
:param validate_responses: Whether to validate responses against the specification. This has
an impact on performance. Defaults to False.
Expand All @@ -175,7 +176,7 @@ def __init__(
:param security_map: A dictionary of security handlers to use. Defaults to
:obj:`security.SECURITY_HANDLERS`
"""
self.middleware_app: AsyncMiddlewareApp = AsyncMiddlewareApp()
self._middleware_app: AsyncMiddlewareApp = AsyncMiddlewareApp()

super().__init__(
import_name,
Expand All @@ -199,7 +200,7 @@ def __init__(
def add_url_rule(
self, rule, endpoint: str = None, view_func: t.Callable = None, **options
):
self.middleware_app.add_url_rule(
self._middleware_app.add_url_rule(
rule, endpoint=endpoint, view_func=view_func, **options
)

Expand Down
15 changes: 8 additions & 7 deletions connexion/apps/flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from connexion.middleware.abstract import AbstractRoutingAPI, SpecMiddleware
from connexion.middleware.lifespan import Lifespan
from connexion.operations import AbstractOperation
from connexion.options import SwaggerUIOptions
from connexion.problem import problem
from connexion.resolver import Resolver
from connexion.uri_parsing import AbstractURIParser
Expand Down Expand Up @@ -176,7 +177,7 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
class FlaskApp(AbstractApp):
"""Connexion Application based on ConnexionMiddleware wrapping a Flask application."""

middleware_app: FlaskMiddlewareApp
_middleware_app: FlaskMiddlewareApp

def __init__(
self,
Expand All @@ -193,7 +194,7 @@ def __init__(
resolver: t.Optional[t.Union[Resolver, t.Callable]] = None,
resolver_error: t.Optional[int] = None,
strict_validation: t.Optional[bool] = None,
swagger_ui_options: t.Optional[dict] = None,
swagger_ui_options: t.Optional[SwaggerUIOptions] = None,
uri_parser_class: t.Optional[AbstractURIParser] = None,
validate_responses: t.Optional[bool] = None,
validator_map: t.Optional[dict] = None,
Expand Down Expand Up @@ -226,8 +227,8 @@ def __init__(
start.
:param strict_validation: When True, extra form or query parameters not defined in the
specification result in a validation error. Defaults to False.
:param swagger_ui_options: A dict with configuration options for the swagger ui. See
:class:`options.ConnexionOptions`.
:param swagger_ui_options: Instance of :class:`options.ConnexionOptions` with
configuration options for the swagger ui.
:param uri_parser_class: Class to use for uri parsing. See :mod:`uri_parsing`.
:param validate_responses: Whether to validate responses against the specification. This has
an impact on performance. Defaults to False.
Expand All @@ -236,8 +237,8 @@ def __init__(
:param security_map: A dictionary of security handlers to use. Defaults to
:obj:`security.SECURITY_HANDLERS`
"""
self.middleware_app = FlaskMiddlewareApp(import_name, server_args or {})
self.app = self.middleware_app.app
self._middleware_app = FlaskMiddlewareApp(import_name, server_args or {})
self.app = self._middleware_app.app
super().__init__(
import_name,
lifespan=lifespan,
Expand All @@ -260,7 +261,7 @@ def __init__(
def add_url_rule(
self, rule, endpoint: str = None, view_func: t.Callable = None, **options
):
self.middleware_app.add_url_rule(
self._middleware_app.add_url_rule(
rule, endpoint=endpoint, view_func=view_func, **options
)

Expand Down
2 changes: 1 addition & 1 deletion connexion/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def main():
)
@click.option(
"--hide-console-ui",
help="Hides the the API console UI which is by default available at `/ui`.",
help="Hides the API console UI which is by default available at `/ui`.",
is_flag=True,
default=False,
)
Expand Down
30 changes: 20 additions & 10 deletions connexion/decorators/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from connexion.decorators.response import (
AsyncResponseDecorator,
BaseResponseDecorator,
NoResponseDecorator,
SyncResponseDecorator,
)
from connexion.frameworks.abstract import Framework
Expand Down Expand Up @@ -94,10 +95,12 @@ def __call__(self, function: t.Callable) -> t.Callable:
raise NotImplementedError


class FlaskDecorator(BaseDecorator):
"""Decorator for usage with Flask. The parameter decorator works with a Flask request,
and provides Flask datastructures to the view function. The response decorator returns
a Flask response"""
class WSGIDecorator(BaseDecorator):
"""Decorator for usage with WSGI apps. The parameter decorator works with a Flask request,
and provides Flask datastructures to the view function. This works for any WSGI app, since
we get the request via the connexion context provided by WSGI middleware.
This decorator does not parse responses, but passes them directly to the WSGI App."""

framework = FlaskFramework

Expand All @@ -106,8 +109,8 @@ def _parameter_decorator_cls(self) -> t.Type[SyncParameterDecorator]:
return SyncParameterDecorator

@property
def _response_decorator_cls(self) -> t.Type[SyncResponseDecorator]:
return SyncResponseDecorator
def _response_decorator_cls(self) -> t.Type[BaseResponseDecorator]:
return NoResponseDecorator

@property
def _sync_async_decorator(self) -> t.Callable[[t.Callable], t.Callable]:
Expand All @@ -133,6 +136,17 @@ def wrapper(*args, **kwargs):
return wrapper


class FlaskDecorator(WSGIDecorator):
"""Decorator for usage with Connexion or Flask apps. The parameter decorator works with a
Flask request, and provides Flask datastructures to the view function.
The response decorator returns Flask responses."""

@property
def _response_decorator_cls(self) -> t.Type[SyncResponseDecorator]:
return SyncResponseDecorator


class ASGIDecorator(BaseDecorator):
"""Decorator for usage with ASGI apps. The parameter decorator works with a Starlette request,
and provides Starlette datastructures to the view function. This works for any ASGI app, since
Expand All @@ -148,10 +162,6 @@ def _parameter_decorator_cls(self) -> t.Type[AsyncParameterDecorator]:

@property
def _response_decorator_cls(self) -> t.Type[BaseResponseDecorator]:
class NoResponseDecorator(BaseResponseDecorator):
def __call__(self, function: t.Callable) -> t.Callable:
return lambda request: function(request)

return NoResponseDecorator

@property
Expand Down
Loading

0 comments on commit 53cbe50

Please sign in to comment.