You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by po...@apache.org on 2022/01/22 15:49:37 UTC

[airflow] 24/33: Switch to non-vendored latest connexion library (#20910)

This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch v2-2-test
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit 878287c9db7d5f71414021890260f12874097e4a
Author: Jarek Potiuk <ja...@potiuk.com>
AuthorDate: Tue Jan 18 15:18:01 2022 +0100

    Switch to non-vendored latest connexion library (#20910)
    
    The `connexion` library has been vendored in because of requests
    library that used to have non-optional chardet LGPL dependency,
    however requests library had since released a version (which we
    helped to provide and convince the requests maintainer to merge)
    where chardet is an optional dependency (with mandatory
    charset_normalizer). This means that we do not need to vendor-in
    connexion any more.
    
    Also connexion after being somewhat abandoned, has been
    "revived" and there are active community now that maintains it -
    they released several new versions since 2.7.0 we used (2.10.0 is
    now the latest version, so we can upgrade to that version instead)
    
    (cherry picked from commit 2c761cc335ef09de40c0337e8bcb48ae449b51ab)
---
 airflow/_vendor/connexion/__init__.py              |  48 ---
 airflow/_vendor/connexion/__main__.py              |   3 -
 airflow/_vendor/connexion/apis/__init__.py         |   1 -
 airflow/_vendor/connexion/apis/abstract.py         | 446 ---------------------
 airflow/_vendor/connexion/apis/aiohttp_api.py      | 394 ------------------
 airflow/_vendor/connexion/apis/flask_api.py        | 310 --------------
 airflow/_vendor/connexion/apis/flask_utils.py      |  81 ----
 airflow/_vendor/connexion/apps/__init__.py         |   1 -
 airflow/_vendor/connexion/apps/abstract.py         | 249 ------------
 airflow/_vendor/connexion/apps/aiohttp_app.py      |  95 -----
 airflow/_vendor/connexion/apps/flask_app.py        | 138 -------
 airflow/_vendor/connexion/cli.py                   | 210 ----------
 airflow/_vendor/connexion/decorators/__init__.py   |   0
 .../connexion/decorators/coroutine_wrappers.py     |  53 ---
 airflow/_vendor/connexion/decorators/decorator.py  |  51 ---
 airflow/_vendor/connexion/decorators/metrics.py    |  54 ---
 airflow/_vendor/connexion/decorators/parameter.py  | 123 ------
 airflow/_vendor/connexion/decorators/produces.py   |  49 ---
 airflow/_vendor/connexion/decorators/response.py   | 112 ------
 airflow/_vendor/connexion/decorators/security.py   | 341 ----------------
 .../_vendor/connexion/decorators/uri_parsing.py    | 329 ---------------
 airflow/_vendor/connexion/decorators/validation.py | 386 ------------------
 airflow/_vendor/connexion/exceptions.py            | 142 -------
 airflow/_vendor/connexion/handlers.py              |  85 ----
 airflow/_vendor/connexion/http_facts.py            |  15 -
 airflow/_vendor/connexion/json_schema.py           | 114 ------
 airflow/_vendor/connexion/jsonifier.py             |  57 ---
 airflow/_vendor/connexion/lifecycle.py             |  41 --
 airflow/_vendor/connexion/mock.py                  |  47 ---
 airflow/_vendor/connexion/operations/__init__.py   |   8 -
 airflow/_vendor/connexion/operations/abstract.py   | 445 --------------------
 airflow/_vendor/connexion/operations/compat.py     |   3 -
 airflow/_vendor/connexion/operations/openapi.py    | 380 ------------------
 airflow/_vendor/connexion/operations/secure.py     | 164 --------
 airflow/_vendor/connexion/operations/swagger2.py   | 310 --------------
 airflow/_vendor/connexion/options.py               | 144 -------
 airflow/_vendor/connexion/problem.py               |  42 --
 airflow/_vendor/connexion/resolver.py              | 192 ---------
 airflow/_vendor/connexion/setup.cfg                |   7 -
 airflow/_vendor/connexion/setup.py                 | 119 ------
 airflow/_vendor/connexion/spec.py                  | 262 ------------
 airflow/_vendor/connexion/utils.py                 | 250 ------------
 .../api_connexion/endpoints/connection_endpoint.py |   2 +-
 airflow/api_connexion/endpoints/dag_endpoint.py    |   2 +-
 .../api_connexion/endpoints/dag_run_endpoint.py    |   2 +-
 .../endpoints/role_and_permission_endpoint.py      |   2 +-
 airflow/api_connexion/endpoints/user_endpoint.py   |   2 +
 airflow/api_connexion/exceptions.py                |   2 +-
 airflow/exceptions.py                              |   4 +-
 airflow/www/extensions/init_views.py               |   5 +-
 licenses/LICENSE-connexion.txt                     |   9 -
 setup.cfg                                          |  10 +-
 52 files changed, 12 insertions(+), 6329 deletions(-)

diff --git a/airflow/_vendor/connexion/__init__.py b/airflow/_vendor/connexion/__init__.py
deleted file mode 100755
index 8286d6c..0000000
--- a/airflow/_vendor/connexion/__init__.py
+++ /dev/null
@@ -1,48 +0,0 @@
-import sys
-
-import werkzeug.exceptions as exceptions  # NOQA
-
-from .apis import AbstractAPI  # NOQA
-from .apps import AbstractApp  # NOQA
-from .decorators.produces import NoContent  # NOQA
-from .exceptions import ProblemException  # NOQA
-# add operation for backwards compatability
-from .operations import compat
-from .problem import problem  # NOQA
-from .resolver import Resolution, Resolver, RestyResolver  # NOQA
-
-full_name = '{}.operation'.format(__package__)
-sys.modules[full_name] = sys.modules[compat.__name__]
-
-
-def not_installed_error(exc):  # pragma: no cover
-    import functools
-
-    def _required_lib(exc, *args, **kwargs):
-        raise exc
-
-    return functools.partial(_required_lib, exc)
-
-
-try:
-    from .apis.flask_api import FlaskApi, context  # NOQA
-    from .apps.flask_app import FlaskApp
-    from flask import request  # NOQA
-except ImportError as e:  # pragma: no cover
-    _flask_not_installed_error = not_installed_error(e)
-    FlaskApi = _flask_not_installed_error
-    FlaskApp = _flask_not_installed_error
-
-App = FlaskApp
-Api = FlaskApi
-
-try:
-    from .apis.aiohttp_api import AioHttpApi
-    from .apps.aiohttp_app import AioHttpApp
-except ImportError as e:  # pragma: no cover
-    _aiohttp_not_installed_error = not_installed_error(e)
-    AioHttpApi = _aiohttp_not_installed_error
-    AioHttpApp = _aiohttp_not_installed_error
-
-# This version is replaced during release process.
-__version__ = '2.7.0'
diff --git a/airflow/_vendor/connexion/__main__.py b/airflow/_vendor/connexion/__main__.py
deleted file mode 100644
index b96e8e6..0000000
--- a/airflow/_vendor/connexion/__main__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from airflow._vendor.connexion.cli import main  # pragma: no cover
-
-main()  # pragma: no cover
diff --git a/airflow/_vendor/connexion/apis/__init__.py b/airflow/_vendor/connexion/apis/__init__.py
deleted file mode 100644
index cf36fd6..0000000
--- a/airflow/_vendor/connexion/apis/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from .abstract import AbstractAPI  # NOQA
diff --git a/airflow/_vendor/connexion/apis/abstract.py b/airflow/_vendor/connexion/apis/abstract.py
deleted file mode 100644
index c2de704..0000000
--- a/airflow/_vendor/connexion/apis/abstract.py
+++ /dev/null
@@ -1,446 +0,0 @@
-import abc
-import logging
-import pathlib
-import sys
-import warnings
-from enum import Enum
-
-from ..decorators.produces import NoContent
-from ..exceptions import ResolverError
-from ..http_facts import METHODS
-from ..jsonifier import Jsonifier
-from ..lifecycle import ConnexionResponse
-from ..operations import make_operation
-from ..options import ConnexionOptions
-from ..resolver import Resolver
-from ..spec import Specification
-from ..utils import is_json_mimetype
-
-MODULE_PATH = pathlib.Path(__file__).absolute().parent.parent
-SWAGGER_UI_URL = 'ui'
-
-logger = logging.getLogger('connexion.apis.abstract')
-
-
-class AbstractAPIMeta(abc.ABCMeta):
-
-    def __init__(cls, name, bases, attrs):
-        abc.ABCMeta.__init__(cls, name, bases, attrs)
-        cls._set_jsonifier()
-
-
-class AbstractAPI(metaclass=AbstractAPIMeta):
-    """
-    Defines an abstract interface for a Swagger API
-    """
-
-    def __init__(self, specification, base_path=None, arguments=None,
-                 validate_responses=False, strict_validation=False, resolver=None,
-                 auth_all_paths=False, debug=False, resolver_error_handler=None,
-                 validator_map=None, pythonic_params=False, pass_context_arg_name=None, options=None):
-        """
-        :type specification: pathlib.Path | dict
-        :type base_path: str | None
-        :type arguments: dict | None
-        :type validate_responses: bool
-        :type strict_validation: bool
-        :type auth_all_paths: bool
-        :type debug: bool
-        :param validator_map: Custom validators for the types "parameter", "body" and "response".
-        :type validator_map: dict
-        :param resolver: Callable that maps operationID to a function
-        :param resolver_error_handler: If given, a callable that generates an
-            Operation used for handling ResolveErrors
-        :type resolver_error_handler: callable | None
-        :param pythonic_params: When True CamelCase parameters are converted to snake_case and an underscore is appended
-        to any shadowed built-ins
-        :type pythonic_params: bool
-        :param options: New style options dictionary.
-        :type options: dict | None
-        :param pass_context_arg_name: If not None URL request handling functions with an argument matching this name
-        will be passed the framework's request context.
-        :type pass_context_arg_name: str | None
-        """
-        self.debug = debug
-        self.validator_map = validator_map
-        self.resolver_error_handler = resolver_error_handler
-
-        logger.debug('Loading specification: %s', specification,
-                     extra={'swagger_yaml': specification,
-                            'base_path': base_path,
-                            'arguments': arguments,
-                            'auth_all_paths': auth_all_paths})
-
-        # Avoid validator having ability to modify specification
-        self.specification = Specification.load(specification, arguments=arguments)
-
-        logger.debug('Read specification', extra={'spec': self.specification})
-
-        self.options = ConnexionOptions(options, oas_version=self.specification.version)
-
-        logger.debug('Options Loaded',
-                     extra={'swagger_ui': self.options.openapi_console_ui_available,
-                            'swagger_path': self.options.openapi_console_ui_from_dir,
-                            'swagger_url': self.options.openapi_console_ui_path})
-
-        self._set_base_path(base_path)
-
-        logger.debug('Security Definitions: %s', self.specification.security_definitions)
-
-        self.resolver = resolver or Resolver()
-
-        logger.debug('Validate Responses: %s', str(validate_responses))
-        self.validate_responses = validate_responses
-
-        logger.debug('Strict Request Validation: %s', str(strict_validation))
-        self.strict_validation = strict_validation
-
-        logger.debug('Pythonic params: %s', str(pythonic_params))
-        self.pythonic_params = pythonic_params
-
-        logger.debug('pass_context_arg_name: %s', pass_context_arg_name)
-        self.pass_context_arg_name = pass_context_arg_name
-
-        if self.options.openapi_spec_available:
-            self.add_openapi_json()
-            self.add_openapi_yaml()
-
-        if self.options.openapi_console_ui_available:
-            self.add_swagger_ui()
-
-        self.add_paths()
-
-        if auth_all_paths:
-            self.add_auth_on_not_found(
-                self.specification.security,
-                self.specification.security_definitions
-            )
-
-    def _set_base_path(self, base_path=None):
-        if base_path is not None:
-            # update spec to include user-provided base_path
-            self.specification.base_path = base_path
-            self.base_path = base_path
-        else:
-            self.base_path = self.specification.base_path
-
-    @abc.abstractmethod
-    def add_openapi_json(self):
-        """
-        Adds openapi spec to {base_path}/openapi.json
-             (or {base_path}/swagger.json for swagger2)
-        """
-
-    @abc.abstractmethod
-    def add_swagger_ui(self):
-        """
-        Adds swagger ui to {base_path}/ui/
-        """
-
-    @abc.abstractmethod
-    def add_auth_on_not_found(self, security, security_definitions):
-        """
-        Adds a 404 error handler to authenticate and only expose the 404 status if the security validation pass.
-        """
-
-    def add_operation(self, path, method):
-        """
-        Adds one operation to the api.
-
-        This method uses the OperationID identify the module and function that will handle the operation
-
-        From Swagger Specification:
-
-        **OperationID**
-
-        A friendly name for the operation. The id MUST be unique among all operations described in the API.
-        Tools and libraries MAY use the operation id to uniquely identify an operation.
-
-        :type method: str
-        :type path: str
-        """
-        operation = make_operation(
-            self.specification,
-            self,
-            path,
-            method,
-            self.resolver,
-            validate_responses=self.validate_responses,
-            validator_map=self.validator_map,
-            strict_validation=self.strict_validation,
-            pythonic_params=self.pythonic_params,
-            uri_parser_class=self.options.uri_parser_class,
-            pass_context_arg_name=self.pass_context_arg_name
-        )
-        self._add_operation_internal(method, path, operation)
-
-    @abc.abstractmethod
-    def _add_operation_internal(self, method, path, operation):
-        """
-        Adds the operation according to the user framework in use.
-        It will be used to register the operation on the user framework router.
-        """
-
-    def _add_resolver_error_handler(self, method, path, err):
-        """
-        Adds a handler for ResolverError for the given method and path.
-        """
-        operation = self.resolver_error_handler(
-            err,
-            security=self.specification.security,
-            security_definitions=self.specification.security_definitions
-        )
-        self._add_operation_internal(method, path, operation)
-
-    def add_paths(self, paths=None):
-        """
-        Adds the paths defined in the specification as endpoints
-
-        :type paths: list
-        """
-        paths = paths or self.specification.get('paths', dict())
-        for path, methods in paths.items():
-            logger.debug('Adding %s%s...', self.base_path, path)
-
-            for method in methods:
-                if method not in METHODS:
-                    continue
-                try:
-                    self.add_operation(path, method)
-                except ResolverError as err:
-                    # If we have an error handler for resolver errors, add it as an operation.
-                    # Otherwise treat it as any other error.
-                    if self.resolver_error_handler is not None:
-                        self._add_resolver_error_handler(method, path, err)
-                    else:
-                        self._handle_add_operation_error(path, method, err.exc_info)
-                except Exception:
-                    # All other relevant exceptions should be handled as well.
-                    self._handle_add_operation_error(path, method, sys.exc_info())
-
-    def _handle_add_operation_error(self, path, method, exc_info):
-        url = '{base_path}{path}'.format(base_path=self.base_path, path=path)
-        error_msg = 'Failed to add operation for {method} {url}'.format(
-            method=method.upper(),
-            url=url)
-        if self.debug:
-            logger.exception(error_msg)
-        else:
-            logger.error(error_msg)
-            _type, value, traceback = exc_info
-            raise value.with_traceback(traceback)
-
-    @classmethod
-    @abc.abstractmethod
-    def get_request(self, *args, **kwargs):
-        """
-        This method converts the user framework request to a ConnexionRequest.
-        """
-
-    @classmethod
-    @abc.abstractmethod
-    def get_response(self, response, mimetype=None, request=None):
-        """
-        This method converts a handler response to a framework response.
-        This method should just retrieve response from handler then call `cls._get_response`.
-        It is mainly here to handle AioHttp async handler.
-        :param response: A response to cast (tuple, framework response, etc).
-        :param mimetype: The response mimetype.
-        :type mimetype: Union[None, str]
-        :param request: The request associated with this response (the user framework request).
-        """
-
-    @classmethod
-    def _get_response(cls, response, mimetype=None, extra_context=None):
-        """
-        This method converts a handler response to a framework response.
-        The response can be a ConnexionResponse, an operation handler, a framework response or a tuple.
-        Other type than ConnexionResponse are handled by `cls._response_from_handler`
-        :param response: A response to cast (tuple, framework response, etc).
-        :param mimetype: The response mimetype.
-        :type mimetype: Union[None, str]
-        :param extra_context: dict of extra details, like url, to include in logs
-        :type extra_context: Union[None, dict]
-        """
-        if extra_context is None:
-            extra_context = {}
-        logger.debug('Getting data and status code',
-                     extra={
-                         'data': response,
-                         'data_type': type(response),
-                         **extra_context
-                     })
-
-        if isinstance(response, ConnexionResponse):
-            framework_response = cls._connexion_to_framework_response(response, mimetype, extra_context)
-        else:
-            framework_response = cls._response_from_handler(response, mimetype, extra_context)
-
-        logger.debug('Got framework response',
-                     extra={
-                         'response': framework_response,
-                         'response_type': type(framework_response),
-                         **extra_context
-                     })
-        return framework_response
-
-    @classmethod
-    def _response_from_handler(cls, response, mimetype, extra_context=None):
-        """
-        Create a framework response from the operation handler data.
-        An operation handler can return:
-        - a framework response
-        - a body (str / binary / dict / list), a response will be created
-            with a status code 200 by default and empty headers.
-        - a tuple of (body: str, status_code: int)
-        - a tuple of (body: str, status_code: int, headers: dict)
-        :param response: A response from an operation handler.
-        :type response Union[Response, str, Tuple[str,], Tuple[str, int], Tuple[str, int, dict]]
-        :param mimetype: The response mimetype.
-        :type mimetype: str
-        :param extra_context: dict of extra details, like url, to include in logs
-        :type extra_context: Union[None, dict]
-        :return A framework response.
-        :rtype Response
-        """
-        if cls._is_framework_response(response):
-            return response
-
-        if isinstance(response, tuple):
-            len_response = len(response)
-            if len_response == 1:
-                data, = response
-                return cls._build_response(mimetype=mimetype, data=data, extra_context=extra_context)
-            if len_response == 2:
-                if isinstance(response[1], (int, Enum)):
-                    data, status_code = response
-                    return cls._build_response(mimetype=mimetype, data=data, status_code=status_code, extra_context=extra_context)
-                else:
-                    data, headers = response
-                return cls._build_response(mimetype=mimetype, data=data, headers=headers, extra_context=extra_context)
-            elif len_response == 3:
-                data, status_code, headers = response
-                return cls._build_response(mimetype=mimetype, data=data, status_code=status_code, headers=headers, extra_context=extra_context)
-            else:
-                raise TypeError(
-                    'The view function did not return a valid response tuple.'
-                    ' The tuple must have the form (body), (body, status, headers),'
-                    ' (body, status), or (body, headers).'
-                )
-        else:
-            return cls._build_response(mimetype=mimetype, data=response, extra_context=extra_context)
-
-    @classmethod
-    def get_connexion_response(cls, response, mimetype=None):
-        """ Cast framework dependent response to ConnexionResponse used for schema validation """
-        if isinstance(response, ConnexionResponse):
-            # If body in ConnexionResponse is not byte, it may not pass schema validation.
-            # In this case, rebuild response with aiohttp to have consistency
-            if response.body is None or isinstance(response.body, bytes):
-                return response
-            else:
-                response = cls._build_response(
-                    data=response.body,
-                    mimetype=mimetype,
-                    content_type=response.content_type,
-                    headers=response.headers,
-                    status_code=response.status_code
-                )
-
-        if not cls._is_framework_response(response):
-            response = cls._response_from_handler(response, mimetype)
-        return cls._framework_to_connexion_response(response=response, mimetype=mimetype)
-
-    @classmethod
-    @abc.abstractmethod
-    def _is_framework_response(cls, response):
-        """ Return True if `response` is a framework response class """
-
-    @classmethod
-    @abc.abstractmethod
-    def _framework_to_connexion_response(cls, response, mimetype):
-        """ Cast framework response class to ConnexionResponse used for schema validation """
-
-    @classmethod
-    @abc.abstractmethod
-    def _connexion_to_framework_response(cls, response, mimetype, extra_context=None):
-        """ Cast ConnexionResponse to framework response class """
-
-    @classmethod
-    @abc.abstractmethod
-    def _build_response(cls, data, mimetype, content_type=None, status_code=None, headers=None, extra_context=None):
-        """
-        Create a framework response from the provided arguments.
-        :param data: Body data.
-        :param content_type: The response mimetype.
-        :type content_type: str
-        :param content_type: The response status code.
-        :type status_code: int
-        :param headers: The response status code.
-        :type headers: Union[Iterable[Tuple[str, str]], Dict[str, str]]
-        :param extra_context: dict of extra details, like url, to include in logs
-        :type extra_context: Union[None, dict]
-        :return A framework response.
-        :rtype Response
-        """
-
-    @classmethod
-    def _prepare_body_and_status_code(cls, data, mimetype, status_code=None, extra_context=None):
-        if data is NoContent:
-            data = None
-
-        if status_code is None:
-            if data is None:
-                status_code = 204
-                mimetype = None
-            else:
-                status_code = 200
-        elif hasattr(status_code, "value"):
-            # If we got an enum instead of an int, extract the value.
-            status_code = status_code.value
-
-        if data is not None:
-            body, mimetype = cls._serialize_data(data, mimetype)
-        else:
-            body = data
-
-        if extra_context is None:
-            extra_context = {}
-        logger.debug('Prepared body and status code (%d)',
-                     status_code,
-                     extra={
-                         'body': body,
-                         **extra_context
-                     })
-
-        return body, status_code, mimetype
-
-    @classmethod
-    def _serialize_data(cls, data, mimetype):
-        # TODO: Harmonize with flask_api. Currently this is the backwards compatible with aiohttp_api._cast_body.
-        if not isinstance(data, bytes):
-            if isinstance(mimetype, str) and is_json_mimetype(mimetype):
-                body = cls.jsonifier.dumps(data)
-            elif isinstance(data, str):
-                body = data
-            else:
-                warnings.warn(
-                    "Implicit (aiohttp) serialization with str() will change in the next major version. "
-                    "This is triggered because a non-JSON response body is being stringified. "
-                    "This will be replaced by something that is mimetype-specific and may "
-                    "serialize some things as JSON or throw an error instead of silently "
-                    "stringifying unknown response bodies. "
-                    "Please make sure to specify media/mime types in your specs.",
-                    FutureWarning  # a Deprecation targeted at application users.
-                )
-                body = str(data)
-        else:
-            body = data
-        return body, mimetype
-
-    def json_loads(self, data):
-        return self.jsonifier.loads(data)
-
-    @classmethod
-    def _set_jsonifier(cls):
-        cls.jsonifier = Jsonifier()
diff --git a/airflow/_vendor/connexion/apis/aiohttp_api.py b/airflow/_vendor/connexion/apis/aiohttp_api.py
deleted file mode 100644
index 50cda94..0000000
--- a/airflow/_vendor/connexion/apis/aiohttp_api.py
+++ /dev/null
@@ -1,394 +0,0 @@
-import asyncio
-import logging
-import re
-import traceback
-from contextlib import suppress
-from http import HTTPStatus
-from urllib.parse import parse_qs
-
-import aiohttp_jinja2
-import jinja2
-from aiohttp import web
-from aiohttp.web_exceptions import HTTPNotFound, HTTPPermanentRedirect
-from aiohttp.web_middlewares import normalize_path_middleware
-from airflow._vendor.connexion.apis.abstract import AbstractAPI
-from airflow._vendor.connexion.exceptions import ProblemException
-from airflow._vendor.connexion.handlers import AuthErrorHandler
-from airflow._vendor.connexion.jsonifier import JSONEncoder, Jsonifier
-from airflow._vendor.connexion.lifecycle import ConnexionRequest, ConnexionResponse
-from airflow._vendor.connexion.problem import problem
-from airflow._vendor.connexion.utils import yamldumper
-from werkzeug.exceptions import HTTPException as werkzeug_HTTPException
-
-
-logger = logging.getLogger('connexion.apis.aiohttp_api')
-
-
-def _generic_problem(http_status: HTTPStatus, exc: Exception = None):
-    extra = None
-    if exc is not None:
-        loop = asyncio.get_event_loop()
-        if loop.get_debug():
-            tb = None
-            with suppress(Exception):
-                tb = traceback.format_exc()
-            if tb:
-                extra = {"traceback": tb}
-
-    return problem(
-        status=http_status.value,
-        title=http_status.phrase,
-        detail=http_status.description,
-        ext=extra,
-    )
-
-
-@web.middleware
-async def problems_middleware(request, handler):
-    try:
-        response = await handler(request)
-    except ProblemException as exc:
-        response = problem(status=exc.status, detail=exc.detail, title=exc.title,
-                           type=exc.type, instance=exc.instance, headers=exc.headers, ext=exc.ext)
-    except (werkzeug_HTTPException, _HttpNotFoundError) as exc:
-        response = problem(status=exc.code, title=exc.name, detail=exc.description)
-    except web.HTTPError as exc:
-        if exc.text == "{}: {}".format(exc.status, exc.reason):
-            detail = HTTPStatus(exc.status).description
-        else:
-            detail = exc.text
-        response = problem(status=exc.status, title=exc.reason, detail=detail)
-    except (
-        web.HTTPException,  # eg raised HTTPRedirection or HTTPSuccessful
-        asyncio.CancelledError,  # skipped in default web_protocol
-    ):
-        # leave this to default handling in aiohttp.web_protocol.RequestHandler.start()
-        raise
-    except asyncio.TimeoutError as exc:
-        # overrides 504 from aiohttp.web_protocol.RequestHandler.start()
-        logger.debug('Request handler timed out.', exc_info=exc)
-        response = _generic_problem(HTTPStatus.GATEWAY_TIMEOUT, exc)
-    except Exception as exc:
-        # overrides 500 from aiohttp.web_protocol.RequestHandler.start()
-        logger.exception('Error handling request', exc_info=exc)
-        response = _generic_problem(HTTPStatus.INTERNAL_SERVER_ERROR, exc)
-
-    if isinstance(response, ConnexionResponse):
-        response = await AioHttpApi.get_response(response)
-    return response
-
-
-class AioHttpApi(AbstractAPI):
-    def __init__(self, *args, **kwargs):
-        # NOTE we use HTTPPermanentRedirect (308) because
-        # clients sometimes turn POST requests into GET requests
-        # on 301, 302, or 303
-        # see https://tools.ietf.org/html/rfc7538
-        trailing_slash_redirect = normalize_path_middleware(
-            append_slash=True,
-            redirect_class=HTTPPermanentRedirect
-        )
-        self.subapp = web.Application(
-            middlewares=[
-                problems_middleware,
-                trailing_slash_redirect
-            ]
-        )
-        AbstractAPI.__init__(self, *args, **kwargs)
-
-        aiohttp_jinja2.setup(
-            self.subapp,
-            loader=jinja2.FileSystemLoader(
-                str(self.options.openapi_console_ui_from_dir)
-            )
-        )
-        middlewares = self.options.as_dict().get('middlewares', [])
-        self.subapp.middlewares.extend(middlewares)
-
-    def _set_base_path(self, base_path):
-        AbstractAPI._set_base_path(self, base_path)
-        self._api_name = AioHttpApi.normalize_string(self.base_path)
-
-    @staticmethod
-    def normalize_string(string):
-        return re.sub(r'[^a-zA-Z0-9]', '_', string.strip('/'))
-
-    def _base_path_for_prefix(self, request):
-        """
-        returns a modified basePath which includes the incoming request's
-        path prefix.
-        """
-        base_path = self.base_path
-        if not request.path.startswith(self.base_path):
-            prefix = request.path.split(self.base_path)[0]
-            base_path = prefix + base_path
-        return base_path
-
-    def _spec_for_prefix(self, request):
-        """
-        returns a spec with a modified basePath / servers block
-        which corresponds to the incoming request path.
-        This is needed when behind a path-altering reverse proxy.
-        """
-        base_path = self._base_path_for_prefix(request)
-        return self.specification.with_base_path(base_path).raw
-
-    def add_openapi_json(self):
-        """
-        Adds openapi json to {base_path}/openapi.json
-             (or {base_path}/swagger.json for swagger2)
-        """
-        logger.debug('Adding spec json: %s/%s', self.base_path,
-                     self.options.openapi_spec_path)
-        self.subapp.router.add_route(
-            'GET',
-            self.options.openapi_spec_path,
-            self._get_openapi_json
-        )
-
-    def add_openapi_yaml(self):
-        """
-        Adds openapi json to {base_path}/openapi.json
-             (or {base_path}/swagger.json for swagger2)
-        """
-        if not self.options.openapi_spec_path.endswith("json"):
-            return
-
-        openapi_spec_path_yaml = \
-            self.options.openapi_spec_path[:-len("json")] + "yaml"
-        logger.debug('Adding spec yaml: %s/%s', self.base_path,
-                     openapi_spec_path_yaml)
-        self.subapp.router.add_route(
-            'GET',
-            openapi_spec_path_yaml,
-            self._get_openapi_yaml
-        )
-
-    async def _get_openapi_json(self, request):
-        return web.Response(
-            status=200,
-            content_type='application/json',
-            body=self.jsonifier.dumps(self._spec_for_prefix(request))
-        )
-
-    async def _get_openapi_yaml(self, request):
-        return web.Response(
-            status=200,
-            content_type='text/yaml',
-            body=yamldumper(self._spec_for_prefix(request))
-        )
-
-    def add_swagger_ui(self):
-        """
-        Adds swagger ui to {base_path}/ui/
-        """
-        console_ui_path = self.options.openapi_console_ui_path.strip().rstrip('/')
-        logger.debug('Adding swagger-ui: %s%s/',
-                     self.base_path,
-                     console_ui_path)
-
-        for path in (
-            console_ui_path + '/',
-            console_ui_path + '/index.html',
-        ):
-            self.subapp.router.add_route(
-                'GET',
-                path,
-                self._get_swagger_ui_home
-            )
-
-        if self.options.openapi_console_ui_config is not None:
-            self.subapp.router.add_route(
-                'GET',
-                console_ui_path + '/swagger-ui-config.json',
-                self._get_swagger_ui_config
-            )
-
-        # we have to add an explicit redirect instead of relying on the
-        # normalize_path_middleware because we also serve static files
-        # from this dir (below)
-
-        async def redirect(request):
-            raise web.HTTPMovedPermanently(
-                location=self.base_path + console_ui_path + '/'
-            )
-
-        self.subapp.router.add_route(
-            'GET',
-            console_ui_path,
-            redirect
-        )
-
-        # this route will match and get a permission error when trying to
-        # serve index.html, so we add the redirect above.
-        self.subapp.router.add_static(
-            console_ui_path,
-            path=str(self.options.openapi_console_ui_from_dir),
-            name='swagger_ui_static'
-        )
-
-    @aiohttp_jinja2.template('index.j2')
-    async def _get_swagger_ui_home(self, req):
-        base_path = self._base_path_for_prefix(req)
-        template_variables = {
-            'openapi_spec_url': (base_path + self.options.openapi_spec_path)
-        }
-        if self.options.openapi_console_ui_config is not None:
-            template_variables['configUrl'] = 'swagger-ui-config.json'
-        return template_variables
-
-    async def _get_swagger_ui_config(self, req):
-        return web.Response(
-            status=200,
-            content_type='text/json',
-            body=self.jsonifier.dumps(self.options.openapi_console_ui_config)
-        )
-
-    def add_auth_on_not_found(self, security, security_definitions):
-        """
-        Adds a 404 error handler to authenticate and only expose the 404 status if the security validation pass.
-        """
-        logger.debug('Adding path not found authentication')
-        not_found_error = AuthErrorHandler(
-            self, _HttpNotFoundError(),
-            security=security,
-            security_definitions=security_definitions
-        )
-        endpoint_name = "{}_not_found".format(self._api_name)
-        self.subapp.router.add_route(
-            '*',
-            '/{not_found_path}',
-            not_found_error.function,
-            name=endpoint_name
-        )
-
-    def _add_operation_internal(self, method, path, operation):
-        method = method.upper()
-        operation_id = operation.operation_id or path
-
-        logger.debug('... Adding %s -> %s', method, operation_id,
-                     extra=vars(operation))
-
-        handler = operation.function
-        endpoint_name = '{}_{}_{}'.format(
-            self._api_name,
-            AioHttpApi.normalize_string(path),
-            method.lower()
-        )
-        self.subapp.router.add_route(
-            method, path, handler, name=endpoint_name
-        )
-
-        if not path.endswith('/'):
-            self.subapp.router.add_route(
-                method, path + '/', handler, name=endpoint_name + '_'
-            )
-
-    @classmethod
-    async def get_request(cls, req):
-        """Convert aiohttp request to connexion
-
-        :param req: instance of aiohttp.web.Request
-        :return: connexion request instance
-        :rtype: ConnexionRequest
-        """
-        url = str(req.url)
-        logger.debug('Getting data and status code',
-                     extra={'has_body': req.has_body, 'url': url})
-
-        query = parse_qs(req.rel_url.query_string)
-        headers = req.headers
-        body = None
-        if req.body_exists:
-            body = await req.read()
-
-        return ConnexionRequest(url=url,
-                                method=req.method.lower(),
-                                path_params=dict(req.match_info),
-                                query=query,
-                                headers=headers,
-                                body=body,
-                                json_getter=lambda: cls.jsonifier.loads(body),
-                                files={},
-                                context=req)
-
-    @classmethod
-    async def get_response(cls, response, mimetype=None, request=None):
-        """Get response.
-        This method is used in the lifecycle decorators
-
-        :type response: aiohttp.web.StreamResponse | (Any,) | (Any, int) | (Any, dict) | (Any, int, dict)
-        :rtype: aiohttp.web.Response
-        """
-        while asyncio.iscoroutine(response):
-            response = await response
-
-        url = str(request.url) if request else ''
-
-        return cls._get_response(response, mimetype=mimetype, extra_context={"url": url})
-
-    @classmethod
-    def _is_framework_response(cls, response):
-        """ Return True if `response` is a framework response class """
-        return isinstance(response, web.StreamResponse)
-
-    @classmethod
-    def _framework_to_connexion_response(cls, response, mimetype):
-        """ Cast framework response class to ConnexionResponse used for schema validation """
-        body = None
-        if hasattr(response, "body"):  # StreamResponse and FileResponse don't have body
-            body = response.body
-        return ConnexionResponse(
-            status_code=response.status,
-            mimetype=mimetype,
-            content_type=response.content_type,
-            headers=response.headers,
-            body=body
-        )
-
-    @classmethod
-    def _connexion_to_framework_response(cls, response, mimetype, extra_context=None):
-        """ Cast ConnexionResponse to framework response class """
-        return cls._build_response(
-            mimetype=response.mimetype or mimetype,
-            status_code=response.status_code,
-            content_type=response.content_type,
-            headers=response.headers,
-            data=response.body,
-            extra_context=extra_context,
-        )
-
-    @classmethod
-    def _build_response(cls, data, mimetype, content_type=None, headers=None, status_code=None, extra_context=None):
-        if cls._is_framework_response(data):
-            raise TypeError("Cannot return web.StreamResponse in tuple. Only raw data can be returned in tuple.")
-
-        data, status_code, serialized_mimetype = cls._prepare_body_and_status_code(data=data, mimetype=mimetype, status_code=status_code, extra_context=extra_context)
-
-        if isinstance(data, str):
-            text = data
-            body = None
-        else:
-            text = None
-            body = data
-
-        content_type = content_type or mimetype or serialized_mimetype
-        return web.Response(body=body, text=text, headers=headers, status=status_code, content_type=content_type)
-
-    @classmethod
-    def _set_jsonifier(cls):
-        cls.jsonifier = Jsonifier(cls=JSONEncoder)
-
-
-class _HttpNotFoundError(HTTPNotFound):
-    def __init__(self):
-        self.name = 'Not Found'
-        self.description = (
-            'The requested URL was not found on the server. '
-            'If you entered the URL manually please check your spelling and '
-            'try again.'
-        )
-        self.code = type(self).status_code
-        self.empty_body = True
-
-        HTTPNotFound.__init__(self, reason=self.name)
diff --git a/airflow/_vendor/connexion/apis/flask_api.py b/airflow/_vendor/connexion/apis/flask_api.py
deleted file mode 100644
index b292153..0000000
--- a/airflow/_vendor/connexion/apis/flask_api.py
+++ /dev/null
@@ -1,310 +0,0 @@
-import logging
-import warnings
-
-import flask
-import werkzeug.exceptions
-from airflow._vendor.connexion.apis import flask_utils
-from airflow._vendor.connexion.apis.abstract import AbstractAPI
-from airflow._vendor.connexion.handlers import AuthErrorHandler
-from airflow._vendor.connexion.jsonifier import Jsonifier
-from airflow._vendor.connexion.lifecycle import ConnexionRequest, ConnexionResponse
-from airflow._vendor.connexion.utils import is_json_mimetype, yamldumper
-from werkzeug.local import LocalProxy
-
-logger = logging.getLogger('connexion.apis.flask_api')
-
-
-class FlaskApi(AbstractAPI):
-
-    def _set_base_path(self, base_path):
-        super(FlaskApi, self)._set_base_path(base_path)
-        self._set_blueprint()
-
-    def _set_blueprint(self):
-        logger.debug('Creating API blueprint: %s', self.base_path)
-        endpoint = flask_utils.flaskify_endpoint(self.base_path)
-        self.blueprint = flask.Blueprint(endpoint, __name__, url_prefix=self.base_path,
-                                         template_folder=str(self.options.openapi_console_ui_from_dir))
-
-    def add_openapi_json(self):
-        """
-        Adds spec json to {base_path}/swagger.json
-        or {base_path}/openapi.json (for oas3)
-        """
-        logger.debug('Adding spec json: %s/%s', self.base_path,
-                     self.options.openapi_spec_path)
-        endpoint_name = "{name}_openapi_json".format(name=self.blueprint.name)
-
-        self.blueprint.add_url_rule(self.options.openapi_spec_path,
-                                    endpoint_name,
-                                    self._handlers.get_json_spec)
-
-    def add_openapi_yaml(self):
-        """
-        Adds spec yaml to {base_path}/swagger.yaml
-        or {base_path}/openapi.yaml (for oas3)
-        """
-        if not self.options.openapi_spec_path.endswith("json"):
-            return
-
-        openapi_spec_path_yaml = \
-            self.options.openapi_spec_path[:-len("json")] + "yaml"
-        logger.debug('Adding spec yaml: %s/%s', self.base_path,
-                     openapi_spec_path_yaml)
-        endpoint_name = "{name}_openapi_yaml".format(name=self.blueprint.name)
-        self.blueprint.add_url_rule(
-            openapi_spec_path_yaml,
-            endpoint_name,
-            self._handlers.get_yaml_spec
-        )
-
-    def add_swagger_ui(self):
-        """
-        Adds swagger ui to {base_path}/ui/
-        """
-        console_ui_path = self.options.openapi_console_ui_path.strip('/')
-        logger.debug('Adding swagger-ui: %s/%s/',
-                     self.base_path,
-                     console_ui_path)
-
-        if self.options.openapi_console_ui_config is not None:
-            config_endpoint_name = "{name}_swagger_ui_config".format(name=self.blueprint.name)
-            config_file_url = '/{console_ui_path}/swagger-ui-config.json'.format(
-                console_ui_path=console_ui_path)
-
-            self.blueprint.add_url_rule(config_file_url,
-                                        config_endpoint_name,
-                                        lambda: flask.jsonify(self.options.openapi_console_ui_config))
-
-        static_endpoint_name = "{name}_swagger_ui_static".format(name=self.blueprint.name)
-        static_files_url = '/{console_ui_path}/<path:filename>'.format(
-            console_ui_path=console_ui_path)
-
-        self.blueprint.add_url_rule(static_files_url,
-                                    static_endpoint_name,
-                                    self._handlers.console_ui_static_files)
-
-        index_endpoint_name = "{name}_swagger_ui_index".format(name=self.blueprint.name)
-        console_ui_url = '/{console_ui_path}/'.format(
-            console_ui_path=console_ui_path)
-
-        self.blueprint.add_url_rule(console_ui_url,
-                                    index_endpoint_name,
-                                    self._handlers.console_ui_home)
-
-    def add_auth_on_not_found(self, security, security_definitions):
-        """
-        Adds a 404 error handler to authenticate and only expose the 404 status if the security validation pass.
-        """
-        logger.debug('Adding path not found authentication')
-        not_found_error = AuthErrorHandler(self, werkzeug.exceptions.NotFound(), security=security,
-                                           security_definitions=security_definitions)
-        endpoint_name = "{name}_not_found".format(name=self.blueprint.name)
-        self.blueprint.add_url_rule('/<path:invalid_path>', endpoint_name, not_found_error.function)
-
-    def _add_operation_internal(self, method, path, operation):
-        operation_id = operation.operation_id
-        logger.debug('... Adding %s -> %s', method.upper(), operation_id,
-                     extra=vars(operation))
-
-        flask_path = flask_utils.flaskify_path(path, operation.get_path_parameter_types())
-        endpoint_name = flask_utils.flaskify_endpoint(operation.operation_id,
-                                                      operation.randomize_endpoint)
-        function = operation.function
-        self.blueprint.add_url_rule(flask_path, endpoint_name, function, methods=[method])
-
-    @property
-    def _handlers(self):
-        # type: () -> InternalHandlers
-        if not hasattr(self, '_internal_handlers'):
-            self._internal_handlers = InternalHandlers(self.base_path, self.options, self.specification)
-        return self._internal_handlers
-
-    @classmethod
-    def get_response(cls, response, mimetype=None, request=None):
-        """Gets ConnexionResponse instance for the operation handler
-        result. Status Code and Headers for response.  If only body
-        data is returned by the endpoint function, then the status
-        code will be set to 200 and no headers will be added.
-
-        If the returned object is a flask.Response then it will just
-        pass the information needed to recreate it.
-
-        :type response: flask.Response | (flask.Response,) | (flask.Response, int) | (flask.Response, dict) | (flask.Response, int, dict)
-        :rtype: ConnexionResponse
-        """
-        return cls._get_response(response, mimetype=mimetype, extra_context={"url": flask.request.url})
-
-    @classmethod
-    def _is_framework_response(cls, response):
-        """ Return True if provided response is a framework type """
-        return flask_utils.is_flask_response(response)
-
-    @classmethod
-    def _framework_to_connexion_response(cls, response, mimetype):
-        """ Cast framework response class to ConnexionResponse used for schema validation """
-        return ConnexionResponse(
-            status_code=response.status_code,
-            mimetype=response.mimetype,
-            content_type=response.content_type,
-            headers=response.headers,
-            body=response.get_data(),
-        )
-
-    @classmethod
-    def _connexion_to_framework_response(cls, response, mimetype, extra_context=None):
-        """ Cast ConnexionResponse to framework response class """
-        flask_response = cls._build_response(
-            mimetype=response.mimetype or mimetype,
-            content_type=response.content_type,
-            headers=response.headers,
-            status_code=response.status_code,
-            data=response.body,
-            extra_context=extra_context,
-            )
-
-        return flask_response
-
-    @classmethod
-    def _build_response(cls, mimetype, content_type=None, headers=None, status_code=None, data=None, extra_context=None):
-        if cls._is_framework_response(data):
-            return flask.current_app.make_response((data, status_code, headers))
-
-        data, status_code, serialized_mimetype = cls._prepare_body_and_status_code(data=data, mimetype=mimetype, status_code=status_code, extra_context=extra_context)
-
-        kwargs = {
-            'mimetype': mimetype or serialized_mimetype,
-            'content_type': content_type,
-            'headers': headers,
-            'response': data,
-            'status': status_code
-        }
-        kwargs = {k: v for k, v in kwargs.items() if v is not None}
-        return flask.current_app.response_class(**kwargs)
-
-    @classmethod
-    def _serialize_data(cls, data, mimetype):
-        # TODO: harmonize flask and aiohttp serialization when mimetype=None or mimetype is not JSON
-        #       (cases where it might not make sense to jsonify the data)
-        if (isinstance(mimetype, str) and is_json_mimetype(mimetype)):
-            body = cls.jsonifier.dumps(data)
-        elif not (isinstance(data, bytes) or isinstance(data, str)):
-            warnings.warn(
-                "Implicit (flask) JSON serialization will change in the next major version. "
-                "This is triggered because a response body is being serialized as JSON "
-                "even though the mimetype is not a JSON type. "
-                "This will be replaced by something that is mimetype-specific and may "
-                "raise an error instead of silently converting everything to JSON. "
-                "Please make sure to specify media/mime types in your specs.",
-                FutureWarning  # a Deprecation targeted at application users.
-            )
-            body = cls.jsonifier.dumps(data)
-        else:
-            body = data
-
-        return body, mimetype
-
-    @classmethod
-    def get_request(cls, *args, **params):
-        # type: (*Any, **Any) -> ConnexionRequest
-        """Gets ConnexionRequest instance for the operation handler
-        result. Status Code and Headers for response.  If only body
-        data is returned by the endpoint function, then the status
-        code will be set to 200 and no headers will be added.
-
-        If the returned object is a flask.Response then it will just
-        pass the information needed to recreate it.
-
-        :rtype: ConnexionRequest
-        """
-        context_dict = {}
-        setattr(flask._request_ctx_stack.top, 'connexion_context', context_dict)
-        flask_request = flask.request
-        request = ConnexionRequest(
-            flask_request.url,
-            flask_request.method,
-            headers=flask_request.headers,
-            form=flask_request.form,
-            query=flask_request.args,
-            body=flask_request.get_data(),
-            json_getter=lambda: flask_request.get_json(silent=True),
-            files=flask_request.files,
-            path_params=params,
-            context=context_dict
-        )
-        logger.debug('Getting data and status code',
-                     extra={
-                         'data': request.body,
-                         'data_type': type(request.body),
-                         'url': request.url
-                     })
-        return request
-
-    @classmethod
-    def _set_jsonifier(cls):
-        """
-        Use Flask specific JSON loader
-        """
-        cls.jsonifier = Jsonifier(flask.json, indent=2)
-
-
-def _get_context():
-    return getattr(flask._request_ctx_stack.top, 'connexion_context')
-
-
-context = LocalProxy(_get_context)
-
-
-class InternalHandlers(object):
-    """
-    Flask handlers for internally registered endpoints.
-    """
-
-    def __init__(self, base_path, options, specification):
-        self.base_path = base_path
-        self.options = options
-        self.specification = specification
-
-    def console_ui_home(self):
-        """
-        Home page of the OpenAPI Console UI.
-
-        :return:
-        """
-        openapi_json_route_name = "{blueprint}.{prefix}_openapi_json"
-        escaped = flask_utils.flaskify_endpoint(self.base_path)
-        openapi_json_route_name = openapi_json_route_name.format(
-            blueprint=escaped,
-            prefix=escaped
-        )
-        template_variables = {
-            'openapi_spec_url': flask.url_for(openapi_json_route_name)
-        }
-        if self.options.openapi_console_ui_config is not None:
-            template_variables['configUrl'] = 'swagger-ui-config.json'
-        return flask.render_template('index.j2', **template_variables)
-
-    def console_ui_static_files(self, filename):
-        """
-        Servers the static files for the OpenAPI Console UI.
-
-        :param filename: Requested file contents.
-        :return:
-        """
-        # convert PosixPath to str
-        static_dir = str(self.options.openapi_console_ui_from_dir)
-        return flask.send_from_directory(static_dir, filename)
-
-    def get_json_spec(self):
-        return flask.jsonify(self._spec_for_prefix())
-
-    def get_yaml_spec(self):
-        return yamldumper(self._spec_for_prefix()), 200, {"Content-Type": "text/yaml"}
-
-    def _spec_for_prefix(self):
-        """
-        Modify base_path in the spec based on incoming url
-        This fixes problems with reverse proxies changing the path.
-        """
-        base_path = flask.url_for(flask.request.endpoint).rsplit("/", 1)[0]
-        return self.specification.with_base_path(base_path).raw
diff --git a/airflow/_vendor/connexion/apis/flask_utils.py b/airflow/_vendor/connexion/apis/flask_utils.py
deleted file mode 100644
index 5d97268..0000000
--- a/airflow/_vendor/connexion/apis/flask_utils.py
+++ /dev/null
@@ -1,81 +0,0 @@
-import functools
-import random
-import re
-import string
-
-import flask
-import werkzeug.wrappers
-
-PATH_PARAMETER = re.compile(r'\{([^}]*)\}')
-
-# map Swagger type to flask path converter
-# see http://flask.pocoo.org/docs/0.10/api/#url-route-registrations
-PATH_PARAMETER_CONVERTERS = {
-    'integer': 'int',
-    'number': 'float',
-    'path': 'path'
-}
-
-
-def flaskify_endpoint(identifier, randomize=None):
-    """
-    Converts the provided identifier in a valid flask endpoint name
-
-    :type identifier: str
-    :param randomize: If specified, add this many random characters (upper case
-        and digits) to the endpoint name, separated by a pipe character.
-    :type randomize: int | None
-    :rtype: str
-    """
-    result = identifier.replace('.', '_')
-    if randomize is None:
-        return result
-
-    chars = string.ascii_uppercase + string.digits
-    return "{result}|{random_string}".format(
-        result=result,
-        random_string=''.join(random.SystemRandom().choice(chars) for _ in range(randomize)))
-
-
-def convert_path_parameter(match, types):
-    name = match.group(1)
-    swagger_type = types.get(name)
-    converter = PATH_PARAMETER_CONVERTERS.get(swagger_type)
-    return '<{0}{1}{2}>'.format(converter or '',
-                                ':' if converter else '',
-                                name.replace('-', '_'))
-
-
-def flaskify_path(swagger_path, types=None):
-    """
-    Convert swagger path templates to flask path templates
-
-    :type swagger_path: str
-    :type types: dict
-    :rtype: str
-
-    >>> flaskify_path('/foo-bar/{my-param}')
-    '/foo-bar/<my_param>'
-
-    >>> flaskify_path('/foo/{someint}', {'someint': 'int'})
-    '/foo/<int:someint>'
-    """
-    if types is None:
-        types = {}
-    convert_match = functools.partial(convert_path_parameter, types=types)
-    return PATH_PARAMETER.sub(convert_match, swagger_path)
-
-
-def is_flask_response(obj):
-    """
-    Verifies if obj is a default Flask response instance.
-
-    :type obj: object
-    :rtype bool
-
-    >>> is_flask_response(redirect('http://example.com/'))
-    True
-    >>> is_flask_response(flask.Response())
-    True
-    """
-    return isinstance(obj, flask.Response) or isinstance(obj, werkzeug.wrappers.Response)
diff --git a/airflow/_vendor/connexion/apps/__init__.py b/airflow/_vendor/connexion/apps/__init__.py
deleted file mode 100644
index 18ff24c..0000000
--- a/airflow/_vendor/connexion/apps/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from .abstract import AbstractApp  # NOQA
diff --git a/airflow/_vendor/connexion/apps/abstract.py b/airflow/_vendor/connexion/apps/abstract.py
deleted file mode 100644
index 60fb648..0000000
--- a/airflow/_vendor/connexion/apps/abstract.py
+++ /dev/null
@@ -1,249 +0,0 @@
-import abc
-import logging
-import pathlib
-
-from ..options import ConnexionOptions
-from ..resolver import Resolver
-
-logger = logging.getLogger('connexion.app')
-
-
-class AbstractApp(metaclass=abc.ABCMeta):
-    def __init__(self, import_name, api_cls, port=None, specification_dir='',
-                 host=None, server=None, server_args=None, arguments=None, auth_all_paths=False, debug=None,
-                 resolver=None, options=None, skip_error_handlers=False):
-        """
-        :param import_name: the name of the application package
-        :type import_name: str
-        :param host: the host interface to bind on.
-        :type host: str
-        :param port: port to listen to
-        :type port: int
-        :param specification_dir: directory where to look for specifications
-        :type specification_dir: pathlib.Path | str
-        :param server: which wsgi server to use
-        :type server: str | None
-        :param server_args: dictionary of arguments which are then passed to appropriate http server (Flask or aio_http)
-        :type server_args: dict | None
-        :param arguments: arguments to replace on the specification
-        :type arguments: dict | None
-        :param auth_all_paths: whether to authenticate not defined paths
-        :type auth_all_paths: bool
-        :param debug: include debugging information
-        :type debug: bool
-        :param resolver: Callable that maps operationID to a function
-        """
-        self.port = port
-        self.host = host
-        self.debug = debug
-        self.resolver = resolver
-        self.import_name = import_name
-        self.arguments = arguments or {}
-        self.api_cls = api_cls
-        self.resolver_error = None
-
-        # Options
-        self.auth_all_paths = auth_all_paths
-
-        self.options = ConnexionOptions(options)
-
-        self.server = server
-        self.server_args = dict() if server_args is None else server_args
-        self.app = self.create_app()
-
-        # we get our application root path to avoid duplicating logic
-        self.root_path = self.get_root_path()
-        logger.debug('Root Path: %s', self.root_path)
-
-        specification_dir = pathlib.Path(specification_dir)  # Ensure specification dir is a Path
-        if specification_dir.is_absolute():
-            self.specification_dir = specification_dir
-        else:
-            self.specification_dir = self.root_path / specification_dir
-
-        logger.debug('Specification directory: %s', self.specification_dir)
-
-        if not skip_error_handlers:
-            logger.debug('Setting error handlers')
-            self.set_errors_handlers()
-
-    @abc.abstractmethod
-    def create_app(self):
-        """
-        Creates the user framework application
-        """
-
-    @abc.abstractmethod
-    def get_root_path(self):
-        """
-        Gets the root path of the user framework application
-        """
-
-    @abc.abstractmethod
-    def set_errors_handlers(self):
-        """
-        Sets all errors handlers of the user framework application
-        """
-
-    def add_api(self, specification, base_path=None, arguments=None,
-                auth_all_paths=None, validate_responses=False,
-                strict_validation=False, resolver=None, resolver_error=None,
-                pythonic_params=False, pass_context_arg_name=None, options=None,
-                validator_map=None):
-        """
-        Adds an API to the application based on a swagger file or API dict
-
-        :param specification: swagger file with the specification | specification dict
-        :type specification: pathlib.Path or str or dict
-        :param base_path: base path where to add this api
-        :type base_path: str | None
-        :param arguments: api version specific arguments to replace on the specification
-        :type arguments: dict | None
-        :param auth_all_paths: whether to authenticate not defined paths
-        :type auth_all_paths: bool
-        :param validate_responses: True enables validation. Validation errors generate HTTP 500 responses.
-        :type validate_responses: bool
-        :param strict_validation: True enables validation on invalid request parameters
-        :type strict_validation: bool
-        :param resolver: Operation resolver.
-        :type resolver: Resolver | types.FunctionType
-        :param resolver_error: If specified, turns ResolverError into error
-            responses with the given status code.
-        :type resolver_error: int | None
-        :param pythonic_params: When True CamelCase parameters are converted to snake_case
-        :type pythonic_params: bool
-        :param options: New style options dictionary.
-        :type options: dict | None
-        :param pass_context_arg_name: Name of argument in handler functions to pass request context to.
-        :type pass_context_arg_name: str | None
-        :param validator_map: map of validators
-        :type validator_map: dict
-        :rtype: AbstractAPI
-        """
-        # Turn the resolver_error code into a handler object
-        self.resolver_error = resolver_error
-        resolver_error_handler = None
-        if self.resolver_error is not None:
-            resolver_error_handler = self._resolver_error_handler
-
-        resolver = resolver or self.resolver
-        resolver = Resolver(resolver) if hasattr(resolver, '__call__') else resolver
-
-        auth_all_paths = auth_all_paths if auth_all_paths is not None else self.auth_all_paths
-        # TODO test if base_path starts with an / (if not none)
-        arguments = arguments or dict()
-        arguments = dict(self.arguments, **arguments)  # copy global arguments and update with api specfic
-
-        if isinstance(specification, dict):
-            specification = specification
-        else:
-            specification = self.specification_dir / specification
-
-        api_options = self.options.extend(options)
-
-        api = self.api_cls(specification,
-                           base_path=base_path,
-                           arguments=arguments,
-                           resolver=resolver,
-                           resolver_error_handler=resolver_error_handler,
-                           validate_responses=validate_responses,
-                           strict_validation=strict_validation,
-                           auth_all_paths=auth_all_paths,
-                           debug=self.debug,
-                           validator_map=validator_map,
-                           pythonic_params=pythonic_params,
-                           pass_context_arg_name=pass_context_arg_name,
-                           options=api_options.as_dict())
-        return api
-
-    def _resolver_error_handler(self, *args, **kwargs):
-        from airflow._vendor.connexion.handlers import ResolverErrorHandler
-        return ResolverErrorHandler(self.api_cls, self.resolver_error, *args, **kwargs)
-
-    def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
-        """
-        Connects a URL rule.  Works exactly like the `route` decorator.  If a view_func is provided it will be
-        registered with the endpoint.
-
-        Basically this example::
-
-            @app.route('/')
-            def index():
-                pass
-
-        Is equivalent to the following::
-
-            def index():
-                pass
-            app.add_url_rule('/', 'index', index)
-
-        If the view_func is not provided you will need to connect the endpoint to a view function like so::
-
-            app.view_functions['index'] = index
-
-        Internally`route` invokes `add_url_rule` so if you want to customize the behavior via subclassing you only need
-        to change this method.
-
-        :param rule: the URL rule as string
-        :type rule: str
-        :param endpoint: the endpoint for the registered URL rule. Flask itself assumes the name of the view function as
-                         endpoint
-        :type endpoint: str
-        :param view_func: the function to call when serving a request to the provided endpoint
-        :type view_func: types.FunctionType
-        :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`).
-        """
-        log_details = {'endpoint': endpoint, 'view_func': view_func.__name__}
-        log_details.update(options)
-        logger.debug('Adding %s', rule, extra=log_details)
-        self.app.add_url_rule(rule, endpoint, view_func, **options)
-
-    def route(self, rule, **options):
-        """
-        A decorator that is used to register a view function for a
-        given URL rule.  This does the same thing as `add_url_rule`
-        but is intended for decorator usage::
-
-            @app.route('/')
-            def index():
-                return 'Hello World'
-
-        :param rule: the URL rule as string
-        :type rule: str
-        :param endpoint: the endpoint for the registered URL rule.  Flask
-                         itself assumes the name of the view function as
-                         endpoint
-        :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`).
-        """
-        logger.debug('Adding %s with decorator', rule, extra=options)
-        return self.app.route(rule, **options)
-
-    @abc.abstractmethod
-    def run(self, port=None, server=None, debug=None, host=None, **options):  # pragma: no cover
-        """
-        Runs the application on a local development server.
-        :param host: the host interface to bind on.
-        :type host: str
-        :param port: port to listen to
-        :type port: int
-        :param server: which wsgi server to use
-        :type server: str | None
-        :param debug: include debugging information
-        :type debug: bool
-        :param options: options to be forwarded to the underlying server
-        """
-
-    def __call__(self, environ, start_response):  # pragma: no cover
-        """
-        Makes the class callable to be WSGI-compliant. As Flask is used to handle requests,
-        this is a passthrough-call to the Flask callable class.
-        This is an abstraction to avoid directly referencing the app attribute from outside the
-        class and protect it from unwanted modification.
-        """
-        return self.app(environ, start_response)
diff --git a/airflow/_vendor/connexion/apps/aiohttp_app.py b/airflow/_vendor/connexion/apps/aiohttp_app.py
deleted file mode 100644
index 1e3dba8..0000000
--- a/airflow/_vendor/connexion/apps/aiohttp_app.py
+++ /dev/null
@@ -1,95 +0,0 @@
-import logging
-import os.path
-import pkgutil
-import sys
-
-from aiohttp import web
-
-from ..apis.aiohttp_api import AioHttpApi
-from ..exceptions import ConnexionException
-from .abstract import AbstractApp
-
-logger = logging.getLogger('connexion.aiohttp_app')
-
-
-class AioHttpApp(AbstractApp):
-
-    def __init__(self, import_name, only_one_api=False, **kwargs):
-        super(AioHttpApp, self).__init__(import_name, AioHttpApi, server='aiohttp', **kwargs)
-        self._only_one_api = only_one_api
-        self._api_added = False
-
-    def create_app(self):
-        return web.Application(**self.server_args)
-
-    def get_root_path(self):
-        mod = sys.modules.get(self.import_name)
-        if mod is not None and hasattr(mod, '__file__'):
-            return os.path.dirname(os.path.abspath(mod.__file__))
-
-        loader = pkgutil.get_loader(self.import_name)
-        filepath = None
-
-        if hasattr(loader, 'get_filename'):
-            filepath = loader.get_filename(self.import_name)
-
-        if filepath is None:
-            raise RuntimeError("Invalid import name '{}'".format(self.import_name))
-
-        return os.path.dirname(os.path.abspath(filepath))
-
-    def set_errors_handlers(self):
-        pass
-
-    def add_api(self, specification, **kwargs):
-        if self._only_one_api:
-            if self._api_added:
-                raise ConnexionException(
-                    "an api was already added, "
-                    "create a new app with 'only_one_api=False' "
-                    "to add more than one api"
-                )
-            else:
-                self.app = self._get_api(specification, kwargs).subapp
-                self._api_added = True
-                return self.app
-
-        api = self._get_api(specification, kwargs)
-        try:
-            self.app.add_subapp(api.base_path, api.subapp)
-        except ValueError:
-            raise ConnexionException(
-                "aiohttp doesn't allow to set empty base_path ('/'), "
-                "use non-empty instead, e.g /api"
-            )
-
-        return api
-
-    def _get_api(self, specification, kwargs):
-        return super(AioHttpApp, self).add_api(specification, **kwargs)
-
-    def run(self, port=None, server=None, debug=None, host=None, **options):
-        if port is not None:
-            self.port = port
-        elif self.port is None:
-            self.port = 5000
-
-        self.server = server or self.server
-        self.host = host or self.host or '0.0.0.0'
-
-        if debug is not None:
-            self.debug = debug
-
-        logger.debug('Starting %s HTTP server..', self.server, extra=vars(self))
-
-        if self.server == 'aiohttp':
-            logger.info('Listening on %s:%s..', self.host, self.port)
-
-            access_log = options.pop('access_log', None)
-
-            if options.pop('use_default_access_log', None):
-                access_log = logger
-
-            web.run_app(self.app, port=self.port, host=self.host, access_log=access_log, **options)
-        else:
-            raise Exception('Server {} not recognized'.format(self.server))
diff --git a/airflow/_vendor/connexion/apps/flask_app.py b/airflow/_vendor/connexion/apps/flask_app.py
deleted file mode 100644
index 2ae02e1..0000000
--- a/airflow/_vendor/connexion/apps/flask_app.py
+++ /dev/null
@@ -1,138 +0,0 @@
-import datetime
-import logging
-import pathlib
-from decimal import Decimal
-from types import FunctionType  # NOQA
-
-import flask
-import werkzeug.exceptions
-from flask import json
-
-from ..apis.flask_api import FlaskApi
-from ..exceptions import ProblemException
-from ..problem import problem
-from .abstract import AbstractApp
-
-logger = logging.getLogger('connexion.app')
-
-
-class FlaskApp(AbstractApp):
-    def __init__(self, import_name, server='flask', **kwargs):
-        super(FlaskApp, self).__init__(import_name, FlaskApi, server=server, **kwargs)
-
-    def create_app(self):
-        app = flask.Flask(self.import_name, **self.server_args)
-        app.json_encoder = FlaskJSONEncoder
-        return app
-
-    def get_root_path(self):
-        return pathlib.Path(self.app.root_path)
-
-    def set_errors_handlers(self):
-        for error_code in werkzeug.exceptions.default_exceptions:
-            self.add_error_handler(error_code, self.common_error_handler)
-
-        self.add_error_handler(ProblemException, self.common_error_handler)
-
-    @staticmethod
-    def common_error_handler(exception):
-        """
-        :type exception: Exception
-        """
-        if isinstance(exception, ProblemException):
-            response = problem(
-                status=exception.status, title=exception.title, detail=exception.detail,
-                type=exception.type, instance=exception.instance, headers=exception.headers,
-                ext=exception.ext)
-        else:
-            if not isinstance(exception, werkzeug.exceptions.HTTPException):
-                exception = werkzeug.exceptions.InternalServerError()
-
-            response = problem(title=exception.name, detail=exception.description,
-                               status=exception.code)
-
-        return FlaskApi.get_response(response)
-
-    def add_api(self, specification, **kwargs):
-        api = super(FlaskApp, self).add_api(specification, **kwargs)
-        self.app.register_blueprint(api.blueprint)
-        return api
-
-    def add_error_handler(self, error_code, function):
-        # type: (int, FunctionType) -> None
-        self.app.register_error_handler(error_code, function)
-
-    def run(self, port=None, server=None, debug=None, host=None, **options):  # pragma: no cover
-        """
-        Runs the application on a local development server.
-        :param host: the host interface to bind on.
-        :type host: str
-        :param port: port to listen to
-        :type port: int
-        :param server: which wsgi server to use
-        :type server: str | None
-        :param debug: include debugging information
-        :type debug: bool
-        :param options: options to be forwarded to the underlying server
-        """
-        # this functions is not covered in unit tests because we would effectively testing the mocks
-
-        # overwrite constructor parameter
-        if port is not None:
-            self.port = port
-        elif self.port is None:
-            self.port = 5000
-
-        self.host = host or self.host or '0.0.0.0'
-
-        if server is not None:
-            self.server = server
-
-        if debug is not None:
-            self.debug = debug
-
-        logger.debug('Starting %s HTTP server..', self.server, extra=vars(self))
-        if self.server == 'flask':
-            self.app.run(self.host, port=self.port, debug=self.debug, **options)
-        elif self.server == 'tornado':
-            try:
-                import tornado.wsgi
-                import tornado.httpserver
-                import tornado.ioloop
-            except ImportError:
-                raise Exception('tornado library not installed')
-            wsgi_container = tornado.wsgi.WSGIContainer(self.app)
-            http_server = tornado.httpserver.HTTPServer(wsgi_container, **options)
-            http_server.listen(self.port, address=self.host)
-            logger.info('Listening on %s:%s..', self.host, self.port)
-            tornado.ioloop.IOLoop.instance().start()
-        elif self.server == 'gevent':
-            try:
-                import gevent.pywsgi
-            except ImportError:
-                raise Exception('gevent library not installed')
-            http_server = gevent.pywsgi.WSGIServer((self.host, self.port), self.app, **options)
-            logger.info('Listening on %s:%s..', self.host, self.port)
-            http_server.serve_forever()
-        else:
-            raise Exception('Server {} not recognized'.format(self.server))
-
-
-class FlaskJSONEncoder(json.JSONEncoder):
-    def default(self, o):
-        if isinstance(o, datetime.datetime):
-            if o.tzinfo:
-                # eg: '2015-09-25T23:14:42.588601+00:00'
-                return o.isoformat('T')
-            else:
-                # No timezone present - assume UTC.
-                # eg: '2015-09-25T23:14:42.588601Z'
-                return o.isoformat('T') + 'Z'
-
-        if isinstance(o, datetime.date):
-            return o.isoformat()
-
-        if isinstance(o, Decimal):
-            return float(o)
-
-        return json.JSONEncoder.default(self, o)
diff --git a/airflow/_vendor/connexion/cli.py b/airflow/_vendor/connexion/cli.py
deleted file mode 100644
index edb37ef..0000000
--- a/airflow/_vendor/connexion/cli.py
+++ /dev/null
@@ -1,210 +0,0 @@
-import logging
-import sys
-from os import path
-
-import click
-import airflow._vendor.connexion as connexion
-from clickclick import AliasedGroup, fatal_error
-from airflow._vendor.connexion.mock import MockResolver
-
-logger = logging.getLogger('connexion.cli')
-CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
-FLASK_APP = 'flask'
-AIOHTTP_APP = 'aiohttp'
-AVAILABLE_SERVERS = {
-    'flask': [FLASK_APP],
-    'gevent': [FLASK_APP],
-    'tornado': [FLASK_APP],
-    'aiohttp': [AIOHTTP_APP]
-}
-AVAILABLE_APPS = {
-    FLASK_APP: 'connexion.apps.flask_app.FlaskApp',
-    AIOHTTP_APP: 'connexion.apps.aiohttp_app.AioHttpApp'
-}
-DEFAULT_SERVERS = {
-    FLASK_APP: FLASK_APP,
-    AIOHTTP_APP: AIOHTTP_APP
-}
-
-
-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
-
-
-def print_version(ctx, param, value):
-    if not value or ctx.resilient_parsing:
-        return
-    click.echo('Connexion {}'.format(connexion.__version__))
-    ctx.exit()
-
-
-@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS)
-@click.option('-V', '--version', is_flag=True, callback=print_version, expose_value=False, is_eager=True,
-              help='Print the current version number and exit.')
-def main():
-    pass
-
-
-@main.command()
-@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(AVAILABLE_SERVERS.keys()),
-              callback=validate_server_requirements,
-              help='Which WSGI server container to use. (deprecated, use --server instead)')
-@click.option('--server', '-s',
-              type=click.Choice(AVAILABLE_SERVERS.keys()),
-              callback=validate_server_requirements,
-              help='Which server container to use.')
-@click.option('--stub',
-              help='Returns status code 501, and `Not Implemented Yet` payload, for '
-              'the endpoints which handlers are not found.',
-              is_flag=True, default=False)
-@click.option('--mock', type=click.Choice(['all', 'notimplemented']),
-              help='Returns example data for all endpoints or for which handlers are not found.')
-@click.option('--hide-spec',
-              help='Hides the API spec in JSON format which is by default available at `/swagger.json`.',
-              is_flag=True, default=False)
-@click.option('--hide-console-ui',
-              help='Hides the the API console UI which is by default available at `/ui`.',
-              is_flag=True, default=False)
-@click.option('--console-ui-url', metavar='URL',
-              help='Personalize what URL path the API console UI will be mounted.')
-@click.option('--console-ui-from', metavar='PATH',
-              help='Path to a customized API console UI dashboard.')
-@click.option('--auth-all-paths',
-              help='Enable authentication to paths not defined in the spec.',
-              is_flag=True, default=False)
-@click.option('--validate-responses',
-              help='Enable validation of response values from operation handlers.',
-              is_flag=True, default=False)
-@click.option('--strict-validation',
-              help='Enable strict validation of request payloads.',
-              is_flag=True, default=False)
-@click.option('--debug', '-d', help='Show debugging information.',
-              is_flag=True, default=False)
-@click.option('--verbose', '-v', help='Show verbose information.', count=True)
-@click.option('--base-path', metavar='PATH',
-              help='Override the basePath in the API spec.')
-@click.option('--app-framework', '-f', default=FLASK_APP,
-              type=click.Choice(AVAILABLE_APPS.keys()),
-              help='The app framework used to run the server')
-def run(spec_file,
-        base_module_path,
-        port,
-        host,
-        wsgi_server,
-        server,
-        stub,
-        mock,
-        hide_spec,
-        hide_console_ui,
-        console_ui_url,
-        console_ui_from,
-        auth_all_paths,
-        validate_responses,
-        strict_validation,
-        debug,
-        verbose,
-        base_path,
-        app_framework):
-    """
-    Runs a server compliant with a OpenAPI/Swagger 2.0 Specification file.
-
-    Arguments:
-
-    - SPEC_FILE: specification file that describes the server endpoints.
-
-    - 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)
-
-    if app_framework == AIOHTTP_APP:
-        try:
-            import aiohttp  # NOQA
-        except Exception:
-            fatal_error('aiohttp library is not installed')
-
-    logging_level = logging.WARN
-    if verbose > 0:
-        logging_level = logging.INFO
-
-    if debug or verbose > 1:
-        logging_level = logging.DEBUG
-        debug = True
-
-    logging.basicConfig(level=logging_level)
-
-    spec_file_full_path = path.abspath(spec_file)
-    py_module_path = base_module_path or path.dirname(spec_file_full_path)
-    sys.path.insert(1, path.abspath(py_module_path))
-    logger.debug('Added {} to system path.'.format(py_module_path))
-
-    resolver_error = None
-    if stub:
-        resolver_error = 501
-
-    api_extra_args = {}
-    if mock:
-        resolver = MockResolver(mock_all=mock == 'all')
-        api_extra_args['resolver'] = resolver
-
-    app_cls = connexion.utils.get_function_from_name(
-      AVAILABLE_APPS[app_framework]
-    )
-
-    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__,
-                  debug=debug,
-                  auth_all_paths=auth_all_paths,
-                  options=options)
-
-    app.add_api(spec_file_full_path,
-                base_path=base_path,
-                resolver_error=resolver_error,
-                validate_responses=validate_responses,
-                strict_validation=strict_validation,
-                **api_extra_args)
-
-    app.run(port=port,
-            host=host,
-            server=server,
-            debug=debug)
-
-
-if __name__ == '__main__':  # pragma: no cover
-    main()
diff --git a/airflow/_vendor/connexion/decorators/__init__.py b/airflow/_vendor/connexion/decorators/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/airflow/_vendor/connexion/decorators/coroutine_wrappers.py b/airflow/_vendor/connexion/decorators/coroutine_wrappers.py
deleted file mode 100644
index 9b58d3e..0000000
--- a/airflow/_vendor/connexion/decorators/coroutine_wrappers.py
+++ /dev/null
@@ -1,53 +0,0 @@
-import asyncio
-import functools
-
-
-def get_request_life_cycle_wrapper(function, api, mimetype):
-    """
-    It is a wrapper used on `RequestResponseDecorator` class.
-    This function is located in an extra module because python2.7 don't
-    support the 'yield from' syntax. This function is used to await
-    the coroutines to connexion does the proper validation of parameters
-    and responses.
-
-    :rtype asyncio.coroutine
-    """
-    @functools.wraps(function)
-    def wrapper(*args, **kwargs):
-        connexion_request = api.get_request(*args, **kwargs)
-        while asyncio.iscoroutine(connexion_request):
-            connexion_request = yield from connexion_request
-
-        connexion_response = function(connexion_request)
-        while asyncio.iscoroutine(connexion_response):
-            connexion_response = yield from connexion_response
-
-        framework_response = api.get_response(connexion_response, mimetype,
-                                              connexion_request)
-        while asyncio.iscoroutine(framework_response):
-            framework_response = yield from framework_response
-
-        return framework_response
-
-    return asyncio.coroutine(wrapper)
-
-
-def get_response_validator_wrapper(function, _wrapper):
-    """
-    It is a wrapper used on `ResponseValidator` class.
-    This function is located in an extra module because python2.7 don't
-    support the 'yield from' syntax. This function is used to await
-    the coroutines to connexion does the proper validation of parameters
-    and responses.
-
-    :rtype asyncio.coroutine
-    """
-    @functools.wraps(function)
-    def wrapper(request):
-        response = function(request)
-        while asyncio.iscoroutine(response):
-            response = yield from response
-
-        return _wrapper(request, response)
-
-    return asyncio.coroutine(wrapper)
diff --git a/airflow/_vendor/connexion/decorators/decorator.py b/airflow/_vendor/connexion/decorators/decorator.py
deleted file mode 100644
index aa26adc..0000000
--- a/airflow/_vendor/connexion/decorators/decorator.py
+++ /dev/null
@@ -1,51 +0,0 @@
-import functools
-import logging
-
-from ..utils import has_coroutine
-
-logger = logging.getLogger('connexion.decorators.decorator')
-
-
-class BaseDecorator(object):
-
-    def __call__(self, function):
-        """
-        :type function: types.FunctionType
-        :rtype: types.FunctionType
-        """
-        return function
-
-    def __repr__(self):  # pragma: no cover
-        """
-        :rtype: str
-        """
-        return '<BaseDecorator>'
-
-
-class RequestResponseDecorator(BaseDecorator):
-    """Manages the lifecycle of the request internally in Connexion.
-    Filter the ConnexionRequest instance to return the corresponding
-    framework specific object.
-    """
-
-    def __init__(self, api, mimetype):
-        self.api = api
-        self.mimetype = mimetype
-
-    def __call__(self, function):
-        """
-        :type function: types.FunctionType
-        :rtype: types.FunctionType
-        """
-        if has_coroutine(function, self.api):
-            from .coroutine_wrappers import get_request_life_cycle_wrapper
-            wrapper = get_request_life_cycle_wrapper(function, self.api, self.mimetype)
-
-        else:  # pragma: 3 no cover
-            @functools.wraps(function)
-            def wrapper(*args, **kwargs):
-                request = self.api.get_request(*args, **kwargs)
-                response = function(request)
-                return self.api.get_response(response, self.mimetype, request)
-
-        return wrapper
diff --git a/airflow/_vendor/connexion/decorators/metrics.py b/airflow/_vendor/connexion/decorators/metrics.py
deleted file mode 100644
index 8977a6d..0000000
--- a/airflow/_vendor/connexion/decorators/metrics.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import functools
-import os
-import time
-
-from werkzeug.exceptions import HTTPException
-from airflow._vendor.connexion.exceptions import ProblemException
-try:
-    import uwsgi_metrics
-    HAS_UWSGI_METRICS = True  # pragma: no cover
-except ImportError:
-    uwsgi_metrics = None
-    HAS_UWSGI_METRICS = False
-
-
-class UWSGIMetricsCollector(object):
-    def __init__(self, path, method):
-        self.path = path
-        self.method = method
-        swagger_path = path.strip('/').replace('/', '.').replace('<', '{').replace('>', '}')
-        self.key_suffix = '{method}.{path}'.format(path=swagger_path, method=method.upper())
-        self.prefix = os.getenv('HTTP_METRICS_PREFIX', 'connexion.response')
-
-    @staticmethod
-    def is_available():
-        return HAS_UWSGI_METRICS
-
-    def __call__(self, function):
-        """
-        :type function: types.FunctionType
-        :rtype: types.FunctionType
-        """
-
-        @functools.wraps(function)
-        def wrapper(*args, **kwargs):
-            status = 500
-            start_time_s = time.time()
-            try:
-                response = function(*args, **kwargs)
-                status = response.status_code
-            except HTTPException as http_e:
-                status = http_e.code
-                raise http_e
-            except ProblemException as prob_e:
-                status = prob_e.status
-                raise prob_e
-            finally:
-                end_time_s = time.time()
-                delta_s = end_time_s - start_time_s
-                delta_ms = delta_s * 1000
-                key = '{status}.{suffix}'.format(status=status, suffix=self.key_suffix)
-                uwsgi_metrics.timer(self.prefix, key, delta_ms)
-            return response
-
-        return wrapper
diff --git a/airflow/_vendor/connexion/decorators/parameter.py b/airflow/_vendor/connexion/decorators/parameter.py
deleted file mode 100644
index 0a9aa78..0000000
--- a/airflow/_vendor/connexion/decorators/parameter.py
+++ /dev/null
@@ -1,123 +0,0 @@
-import functools
-import inspect
-import logging
-import re
-
-import inflection
-
-from ..http_facts import FORM_CONTENT_TYPES
-from ..lifecycle import ConnexionRequest  # NOQA
-from ..utils import all_json
-
-try:
-    import builtins
-except ImportError:  # pragma: no cover
-    import __builtin__ as builtins
-
-
-logger = logging.getLogger(__name__)
-
-# Python 2/3 compatibility:
-try:
-    py_string = unicode
-except NameError:  # pragma: no cover
-    py_string = str  # pragma: no cover
-
-
-def inspect_function_arguments(function):  # pragma: no cover
-    """
-    Returns the list of variables names of a function and if it
-    accepts keyword arguments.
-
-    :type function: Callable
-    :rtype: tuple[list[str], bool]
-    """
-    parameters = inspect.signature(function).parameters
-    bound_arguments = [name for name, p in parameters.items()
-                       if p.kind not in (p.VAR_POSITIONAL, p.VAR_KEYWORD)]
-    has_kwargs = any(p.kind == p.VAR_KEYWORD for p in parameters.values())
-    return list(bound_arguments), has_kwargs
-
-
-def snake_and_shadow(name):
-    """
-    Converts the given name into Pythonic form. Firstly it converts CamelCase names to snake_case. Secondly it looks to
-    see if the name matches a known built-in and if it does it appends an underscore to the name.
-    :param name: The parameter name
-    :type name: str
-    :return:
-    """
-    snake = inflection.underscore(name)
-    if snake in builtins.__dict__.keys():
-        return "{}_".format(snake)
-    return snake
-
-
-def parameter_to_arg(operation, function, pythonic_params=False,
-                     pass_context_arg_name=None):
-    """
-    Pass query and body parameters as keyword arguments to handler function.
-
-    See (https://github.com/zalando/connexion/issues/59)
-    :param operation: The operation being called
-    :type operation: connexion.operations.AbstractOperation
-    :param pythonic_params: When True CamelCase parameters are converted to snake_case and an underscore is appended to
-    any shadowed built-ins
-    :type pythonic_params: bool
-    :param pass_context_arg_name: If not None URL and function has an argument matching this name, the framework's
-    request context will be passed as that argument.
-    :type pass_context_arg_name: str|None
-    """
-    consumes = operation.consumes
-
-    def sanitized(name):
-        return name and re.sub('^[^a-zA-Z_]+', '', re.sub('[^0-9a-zA-Z_]', '', name))
-
-    def pythonic(name):
-        name = name and snake_and_shadow(name)
-        return sanitized(name)
-
-    sanitize = pythonic if pythonic_params else sanitized
-    arguments, has_kwargs = inspect_function_arguments(function)
-
-    @functools.wraps(function)
-    def wrapper(request):
-        # type: (ConnexionRequest) -> Any
-        logger.debug('Function Arguments: %s', arguments)
-        kwargs = {}
-
-        if all_json(consumes):
-            request_body = request.json
-        elif consumes[0] in FORM_CONTENT_TYPES:
-            request_body = {sanitize(k): v for k, v in request.form.items()}
-        else:
-            request_body = request.body
-
-        try:
-            query = request.query.to_dict(flat=False)
-        except AttributeError:
-            query = dict(request.query.items())
-
-        kwargs.update(
-            operation.get_arguments(request.path_params, query, request_body,
-                                    request.files, arguments, has_kwargs, sanitize)
-        )
-
-        # optionally convert parameter variable names to un-shadowed, snake_case form
-        if pythonic_params:
-            kwargs = {snake_and_shadow(k): v for k, v in kwargs.items()}
-
-        # add context info (e.g. from security decorator)
-        for key, value in request.context.items():
-            if has_kwargs or key in arguments:
-                kwargs[key] = value
-            else:
-                logger.debug("Context parameter '%s' not in function arguments", key)
-
-        # attempt to provide the request context to the function
-        if pass_context_arg_name and (has_kwargs or pass_context_arg_name in arguments):
-            kwargs[pass_context_arg_name] = request.context
-
-        return function(**kwargs)
-
-    return wrapper
diff --git a/airflow/_vendor/connexion/decorators/produces.py b/airflow/_vendor/connexion/decorators/produces.py
deleted file mode 100644
index b105d88..0000000
--- a/airflow/_vendor/connexion/decorators/produces.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Decorators to change the return type of endpoints
-import functools
-import logging
-
-from .decorator import BaseDecorator
-
-logger = logging.getLogger('connexion.decorators.produces')
-
-# special marker object to return empty content for any status code
-# e.g. in app method do "return NoContent, 201"
-NoContent = object()
-
-
-class BaseSerializer(BaseDecorator):
-    def __init__(self, mimetype='text/plain'):
-        """
-        :type mimetype: str
-        """
-        self.mimetype = mimetype
-
-    def __repr__(self):
-        """
-        :rtype: str
-        """
-        return '<BaseSerializer: {}>'.format(self.mimetype)  # pragma: no cover
-
-
-class Produces(BaseSerializer):
-    def __call__(self, function):
-        """
-        :type function: types.FunctionType
-        :rtype: types.FunctionType
-        """
-
-        @functools.wraps(function)
-        def wrapper(request):
-            url = request.url
-            response = function(request)
-            logger.debug('Returning %s', url,
-                         extra={'url': url, 'mimetype': self.mimetype})
-            return response
-
-        return wrapper
-
-    def __repr__(self):
-        """
-        :rtype: str
-        """
-        return '<Produces: {}>'.format(self.mimetype)  # pragma: no cover
diff --git a/airflow/_vendor/connexion/decorators/response.py b/airflow/_vendor/connexion/decorators/response.py
deleted file mode 100644
index cb0285a..0000000
--- a/airflow/_vendor/connexion/decorators/response.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# Decorators to change the return type of endpoints
-import functools
-import logging
-
-from jsonschema import ValidationError
-
-from ..exceptions import (NonConformingResponseBody,
-                          NonConformingResponseHeaders)
-from ..utils import all_json, has_coroutine
-from .decorator import BaseDecorator
-from .validation import ResponseBodyValidator
-
-logger = logging.getLogger('connexion.decorators.response')
-
-
-class ResponseValidator(BaseDecorator):
-    def __init__(self, operation, mimetype, validator=None):
-        """
-        :type operation: Operation
-        :type mimetype: str
-        :param validator: Validator class that should be used to validate passed data
-                          against API schema. Default is jsonschema.Draft4Validator.
-        :type validator: jsonschema.IValidator
-        """
-        self.operation = operation
-        self.mimetype = mimetype
-        self.validator = validator
-
-    def validate_response(self, data, status_code, headers, url):
-        """
-        Validates the Response object based on what has been declared in the specification.
-        Ensures the response body matches the declated schema.
-        :type data: dict
-        :type status_code: int
-        :type headers: dict
-        :rtype bool | None
-        """
-        # check against returned header, fall back to expected mimetype
-        content_type = headers.get("Content-Type", self.mimetype)
-        content_type = content_type.rsplit(";", 1)[0]  # remove things like utf8 metadata
-
-        response_definition = self.operation.response_definition(str(status_code), content_type)
-        response_schema = self.operation.response_schema(str(status_code), content_type)
-
-        if self.is_json_schema_compatible(response_schema):
-            v = ResponseBodyValidator(response_schema, validator=self.validator)
-            try:
-                data = self.operation.json_loads(data)
-                v.validate_schema(data, url)
-            except ValidationError as e:
-                raise NonConformingResponseBody(message=str(e))
-
-        if response_definition and response_definition.get("headers"):
-            # converting to set is needed to support python 2.7
-            response_definition_header_keys = set(response_definition.get("headers").keys())
-            header_keys = set(headers.keys())
-            missing_keys = response_definition_header_keys - header_keys
-            if missing_keys:
-                pretty_list = ', '.join(missing_keys)
-                msg = ("Keys in header don't match response specification. "
-                       "Difference: {0}").format(pretty_list)
-                raise NonConformingResponseHeaders(message=msg)
-        return True
-
-    def is_json_schema_compatible(self, response_schema):
-        """
-        Verify if the specified operation responses are JSON schema
-        compatible.
-
-        All operations that specify a JSON schema and have content
-        type "application/json" or "text/plain" can be validated using
-        json_schema package.
-
-        :type response_schema: dict
-        :rtype bool
-        """
-        if not response_schema:
-            return False
-        return all_json([self.mimetype]) or self.mimetype == 'text/plain'
-
-    def __call__(self, function):
-        """
-        :type function: types.FunctionType
-        :rtype: types.FunctionType
-        """
-
-        def _wrapper(request, response):
-            connexion_response = \
-                self.operation.api.get_connexion_response(response, self.mimetype)
-            self.validate_response(
-                connexion_response.body, connexion_response.status_code,
-                connexion_response.headers, request.url)
-
-            return response
-
-        if has_coroutine(function):
-            from .coroutine_wrappers import get_response_validator_wrapper
-            wrapper = get_response_validator_wrapper(function, _wrapper)
-
-        else:  # pragma: 3 no cover
-            @functools.wraps(function)
-            def wrapper(request):
-                response = function(request)
-                return _wrapper(request, response)
-
-        return wrapper
-
-    def __repr__(self):
-        """
-        :rtype: str
-        """
-        return '<ResponseValidator>'  # pragma: no cover
diff --git a/airflow/_vendor/connexion/decorators/security.py b/airflow/_vendor/connexion/decorators/security.py
deleted file mode 100644
index 48aeb5e..0000000
--- a/airflow/_vendor/connexion/decorators/security.py
+++ /dev/null
@@ -1,341 +0,0 @@
-# Authentication and authorization related decorators
-import base64
-import functools
-import logging
-import os
-import textwrap
-
-import httpx
-from airflow._vendor.connexion.utils import get_function_from_name
-import http.cookies
-
-from ..exceptions import (ConnexionException, OAuthProblem,
-                          OAuthResponseProblem, OAuthScopeProblem)
-
-logger = logging.getLogger('connexion.api.security')
-# use connection pool for OAuth tokeninfo
-limits = httpx.Limits(max_keepalive_connections=100, max_connections=100)
-session = httpx.Client(limits=limits)
-
-
-def get_tokeninfo_func(security_definition):
-    """
-    :type security_definition: dict
-    :rtype: function
-
-    >>> get_tokeninfo_url({'x-tokenInfoFunc': 'foo.bar'})
-    '<function foo.bar>'
-    """
-    token_info_func = (security_definition.get("x-tokenInfoFunc") or
-                       os.environ.get('TOKENINFO_FUNC'))
-    if token_info_func:
-        return get_function_from_name(token_info_func)
-
-    token_info_url = (security_definition.get('x-tokenInfoUrl') or
-                      os.environ.get('TOKENINFO_URL'))
-    if token_info_url:
-        return functools.partial(get_tokeninfo_remote, token_info_url)
-
-    return None
-
-
-def get_scope_validate_func(security_definition):
-    """
-    :type security_definition: dict
-    :rtype: function
-
-    >>> get_scope_validate_func({'x-scopeValidateFunc': 'foo.bar'})
-    '<function foo.bar>'
-    """
-    func = (security_definition.get("x-scopeValidateFunc") or
-            os.environ.get('SCOPEVALIDATE_FUNC'))
-    if func:
-        return get_function_from_name(func)
-    return validate_scope
-
-
-def get_basicinfo_func(security_definition):
-    """
-    :type security_definition: dict
-    :rtype: function
-
-    >>> get_basicinfo_func({'x-basicInfoFunc': 'foo.bar'})
-    '<function foo.bar>'
-    """
-    func = (security_definition.get("x-basicInfoFunc") or
-            os.environ.get('BASICINFO_FUNC'))
-    if func:
-        return get_function_from_name(func)
-    return None
-
-
-def get_apikeyinfo_func(security_definition):
-    """
-    :type security_definition: dict
-    :rtype: function
-
-    >>> get_apikeyinfo_func({'x-apikeyInfoFunc': 'foo.bar'})
-    '<function foo.bar>'
-    """
-    func = (security_definition.get("x-apikeyInfoFunc") or
-            os.environ.get('APIKEYINFO_FUNC'))
-    if func:
-        return get_function_from_name(func)
-    return None
-
-
-def get_bearerinfo_func(security_definition):
-    """
-    :type security_definition: dict
-    :rtype: function
-
-    >>> get_bearerinfo_func({'x-bearerInfoFunc': 'foo.bar'})
-    '<function foo.bar>'
-    """
-    func = (security_definition.get("x-bearerInfoFunc") or
-            os.environ.get('BEARERINFO_FUNC'))
-    if func:
-        return get_function_from_name(func)
-    return None
-
-
-def security_passthrough(function):
-    """
-    :type function: types.FunctionType
-    :rtype: types.FunctionType
-    """
-    return function
-
-
-def security_deny(function):
-    """
-    :type function: types.FunctionType
-    :rtype: types.FunctionType
-    """
-
-    def deny(*args, **kwargs):
-        raise ConnexionException("Error in security definitions")
-
-    return deny
-
-
-def get_authorization_info(auth_funcs, request, required_scopes):
-    for func in auth_funcs:
-        token_info = func(request, required_scopes)
-        if token_info is not None:
-            return token_info
-
-    logger.info("... No auth provided. Aborting with 401.")
-    raise OAuthProblem(description='No authorization token provided')
-
-
-def validate_scope(required_scopes, token_scopes):
-    """
-    :param required_scopes: Scopes required to access operation
-    :param token_scopes: Scopes granted by authorization server
-    :rtype: bool
-    """
-    required_scopes = set(required_scopes)
-    if isinstance(token_scopes, list):
-        token_scopes = set(token_scopes)
-    else:
-        token_scopes = set(token_scopes.split())
-    logger.debug("... Scopes required: %s", required_scopes)
-    logger.debug("... Token scopes: %s", token_scopes)
-    if not required_scopes <= token_scopes:
-        logger.info(textwrap.dedent("""
-                    ... Token scopes (%s) do not match the scopes necessary to call endpoint (%s).
-                     Aborting with 403.""").replace('\n', ''),
-                    token_scopes, required_scopes)
-        return False
-    return True
-
-
-def verify_authorization_token(request, token_info_func):
-    """
-    :param request: ConnexionRequest
-    :param token_info_func: types.FunctionType
-    :rtype: dict
-    """
-    authorization = request.headers.get('Authorization')
-    if not authorization:
-        return None
-
-    try:
-        auth_type, token = authorization.split(None, 1)
-    except ValueError:
-        raise OAuthProblem(description='Invalid authorization header')
-
-    if auth_type.lower() != 'bearer':
-        return None
-
-    token_info = token_info_func(token)
-    if token_info is None:
-        raise OAuthResponseProblem(
-            description='Provided token is not valid',
-            token_response=None
-        )
-
-    return token_info
-
-
-def verify_oauth(token_info_func, scope_validate_func):
-
-    def wrapper(request, required_scopes):
-        token_info = verify_authorization_token(request, token_info_func)
-        if token_info is None:
-            return None
-
-        # Fallback to 'scopes' for backward compability
-        token_scopes = token_info.get('scope', token_info.get('scopes', ''))
-        if not scope_validate_func(required_scopes, token_scopes):
-            raise OAuthScopeProblem(
-                description='Provided token doesn\'t have the required scope',
-                required_scopes=required_scopes,
-                token_scopes=token_scopes
-            )
-
-        return token_info
-
-    return wrapper
-
-
-def verify_basic(basic_info_func):
-
-    def wrapper(request, required_scopes):
-        authorization = request.headers.get('Authorization')
-        if not authorization:
-            return None
-
-        try:
-            auth_type, user_pass = authorization.split(None, 1)
-        except ValueError:
-            raise OAuthProblem(description='Invalid authorization header')
-
-        if auth_type.lower() != 'basic':
-            return None
-
-        try:
-            username, password = base64.b64decode(user_pass).decode('latin1').split(':', 1)
-        except Exception:
-            raise OAuthProblem(description='Invalid authorization header')
-
-        token_info = basic_info_func(username, password, required_scopes=required_scopes)
-        if token_info is None:
-            raise OAuthResponseProblem(
-                description='Provided authorization is not valid',
-                token_response=None
-            )
-        return token_info
-
-    return wrapper
-
-
-def get_cookie_value(cookies, name):
-    '''
-    Returns cookie value by its name. None if no such value.
-    :param cookies: str: cookies raw data
-    :param name: str: cookies key
-    '''
-    cookie_parser = http.cookies.SimpleCookie()
-    cookie_parser.load(str(cookies))
-    try:
-        return cookie_parser[name].value
-    except KeyError:
-        return None
-
-
-def verify_apikey(apikey_info_func, loc, name):
-
-    def wrapper(request, required_scopes):
-
-        def _immutable_pop(_dict, key):
-            """
-            Pops the key from an immutable dict and returns the value that was popped,
-            and a new immutable dict without the popped key.
-            """
-            cls = type(_dict)
-            try:
-                _dict = _dict.to_dict(flat=False)
-                return _dict.pop(key)[0], cls(_dict)
-            except AttributeError:
-                _dict = dict(_dict.items())
-                return _dict.pop(key), cls(_dict)
-
-        if loc == 'query':
-            try:
-                apikey, request.query = _immutable_pop(request.query, name)
-            except KeyError:
-                apikey = None
-        elif loc == 'header':
-            apikey = request.headers.get(name)
-        elif loc == 'cookie':
-            cookieslist = request.headers.get('Cookie')
-            apikey = get_cookie_value(cookieslist, name)
-        else:
-            return None
-
-        if apikey is None:
-            return None
-
-        token_info = apikey_info_func(apikey, required_scopes=required_scopes)
-        if token_info is None:
-            raise OAuthResponseProblem(
-                description='Provided apikey is not valid',
-                token_response=None
-            )
-        return token_info
-
-    return wrapper
-
-
-def verify_bearer(bearer_info_func):
-    """
-    :param bearer_info_func: types.FunctionType
-    :rtype: types.FunctionType
-    """
-
-    def wrapper(request, required_scopes):
-        return verify_authorization_token(request, bearer_info_func)
-
-    return wrapper
-
-
-def verify_none():
-    """
-    :rtype: types.FunctionType
-    """
-
-    def wrapper(request, required_scopes):
-        return {}
-
-    return wrapper
-
-
-def verify_security(auth_funcs, required_scopes, function):
-
-    @functools.wraps(function)
-    def wrapper(request):
-        token_info = get_authorization_info(auth_funcs, request, required_scopes)
-
-        # Fallback to 'uid' for backward compability
-        request.context['user'] = token_info.get('sub', token_info.get('uid'))
-        request.context['token_info'] = token_info
-        return function(request)
-
-    return wrapper
-
-
-def get_tokeninfo_remote(token_info_url, token):
-    """
-    Retrieve oauth token_info remotely using HTTP
-    :param token_info_url: Url to get information about the token
-    :type token_info_url: str
-    :param token: oauth token from authorization header
-    :type token: str
-    :rtype: dict
-    """
-    token_request = httpx.get(token_info_url, headers={'Authorization': 'Bearer {}'.format(token)}, timeout=5)
-    if not token_request.ok:
-        return None
-    return token_request.json()
diff --git a/airflow/_vendor/connexion/decorators/uri_parsing.py b/airflow/_vendor/connexion/decorators/uri_parsing.py
deleted file mode 100644
index 340ecae..0000000
--- a/airflow/_vendor/connexion/decorators/uri_parsing.py
+++ /dev/null
@@ -1,329 +0,0 @@
-# Decorators to split query and path parameters
-import abc
-import functools
-import logging
-import re
-import json
-from .. import utils
-
-from .decorator import BaseDecorator
-
-logger = logging.getLogger('connexion.decorators.uri_parsing')
-
-QUERY_STRING_DELIMITERS = {
-    'spaceDelimited': ' ',
-    'pipeDelimited': '|',
-    'simple': ',',
-    'form': ','
-}
-
-
-class AbstractURIParser(BaseDecorator, metaclass=abc.ABCMeta):
-    parsable_parameters = ["query", "path"]
-
-    def __init__(self, param_defns, body_defn):
-        """
-        a URI parser is initialized with parameter definitions.
-        When called with a request object, it handles array types in the URI
-        both in the path and query according to the spec.
-        Some examples include:
-         - https://mysite.fake/in/path/1,2,3/            # path parameters
-         - https://mysite.fake/?in_query=a,b,c           # simple query params
-         - https://mysite.fake/?in_query=a|b|c           # various separators
-         - https://mysite.fake/?in_query=a&in_query=b,c  # complex query params
-        """
-        self._param_defns = {p["name"]: p
-                             for p in param_defns
-                             if p["in"] in self.parsable_parameters}
-        self._body_schema = body_defn.get("schema", {})
-        self._body_encoding = body_defn.get("encoding", {})
-
-    @abc.abstractproperty
-    def param_defns(self):
-        """
-        returns the parameter definitions by name
-        """
-
-    @abc.abstractproperty
-    def param_schemas(self):
-        """
-        returns the parameter schemas by name
-        """
-
-    def __repr__(self):
-        """
-        :rtype: str
-        """
-        return "<{classname}>".format(
-            classname=self.__class__.__name__)  # pragma: no cover
-
-    @abc.abstractmethod
-    def resolve_form(self, form_data):
-        """ Resolve cases where form parameters are provided multiple times.
-        """
-
-    @abc.abstractmethod
-    def resolve_query(self, query_data):
-        """ Resolve cases where query parameters are provided multiple times.
-        """
-
-    @abc.abstractmethod
-    def resolve_path(self, path):
-        """ Resolve cases where path parameters include lists
-        """
-
-    @abc.abstractmethod
-    def _resolve_param_duplicates(self, values, param_defn, _in):
-        """ Resolve cases where query parameters are provided multiple times.
-            For example, if the query string is '?a=1,2,3&a=4,5,6' the value of
-            `a` could be "4,5,6", or "1,2,3" or "1,2,3,4,5,6" depending on the
-            implementation.
-        """
-
-    @abc.abstractmethod
-    def _split(self, value, param_defn, _in):
-        """
-        takes a string, a parameter definition, and a parameter type
-        and returns an array that has been constructed according to
-        the parameter definition.
-        """
-
-    def resolve_params(self, params, _in):
-        """
-        takes a dict of parameters, and resolves the values into
-        the correct array type handling duplicate values, and splitting
-        based on the collectionFormat defined in the spec.
-        """
-        resolved_param = {}
-        for k, values in params.items():
-            param_defn = self.param_defns.get(k)
-            param_schema = self.param_schemas.get(k)
-
-            if not (param_defn or param_schema):
-                # rely on validation
-                resolved_param[k] = values
-                continue
-
-            if _in == 'path':
-                # multiple values in a path is impossible
-                values = [values]
-
-            if (param_schema is not None and param_schema['type'] == 'array'):
-                # resolve variable re-assignment, handle explode
-                values = self._resolve_param_duplicates(values, param_defn, _in)
-                # handle array styles
-                resolved_param[k] = self._split(values, param_defn, _in)
-            else:
-                resolved_param[k] = values[-1]
-
-        return resolved_param
-
-    def __call__(self, function):
-        """
-        :type function: types.FunctionType
-        :rtype: types.FunctionType
-        """
-
-        @functools.wraps(function)
-        def wrapper(request):
-            def coerce_dict(md):
-                """ MultiDict -> dict of lists
-                """
-                try:
-                    return md.to_dict(flat=False)
-                except AttributeError:
-                    return dict(md.items())
-
-            query = coerce_dict(request.query)
-            path_params = coerce_dict(request.path_params)
-            form = coerce_dict(request.form)
-
-            request.query = self.resolve_query(query)
-            request.path_params = self.resolve_path(path_params)
-            request.form = self.resolve_form(form)
-            response = function(request)
-            return response
-
-        return wrapper
-
-
-class OpenAPIURIParser(AbstractURIParser):
-    style_defaults = {"path": "simple", "header": "simple",
-                      "query": "form", "cookie": "form",
-                      "form": "form"}
-
-    @property
-    def param_defns(self):
-        return self._param_defns
-
-    @property
-    def form_defns(self):
-        return {k: v for k, v in self._body_schema.get('properties', {}).items()}
-
-    @property
-    def param_schemas(self):
-        return {k: v.get('schema', {}) for k, v in self.param_defns.items()}
-
-    def resolve_form(self, form_data):
-        if self._body_schema is None or self._body_schema.get('type') != 'object':
-            return form_data
-        for k in form_data:
-            encoding = self._body_encoding.get(k, {"style": "form"})
-            defn = self.form_defns.get(k, {})
-            # TODO support more form encoding styles
-            form_data[k] = \
-                self._resolve_param_duplicates(form_data[k], encoding, 'form')
-            if defn and defn["type"] == "array":
-                form_data[k] = self._split(form_data[k], encoding, 'form')
-            elif 'contentType' in encoding and utils.all_json([encoding.get('contentType')]):
-                form_data[k] = json.loads(form_data[k])
-        return form_data
-
-    @staticmethod
-    def _make_deep_object(k, v):
-        """ consumes keys, value pairs like (a[foo][bar], "baz")
-            returns (a, {"foo": {"bar": "baz"}}}, is_deep_object)
-        """
-        root_key = k.split("[", 1)[0]
-        if k == root_key:
-            return (k, v, False)
-        key_path = re.findall(r'\[([^\[\]]*)\]', k)
-        root = prev = node = {}
-        for k in key_path:
-            node[k] = {}
-            prev = node
-            node = node[k]
-        prev[k] = v[0]
-        return (root_key, [root], True)
-
-    def _preprocess_deep_objects(self, query_data):
-        """ deep objects provide a way of rendering nested objects using query
-            parameters.
-        """
-        deep = [self._make_deep_object(k, v) for k, v in query_data.items()]
-        root_keys = [k for k, v, is_deep_object in deep]
-        ret = dict.fromkeys(root_keys, [{}])
-        for k, v, is_deep_object in deep:
-            if is_deep_object:
-                ret[k] = [utils.deep_merge(v[0], ret[k][0])]
-            else:
-                ret[k] = v
-        return ret
-
-    def resolve_query(self, query_data):
-        query_data = self._preprocess_deep_objects(query_data)
-        return self.resolve_params(query_data, 'query')
-
-    def resolve_path(self, path_data):
-        return self.resolve_params(path_data, 'path')
-
-    @staticmethod
-    def _resolve_param_duplicates(values, param_defn, _in):
-        """ Resolve cases where query parameters are provided multiple times.
-            The default behavior is to use the first-defined value.
-            For example, if the query string is '?a=1,2,3&a=4,5,6' the value of
-            `a` would be "4,5,6".
-            However, if 'explode' is 'True' then the duplicate values
-            are concatenated together and `a` would be "1,2,3,4,5,6".
-        """
-        default_style = OpenAPIURIParser.style_defaults[_in]
-        style = param_defn.get('style', default_style)
-        delimiter = QUERY_STRING_DELIMITERS.get(style, ',')
-        is_form = (style == 'form')
-        explode = param_defn.get('explode', is_form)
-        if explode:
-            return delimiter.join(values)
-
-        # default to last defined value
-        return values[-1]
-
-    @staticmethod
-    def _split(value, param_defn, _in):
-        default_style = OpenAPIURIParser.style_defaults[_in]
-        style = param_defn.get('style', default_style)
-        delimiter = QUERY_STRING_DELIMITERS.get(style, ',')
-        return value.split(delimiter)
-
-
-class Swagger2URIParser(AbstractURIParser):
-    """
-    Adheres to the Swagger2 spec,
-    Assumes the the last defined query parameter should be used.
-    """
-    parsable_parameters = ["query", "path", "formData"]
-
-    @property
-    def param_defns(self):
-        return self._param_defns
-
-    @property
-    def param_schemas(self):
-        return self._param_defns  # swagger2 conflates defn and schema
-
-    def resolve_form(self, form_data):
-        return self.resolve_params(form_data, 'form')
-
-    def resolve_query(self, query_data):
-        return self.resolve_params(query_data, 'query')
-
-    def resolve_path(self, path_data):
-        return self.resolve_params(path_data, 'path')
-
-    @staticmethod
-    def _resolve_param_duplicates(values, param_defn, _in):
-        """ Resolve cases where query parameters are provided multiple times.
-            The default behavior is to use the first-defined value.
-            For example, if the query string is '?a=1,2,3&a=4,5,6' the value of
-            `a` would be "4,5,6".
-            However, if 'collectionFormat' is 'multi' then the duplicate values
-            are concatenated together and `a` would be "1,2,3,4,5,6".
-        """
-        if param_defn.get('collectionFormat') == 'multi':
-            return ','.join(values)
-        # default to last defined value
-        return values[-1]
-
-    @staticmethod
-    def _split(value, param_defn, _in):
-        if param_defn.get("collectionFormat") == 'pipes':
-            return value.split('|')
-        return value.split(',')
-
-
-class FirstValueURIParser(Swagger2URIParser):
-    """
-    Adheres to the Swagger2 spec
-    Assumes that the first defined query parameter should be used
-    """
-
-    @staticmethod
-    def _resolve_param_duplicates(values, param_defn, _in):
-        """ Resolve cases where query parameters are provided multiple times.
-            The default behavior is to use the first-defined value.
-            For example, if the query string is '?a=1,2,3&a=4,5,6' the value of
-            `a` would be "1,2,3".
-            However, if 'collectionFormat' is 'multi' then the duplicate values
-            are concatenated together and `a` would be "1,2,3,4,5,6".
-        """
-        if param_defn.get('collectionFormat') == 'multi':
-            return ','.join(values)
-        # default to first defined value
-        return values[0]
-
-
-class AlwaysMultiURIParser(Swagger2URIParser):
-    """
-    Does not adhere to the Swagger2 spec, but is backwards compatible with
-    connexion behavior in version 1.4.2
-    """
-
-    @staticmethod
-    def _resolve_param_duplicates(values, param_defn, _in):
-        """ Resolve cases where query parameters are provided multiple times.
-            The default behavior is to join all provided parameters together.
-            For example, if the query string is '?a=1,2,3&a=4,5,6' the value of
-            `a` would be "1,2,3,4,5,6".
-        """
-        if param_defn.get('collectionFormat') == 'pipes':
-            return '|'.join(values)
-        return ','.join(values)
diff --git a/airflow/_vendor/connexion/decorators/validation.py b/airflow/_vendor/connexion/decorators/validation.py
deleted file mode 100644
index b7c7a62..0000000
--- a/airflow/_vendor/connexion/decorators/validation.py
+++ /dev/null
@@ -1,386 +0,0 @@
-import collections
-import copy
-import functools
-import logging
-
-import pkg_resources
-from jsonschema import Draft4Validator, ValidationError, draft4_format_checker
-from jsonschema.validators import extend
-from werkzeug.datastructures import FileStorage
-
-from ..exceptions import ExtraParameterProblem, BadRequestProblem, UnsupportedMediaTypeProblem
-from ..http_facts import FORM_CONTENT_TYPES
-from ..json_schema import Draft4RequestValidator, Draft4ResponseValidator
-from ..utils import all_json, boolean, is_json_mimetype, is_null, is_nullable
-
-_jsonschema_3_or_newer = pkg_resources.parse_version(
-        pkg_resources.get_distribution("jsonschema").version) >= \
-    pkg_resources.parse_version("3.0.0")
-
-logger = logging.getLogger('connexion.decorators.validation')
-
-TYPE_MAP = {
-    'integer': int,
-    'number': float,
-    'boolean': boolean,
-    'object': dict
-}
-
-
-class TypeValidationError(Exception):
-    def __init__(self, schema_type, parameter_type, parameter_name):
-        """
-        Exception raise when type validation fails
-
-        :type schema_type: str
-        :type parameter_type: str
-        :type parameter_name: str
-        :return:
-        """
-        self.schema_type = schema_type
-        self.parameter_type = parameter_type
-        self.parameter_name = parameter_name
-
-    def __str__(self):
-        msg = "Wrong type, expected '{schema_type}' for {parameter_type} parameter '{parameter_name}'"
-        return msg.format(**vars(self))
-
-
-def coerce_type(param, value, parameter_type, parameter_name=None):
-
-    def make_type(value, type_literal):
-        type_func = TYPE_MAP.get(type_literal)
-        return type_func(value)
-
-    param_schema = param.get("schema", param)
-    if is_nullable(param_schema) and is_null(value):
-        return None
-
-    param_type = param_schema.get('type')
-    parameter_name = parameter_name if parameter_name else param.get('name')
-    if param_type == "array":
-        converted_params = []
-        for v in value:
-            try:
-                converted = make_type(v, param_schema["items"]["type"])
-            except (ValueError, TypeError):
-                converted = v
-            converted_params.append(converted)
-        return converted_params
-    elif param_type == 'object':
-        if param_schema.get('properties'):
-            def cast_leaves(d, schema):
-                if type(d) is not dict:
-                    try:
-                        return make_type(d, schema['type'])
-                    except (ValueError, TypeError):
-                        return d
-                for k, v in d.items():
-                    if k in schema['properties']:
-                        d[k] = cast_leaves(v, schema['properties'][k])
-                return d
-
-            return cast_leaves(value, param_schema)
-        return value
-    else:
-        try:
-            return make_type(value, param_type)
-        except ValueError:
-            raise TypeValidationError(param_type, parameter_type, parameter_name)
-        except TypeError:
-            return value
-
-
-def validate_parameter_list(request_params, spec_params):
-    request_params = set(request_params)
-    spec_params = set(spec_params)
-
-    return request_params.difference(spec_params)
-
-
-class RequestBodyValidator(object):
-
-    def __init__(self, schema, consumes, api, is_null_value_valid=False, validator=None,
-                 strict_validation=False):
-        """
-        :param schema: The schema of the request body
-        :param consumes: The list of content types the operation consumes
-        :param is_null_value_valid: Flag to indicate if null is accepted as valid value.
-        :param validator: Validator class that should be used to validate passed data
-                          against API schema. Default is jsonschema.Draft4Validator.
-        :type validator: jsonschema.IValidator
-        :param strict_validation: Flag indicating if parameters not in spec are allowed
-        """
-        self.consumes = consumes
-        self.schema = schema
-        self.has_default = schema.get('default', False)
-        self.is_null_value_valid = is_null_value_valid
-        validatorClass = validator or Draft4RequestValidator
-        self.validator = validatorClass(schema, format_checker=draft4_format_checker)
-        self.api = api
-        self.strict_validation = strict_validation
-
-    def validate_formdata_parameter_list(self, request):
-        request_params = request.form.keys()
-        spec_params = self.schema.get('properties', {}).keys()
-        return validate_parameter_list(request_params, spec_params)
-
-    def __call__(self, function):
-        """
-        :type function: types.FunctionType
-        :rtype: types.FunctionType
-        """
-
-        @functools.wraps(function)
-        def wrapper(request):
-            if all_json(self.consumes):
-                data = request.json
-
-                empty_body = not(request.body or request.form or request.files)
-                if data is None and not empty_body and not self.is_null_value_valid:
-                    try:
-                        ctype_is_json = is_json_mimetype(request.headers.get("Content-Type", ""))
-                    except ValueError:
-                        ctype_is_json = False
-
-                    if ctype_is_json:
-                        # Content-Type is json but actual body was not parsed
-                        raise BadRequestProblem(detail="Request body is not valid JSON")
-                    else:
-                        # the body has contents that were not parsed as JSON
-                        raise UnsupportedMediaTypeProblem(
-                                       "Invalid Content-type ({content_type}), expected JSON data".format(
-                                           content_type=request.headers.get("Content-Type", "")
-                                       ))
-
-                logger.debug("%s validating schema...", request.url)
-                if data is not None or not self.has_default:
-                    self.validate_schema(data, request.url)
-            elif self.consumes[0] in FORM_CONTENT_TYPES:
-                data = dict(request.form.items()) or (request.body if len(request.body) > 0 else {})
-                data.update(dict.fromkeys(request.files, ''))  # validator expects string..
-                logger.debug('%s validating schema...', request.url)
-
-                if self.strict_validation:
-                    formdata_errors = self.validate_formdata_parameter_list(request)
-                    if formdata_errors:
-                        raise ExtraParameterProblem(formdata_errors, [])
-
-                if data:
-                    props = self.schema.get("properties", {})
-                    errs = []
-                    for k, param_defn in props.items():
-                        if k in data:
-                            try:
-                                data[k] = coerce_type(param_defn, data[k], 'requestBody', k)
-                            except TypeValidationError as e:
-                                errs += [str(e)]
-                                print(errs)
-                    if errs:
-                        raise BadRequestProblem(detail=errs)
-
-                self.validate_schema(data, request.url)
-
-            response = function(request)
-            return response
-
-        return wrapper
-
-    def validate_schema(self, data, url):
-        # type: (dict, AnyStr) -> Union[ConnexionResponse, None]
-        if self.is_null_value_valid and is_null(data):
-            return None
-
-        try:
-            self.validator.validate(data)
-        except ValidationError as exception:
-            error_path = '.'.join(str(item) for item in exception.path)
-            error_path_msg = " - '{path}'".format(path=error_path) \
-                if error_path else ""
-            logger.error(
-                "{url} validation error: {error}{error_path_msg}".format(
-                    url=url, error=exception.message,
-                    error_path_msg=error_path_msg),
-                extra={'validator': 'body'})
-            raise BadRequestProblem(detail="{message}{error_path_msg}".format(
-                               message=exception.message,
-                               error_path_msg=error_path_msg))
-
-        return None
-
-
-class ResponseBodyValidator(object):
-    def __init__(self, schema, validator=None):
-        """
-        :param schema: The schema of the response body
-        :param validator: Validator class that should be used to validate passed data
-                          against API schema. Default is jsonschema.Draft4Validator.
-        :type validator: jsonschema.IValidator
-        """
-        ValidatorClass = validator or Draft4ResponseValidator
-        self.validator = ValidatorClass(schema, format_checker=draft4_format_checker)
-
-    def validate_schema(self, data, url):
-        # type: (dict, AnyStr) -> Union[ConnexionResponse, None]
-        try:
-            self.validator.validate(data)
-        except ValidationError as exception:
-            logger.error("{url} validation error: {error}".format(url=url,
-                                                                  error=exception),
-                         extra={'validator': 'response'})
-            raise exception
-
-        return None
-
-
-class ParameterValidator(object):
-    def __init__(self, parameters, api, strict_validation=False):
-        """
-        :param parameters: List of request parameter dictionaries
-        :param api: api that the validator is attached to
-        :param strict_validation: Flag indicating if parameters not in spec are allowed
-        """
-        self.parameters = collections.defaultdict(list)
-        for p in parameters:
-            self.parameters[p['in']].append(p)
-
-        self.api = api
-        self.strict_validation = strict_validation
-
-    @staticmethod
-    def validate_parameter(parameter_type, value, param, param_name=None):
-        if value is not None:
-            if is_nullable(param) and is_null(value):
-                return
-
-            try:
-                converted_value = coerce_type(param, value, parameter_type, param_name)
-            except TypeValidationError as e:
-                return str(e)
-
-            param = copy.deepcopy(param)
-            param = param.get('schema', param)
-            if 'required' in param:
-                del param['required']
-            try:
-                if parameter_type == 'formdata' and param.get('type') == 'file':
-                    if _jsonschema_3_or_newer:
-                        extend(
-                            Draft4Validator,
-                            type_checker=Draft4Validator.TYPE_CHECKER.redefine(
-                                "file",
-                                lambda checker, instance: isinstance(instance, FileStorage)
-                            )
-                        )(param, format_checker=draft4_format_checker).validate(converted_value)
-                    else:
-                        Draft4Validator(
-                            param,
-                            format_checker=draft4_format_checker,
-                            types={'file': FileStorage}).validate(converted_value)
-                else:
-                    Draft4Validator(
-                        param, format_checker=draft4_format_checker).validate(converted_value)
-            except ValidationError as exception:
-                debug_msg = 'Error while converting value {converted_value} from param ' \
-                            '{type_converted_value} of type real type {param_type} to the declared type {param}'
-                fmt_params = dict(
-                    converted_value=str(converted_value),
-                    type_converted_value=type(converted_value),
-                    param_type=param.get('type'),
-                    param=param
-                )
-                logger.info(debug_msg.format(**fmt_params))
-                return str(exception)
-
-        elif param.get('required'):
-            return "Missing {parameter_type} parameter '{param[name]}'".format(**locals())
-
-    def validate_query_parameter_list(self, request):
-        request_params = request.query.keys()
-        spec_params = [x['name'] for x in self.parameters.get('query', [])]
-        return validate_parameter_list(request_params, spec_params)
-
-    def validate_formdata_parameter_list(self, request):
-        request_params = request.form.keys()
-        try:
-            spec_params = [x['name'] for x in self.parameters['formData']]
-        except KeyError:
-            # OAS 3
-            return set()
-        return validate_parameter_list(request_params, spec_params)
-
-    def validate_query_parameter(self, param, request):
-        """
-        Validate a single query parameter (request.args in Flask)
-
-        :type param: dict
-        :rtype: str
-        """
-        val = request.query.get(param['name'])
-        return self.validate_parameter('query', val, param)
-
-    def validate_path_parameter(self, param, request):
-        val = request.path_params.get(param['name'].replace('-', '_'))
-        return self.validate_parameter('path', val, param)
-
-    def validate_header_parameter(self, param, request):
-        val = request.headers.get(param['name'])
-        return self.validate_parameter('header', val, param)
-
-    def validate_cookie_parameter(self, param, request):
-        val = request.cookies.get(param['name'])
-        return self.validate_parameter('cookie', val, param)
-
-    def validate_formdata_parameter(self, param_name, param, request):
-        if param.get('type') == 'file' or param.get('format') == 'binary':
-            val = request.files.get(param_name)
-        else:
-            val = request.form.get(param_name)
-
-        return self.validate_parameter('formdata', val, param)
-
-    def __call__(self, function):
-        """
-        :type function: types.FunctionType
-        :rtype: types.FunctionType
-        """
-
-        @functools.wraps(function)
-        def wrapper(request):
-            logger.debug("%s validating parameters...", request.url)
-
-            if self.strict_validation:
-                query_errors = self.validate_query_parameter_list(request)
-                formdata_errors = self.validate_formdata_parameter_list(request)
-
-                if formdata_errors or query_errors:
-                    raise ExtraParameterProblem(formdata_errors, query_errors)
-
-            for param in self.parameters.get('query', []):
-                error = self.validate_query_parameter(param, request)
-                if error:
-                    raise BadRequestProblem(detail=error)
-
-            for param in self.parameters.get('path', []):
-                error = self.validate_path_parameter(param, request)
-                if error:
-                    raise BadRequestProblem(detail=error)
-
-            for param in self.parameters.get('header', []):
-                error = self.validate_header_parameter(param, request)
-                if error:
-                    raise BadRequestProblem(detail=error)
-
-            for param in self.parameters.get('cookie', []):
-                error = self.validate_cookie_parameter(param, request)
-                if error:
-                    raise BadRequestProblem(detail=error)
-
-            for param in self.parameters.get('formData', []):
-                error = self.validate_formdata_parameter(param["name"], param, request)
-                if error:
-                    raise BadRequestProblem(detail=error)
-
-            return function(request)
-
-        return wrapper
diff --git a/airflow/_vendor/connexion/exceptions.py b/airflow/_vendor/connexion/exceptions.py
deleted file mode 100644
index f86cdd2..0000000
--- a/airflow/_vendor/connexion/exceptions.py
+++ /dev/null
@@ -1,142 +0,0 @@
-import warnings
-from jsonschema.exceptions import ValidationError
-from werkzeug.exceptions import Forbidden, Unauthorized
-
-from .problem import problem
-
-
-class ConnexionException(Exception):
-    pass
-
-
-class ProblemException(ConnexionException):
-    def __init__(self, status=400, title=None, detail=None, type=None,
-                 instance=None, headers=None, ext=None):
-        """
-        This exception is holds arguments that are going to be passed to the
-        `connexion.problem` function to generate a propert response.
-        """
-        self.status = status
-        self.title = title
-        self.detail = detail
-        self.type = type
-        self.instance = instance
-        self.headers = headers
-        self.ext = ext
-
-    def to_problem(self):
-        warnings.warn(
-            "'to_problem' is planned to be removed in a future release. "
-            "Call connexion.problem.problem(..) instead to maintain the existing error response.", DeprecationWarning)
-        return problem(status=self.status, title=self.title, detail=self.detail,
-                       type=self.type, instance=self.instance, headers=self.headers,
-                       ext=self.ext)
-
-
-class ResolverError(LookupError):
-    def __init__(self, reason='Unknown reason', exc_info=None):
-        """
-        :param reason: Reason why the resolver failed.
-        :type reason: str
-        :param exc_info: If specified, gives details of the original exception
-            as returned by sys.exc_info()
-        :type exc_info: tuple | None
-        """
-        self.reason = reason
-        self.exc_info = exc_info
-
-    def __str__(self):  # pragma: no cover
-        return '<ResolverError: {}>'.format(self.reason)
-
-    def __repr__(self):  # pragma: no cover
-        return '<ResolverError: {}>'.format(self.reason)
-
-
-class InvalidSpecification(ConnexionException, ValidationError):
-    pass
-
-
-class NonConformingResponse(ProblemException):
-    def __init__(self, reason='Unknown Reason', message=None):
-        """
-        :param reason: Reason why the response did not conform to the specification
-        :type reason: str
-        """
-        super(NonConformingResponse, self).__init__(status=500, title=reason, detail=message)
-        self.reason = reason
-        self.message = message
-
-    def __str__(self):  # pragma: no cover
-        return '<NonConformingResponse: {}>'.format(self.reason)
-
-    def __repr__(self):  # pragma: no cover
-        return '<NonConformingResponse: {}>'.format(self.reason)
-
-
-class AuthenticationProblem(ProblemException):
-
-    def __init__(self, status, title, detail):
-        super(AuthenticationProblem, self).__init__(status=status, title=title, detail=detail)
-
-
-class ResolverProblem(ProblemException):
-
-    def __init__(self, status, title, detail):
-        super(ResolverProblem, self).__init__(status=status, title=title, detail=detail)
-
-
-class BadRequestProblem(ProblemException):
-
-    def __init__(self, title='Bad Request', detail=None):
-        super(BadRequestProblem, self).__init__(status=400, title=title, detail=detail)
-
-
-class UnsupportedMediaTypeProblem(ProblemException):
-
-    def __init__(self, title="Unsupported Media Type", detail=None):
-        super(UnsupportedMediaTypeProblem, self).__init__(status=415, title=title, detail=detail)
-
-
-class NonConformingResponseBody(NonConformingResponse):
-    def __init__(self, message, reason="Response body does not conform to specification"):
-        super(NonConformingResponseBody, self).__init__(reason=reason, message=message)
-
-
-class NonConformingResponseHeaders(NonConformingResponse):
-    def __init__(self, message, reason="Response headers do not conform to specification"):
-        super(NonConformingResponseHeaders, self).__init__(reason=reason, message=message)
-
-
-class OAuthProblem(Unauthorized):
-    pass
-
-
-class OAuthResponseProblem(OAuthProblem):
-    def __init__(self, token_response, **kwargs):
-        self.token_response = token_response
-        super(OAuthResponseProblem, self).__init__(**kwargs)
-
-
-class OAuthScopeProblem(Forbidden):
-    def __init__(self, token_scopes, required_scopes, **kwargs):
-        self.required_scopes = required_scopes
-        self.token_scopes = token_scopes
-
-        super(OAuthScopeProblem, self).__init__(**kwargs)
-
-
-class ExtraParameterProblem(ProblemException):
-    def __init__(self, formdata_parameters, query_parameters, title=None, detail=None, **kwargs):
-        self.extra_formdata = formdata_parameters
-        self.extra_query = query_parameters
-
-        # This keep backwards compatibility with the old returns
-        if detail is None:
-            if self.extra_query:
-                detail = "Extra {parameter_type} parameter(s) {extra_params} not in spec"\
-                    .format(parameter_type='query', extra_params=', '.join(self.extra_query))
-            elif self.extra_formdata:
-                detail = "Extra {parameter_type} parameter(s) {extra_params} not in spec"\
-                    .format(parameter_type='formData', extra_params=', '.join(self.extra_formdata))
-
-        super(ExtraParameterProblem, self).__init__(title=title, detail=detail, **kwargs)
diff --git a/airflow/_vendor/connexion/handlers.py b/airflow/_vendor/connexion/handlers.py
deleted file mode 100644
index dacd89e..0000000
--- a/airflow/_vendor/connexion/handlers.py
+++ /dev/null
@@ -1,85 +0,0 @@
-import logging
-
-from .operations.secure import SecureOperation
-from .exceptions import AuthenticationProblem, ResolverProblem
-
-logger = logging.getLogger('connexion.handlers')
-
-RESOLVER_ERROR_ENDPOINT_RANDOM_DIGITS = 6
-
-
-class AuthErrorHandler(SecureOperation):
-    """
-    Wraps an error with authentication.
-    """
-
-    def __init__(self, api, exception, security, security_definitions):
-        """
-        This class uses the exception instance to produce the proper response problem in case the
-        request is authenticated.
-
-        :param exception: the exception to be wrapped with authentication
-        :type exception: werkzeug.exceptions.HTTPException
-        :param security: list of security rules the application uses by default
-        :type security: list
-        :param security_definitions: `Security Definitions Object
-            <https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#security-definitions-object>`_
-        :type security_definitions: dict
-        """
-        self.exception = exception
-        super(AuthErrorHandler, self).__init__(api, security, security_definitions)
-
-    @property
-    def function(self):
-        """
-        Configured error auth handler.
-        """
-        security_decorator = self.security_decorator
-        logger.debug('... Adding security decorator (%r)', security_decorator, extra=vars(self))
-        function = self.handle
-        function = security_decorator(function)
-        function = self._request_response_decorator(function)
-        return function
-
-    def handle(self, *args, **kwargs):
-        """
-        Actual handler for the execution after authentication.
-        """
-        raise AuthenticationProblem(
-            title=self.exception.name,
-            detail=self.exception.description,
-            status=self.exception.code
-        )
-
-
-class ResolverErrorHandler(SecureOperation):
-    """
-    Handler for responding to ResolverError.
-    """
-
-    def __init__(self, api, status_code, exception, security, security_definitions):
-        self.status_code = status_code
-        self.exception = exception
-        super(ResolverErrorHandler, self).__init__(api, security, security_definitions)
-
-    @property
-    def function(self):
-        return self.handle
-
-    def handle(self, *args, **kwargs):
-        raise ResolverProblem(
-            title='Not Implemented',
-            detail=self.exception.reason,
-            status=self.status_code
-        )
-
-    @property
-    def operation_id(self):
-        return "noop"
-
-    @property
-    def randomize_endpoint(self):
-        return RESOLVER_ERROR_ENDPOINT_RANDOM_DIGITS
-
-    def get_path_parameter_types(self):
-        return {}
diff --git a/airflow/_vendor/connexion/http_facts.py b/airflow/_vendor/connexion/http_facts.py
deleted file mode 100644
index bff3a85..0000000
--- a/airflow/_vendor/connexion/http_facts.py
+++ /dev/null
@@ -1,15 +0,0 @@
-FORM_CONTENT_TYPES = [
-    'application/x-www-form-urlencoded',
-    'multipart/form-data'
-]
-
-METHODS = set([
-    "get",
-    "put",
-    "post",
-    "delete",
-    "options",
-    "head",
-    "patch",
-    "trace"
-])
diff --git a/airflow/_vendor/connexion/json_schema.py b/airflow/_vendor/connexion/json_schema.py
deleted file mode 100644
index 06b2148..0000000
--- a/airflow/_vendor/connexion/json_schema.py
+++ /dev/null
@@ -1,114 +0,0 @@
-from copy import deepcopy
-
-from jsonschema import Draft4Validator, RefResolver, _utils
-from jsonschema.exceptions import RefResolutionError, ValidationError  # noqa
-from jsonschema.validators import extend
-from openapi_spec_validator.handlers import UrlHandler
-
-from .utils import deep_get
-
-try:
-    from collections.abc import Mapping
-except ImportError:
-    from collections import Mapping
-
-
-default_handlers = {
-    'http': UrlHandler('http'),
-    'https': UrlHandler('https'),
-    'file': UrlHandler('file'),
-}
-
-
-def resolve_refs(spec, store=None, handlers=None):
-    """
-    Resolve JSON references like {"$ref": <some URI>} in a spec.
-    Optionally takes a store, which is a mapping from reference URLs to a
-    dereferenced objects. Prepopulating the store can avoid network calls.
-    """
-    spec = deepcopy(spec)
-    store = store or {}
-    handlers = handlers or default_handlers
-    resolver = RefResolver('', spec, store, handlers=handlers)
-
-    def _do_resolve(node):
-        if isinstance(node, Mapping) and '$ref' in node:
-            path = node['$ref'][2:].split("/")
-            try:
-                # resolve known references
-                node.update(deep_get(spec, path))
-                del node['$ref']
-                return node
-            except KeyError:
-                # resolve external references
-                with resolver.resolving(node['$ref']) as resolved:
-                    return resolved
-        elif isinstance(node, Mapping):
-            for k, v in node.items():
-                node[k] = _do_resolve(v)
-        elif isinstance(node, (list, tuple)):
-            for i, _ in enumerate(node):
-                node[i] = _do_resolve(node[i])
-        return node
-
-    res = _do_resolve(spec)
-    return res
-
-
-def validate_type(validator, types, instance, schema):
-    if instance is None and (schema.get('x-nullable') is True or schema.get('nullable')):
-        return
-
-    types = _utils.ensure_list(types)
-
-    if not any(validator.is_type(instance, type) for type in types):
-        yield ValidationError(_utils.types_msg(instance, types))
-
-
-def validate_enum(validator, enums, instance, schema):
-    if instance is None and (schema.get('x-nullable') is True or schema.get('nullable')):
-        return
-
-    if instance not in enums:
-        yield ValidationError("%r is not one of %r" % (instance, enums))
-
-
-def validate_required(validator, required, instance, schema):
-    if not validator.is_type(instance, "object"):
-        return
-
-    for prop in required:
-        if prop not in instance:
-            properties = schema.get('properties')
-            if properties is not None:
-                subschema = properties.get(prop)
-                if subschema is not None:
-                    if 'readOnly' in validator.VALIDATORS and subschema.get('readOnly'):
-                        continue
-                    if 'writeOnly' in validator.VALIDATORS and subschema.get('writeOnly'):
-                        continue
-                    if 'x-writeOnly' in validator.VALIDATORS and subschema.get('x-writeOnly') is True:
-                        continue
-            yield ValidationError("%r is a required property" % prop)
-
-
-def validate_readOnly(validator, ro, instance, schema):
-    yield ValidationError("Property is read-only")
-
-
-def validate_writeOnly(validator, wo, instance, schema):
-    yield ValidationError("Property is write-only")
-
-
-Draft4RequestValidator = extend(Draft4Validator, {
-                                'type': validate_type,
-                                'enum': validate_enum,
-                                'required': validate_required,
-                                'readOnly': validate_readOnly})
-
-Draft4ResponseValidator = extend(Draft4Validator, {
-                                 'type': validate_type,
-                                 'enum': validate_enum,
-                                 'required': validate_required,
-                                 'writeOnly': validate_writeOnly,
-                                 'x-writeOnly': validate_writeOnly})
diff --git a/airflow/_vendor/connexion/jsonifier.py b/airflow/_vendor/connexion/jsonifier.py
deleted file mode 100644
index 3e8b2fc..0000000
--- a/airflow/_vendor/connexion/jsonifier.py
+++ /dev/null
@@ -1,57 +0,0 @@
-import datetime
-import json
-import uuid
-
-
-class JSONEncoder(json.JSONEncoder):
-    def default(self, o):
-        if isinstance(o, datetime.datetime):
-            if o.tzinfo:
-                # eg: '2015-09-25T23:14:42.588601+00:00'
-                return o.isoformat('T')
-            else:
-                # No timezone present - assume UTC.
-                # eg: '2015-09-25T23:14:42.588601Z'
-                return o.isoformat('T') + 'Z'
-
-        if isinstance(o, datetime.date):
-            return o.isoformat()
-
-        if isinstance(o, uuid.UUID):
-            return str(o)
-
-        return json.JSONEncoder.default(self, o)
-
-
-class Jsonifier(object):
-    """
-    Used to serialized and deserialize to/from JSon
-    """
-    def __init__(self, json_=json, **kwargs):
-        """
-        :param json_: json library to use. Must have loads() and dumps() method
-        :param kwargs: default arguments to pass to json.dumps()
-        """
-        self.json = json_
-        self.dumps_args = kwargs
-
-    def dumps(self, data, **kwargs):
-        """ Central point where JSON serialization happens inside
-        Connexion.
-        """
-        for k, v in self.dumps_args.items():
-            kwargs.setdefault(k, v)
-        return self.json.dumps(data, **kwargs) + '\n'
-
-    def loads(self, data):
-        """ Central point where JSON deserialization happens inside
-        Connexion.
-        """
-        if isinstance(data, bytes):
-            data = data.decode()
-
-        try:
-            return self.json.loads(data)
-        except Exception:
-            if isinstance(data, str):
-                return data
diff --git a/airflow/_vendor/connexion/lifecycle.py b/airflow/_vendor/connexion/lifecycle.py
deleted file mode 100644
index 32fb0f2..0000000
--- a/airflow/_vendor/connexion/lifecycle.py
+++ /dev/null
@@ -1,41 +0,0 @@
-
-class ConnexionRequest(object):
-    def __init__(self,
-                 url,
-                 method,
-                 path_params=None,
-                 query=None,
-                 headers=None,
-                 form=None,
-                 body=None,
-                 json_getter=None,
-                 files=None,
-                 context=None):
-        self.url = url
-        self.method = method
-        self.path_params = path_params or {}
-        self.query = query or {}
-        self.headers = headers or {}
-        self.form = form or {}
-        self.body = body
-        self.json_getter = json_getter
-        self.files = files
-        self.context = context if context is not None else {}
-
-    @property
-    def json(self):
-        return self.json_getter()
-
-
-class ConnexionResponse(object):
-    def __init__(self,
-                 status_code=200,
-                 mimetype=None,
-                 content_type=None,
-                 body=None,
-                 headers=None):
-        self.status_code = status_code
-        self.mimetype = mimetype
-        self.content_type = content_type
-        self.body = body
-        self.headers = headers or {}
diff --git a/airflow/_vendor/connexion/mock.py b/airflow/_vendor/connexion/mock.py
deleted file mode 100644
index e75c335..0000000
--- a/airflow/_vendor/connexion/mock.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import functools
-import logging
-
-from airflow._vendor.connexion.resolver import Resolution, Resolver, ResolverError
-
-logger = logging.getLogger(__name__)
-
-
-class MockResolver(Resolver):
-
-    def __init__(self, mock_all):
-        super(MockResolver, self).__init__()
-        self.mock_all = mock_all
-        self._operation_id_counter = 1
-
-    def resolve(self, operation):
-        """
-        Mock operation resolver
-
-        :type operation: connexion.operations.AbstractOperation
-        """
-        operation_id = self.resolve_operation_id(operation)
-        if not operation_id:
-            # just generate an unique operation ID
-            operation_id = 'mock-{}'.format(self._operation_id_counter)
-            self._operation_id_counter += 1
-
-        mock_func = functools.partial(self.mock_operation, operation=operation)
-        if self.mock_all:
-            func = mock_func
-        else:
-            try:
-                func = self.resolve_function_from_operation_id(operation_id)
-                msg = "... Successfully resolved operationId '{}'! Mock is *not* used for this operation.".format(
-                    operation_id)
-                logger.debug(msg)
-            except ResolverError as resolution_error:
-                logger.debug('... {}! Mock function is used for this operation.'.format(
-                    resolution_error.reason.capitalize()))
-                func = mock_func
-        return Resolution(func, operation_id)
-
-    def mock_operation(self, operation, *args, **kwargs):
-        resp, code = operation.example_response()
-        if resp is not None:
-            return resp, code
-        return 'No example response was defined.', code
diff --git a/airflow/_vendor/connexion/operations/__init__.py b/airflow/_vendor/connexion/operations/__init__.py
deleted file mode 100644
index 4c44b9f..0000000
--- a/airflow/_vendor/connexion/operations/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from .abstract import AbstractOperation  # noqa
-from .openapi import OpenAPIOperation  # noqa
-from .secure import SecureOperation  # noqa
-from .swagger2 import Swagger2Operation  # noqa
-
-
-def make_operation(spec, *args, **kwargs):
-    return spec.operation_cls.from_spec(spec, *args, **kwargs)
diff --git a/airflow/_vendor/connexion/operations/abstract.py b/airflow/_vendor/connexion/operations/abstract.py
deleted file mode 100644
index 51b406b..0000000
--- a/airflow/_vendor/connexion/operations/abstract.py
+++ /dev/null
@@ -1,445 +0,0 @@
-import abc
-import logging
-
-from airflow._vendor.connexion.operations.secure import SecureOperation
-
-from ..decorators.metrics import UWSGIMetricsCollector
-from ..decorators.parameter import parameter_to_arg
-from ..decorators.produces import BaseSerializer, Produces
-from ..decorators.response import ResponseValidator
-from ..decorators.validation import ParameterValidator, RequestBodyValidator
-from ..utils import all_json, is_nullable
-
-logger = logging.getLogger('connexion.operations.abstract')
-
-DEFAULT_MIMETYPE = 'application/json'
-
-VALIDATOR_MAP = {
-    'parameter': ParameterValidator,
-    'body': RequestBodyValidator,
-    'response': ResponseValidator,
-}
-
-
-class AbstractOperation(SecureOperation, metaclass=abc.ABCMeta):
-
-    """
-    An API routes requests to an Operation by a (path, method) pair.
-    The operation uses a resolver to resolve its handler function.
-    We use the provided spec to do a bunch of heavy lifting before
-    (and after) we call security_schemes handler.
-    The registered handler function ends up looking something like:
-
-        @secure_endpoint
-        @validate_inputs
-        @deserialize_function_inputs
-        @serialize_function_outputs
-        @validate_outputs
-        def user_provided_handler_function(important, stuff):
-            if important:
-                serious_business(stuff)
-    """
-    def __init__(self, api, method, path, operation, resolver,
-                 app_security=None, security_schemes=None,
-                 validate_responses=False, strict_validation=False,
-                 randomize_endpoint=None, validator_map=None,
-                 pythonic_params=False, uri_parser_class=None,
-                 pass_context_arg_name=None):
-        """
-        :param api: api that this operation is attached to
-        :type api: apis.AbstractAPI
-        :param method: HTTP method
-        :type method: str
-        :param path:
-        :type path: str
-        :param operation: swagger operation object
-        :type operation: dict
-        :param resolver: Callable that maps operationID to a function
-        :param app_produces: list of content types the application can return by default
-        :param app_security: list of security rules the application uses by default
-        :type app_security: list
-        :param security_schemes: `Security Definitions Object
-            <https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#security-definitions-object>`_
-        :type security_schemes: dict
-        :param validate_responses: True enables validation. Validation errors generate HTTP 500 responses.
-        :type validate_responses: bool
-        :param strict_validation: True enables validation on invalid request parameters
-        :type strict_validation: bool
-        :param randomize_endpoint: number of random characters to append to operation name
-        :type randomize_endpoint: integer
-        :param validator_map: Custom validators for the types "parameter", "body" and "response".
-        :type validator_map: dict
-        :param pythonic_params: When True CamelCase parameters are converted to snake_case and an underscore is appended
-        to any shadowed built-ins
-        :type pythonic_params: bool
-        :param uri_parser_class: class to use for uri parsing
-        :type uri_parser_class: AbstractURIParser
-        :param pass_context_arg_name: If not None will try to inject the request context to the function using this
-        name.
-        :type pass_context_arg_name: str|None
-        """
-        self._api = api
-        self._method = method
-        self._path = path
-        self._operation = operation
-        self._resolver = resolver
-        self._security = app_security
-        self._security_schemes = security_schemes
-        self._validate_responses = validate_responses
-        self._strict_validation = strict_validation
-        self._pythonic_params = pythonic_params
-        self._uri_parser_class = uri_parser_class
-        self._pass_context_arg_name = pass_context_arg_name
-        self._randomize_endpoint = randomize_endpoint
-
-        self._operation_id = self._operation.get("operationId")
-        self._resolution = resolver.resolve(self)
-        self._operation_id = self._resolution.operation_id
-
-        self._responses = self._operation.get("responses", {})
-
-        self._validator_map = dict(VALIDATOR_MAP)
-        self._validator_map.update(validator_map or {})
-
-    @property
-    def method(self):
-        """
-        The HTTP method for this operation (ex. GET, POST)
-        """
-        return self._method
-
-    @property
-    def path(self):
-        """
-        The path of the operation, relative to the API base path
-        """
-        return self._path
-
-    @property
-    def responses(self):
-        """
-        Returns the responses for this operation
-        """
-        return self._responses
-
-    @property
-    def validator_map(self):
-        """
-        Validators to use for parameter, body, and response validation
-        """
-        return self._validator_map
-
-    @property
-    def operation_id(self):
-        """
-        The operation id used to indentify the operation internally to the app
-        """
-        return self._operation_id
-
-    @property
-    def randomize_endpoint(self):
-        """
-        number of random digits to generate and append to the operation_id.
-        """
-        return self._randomize_endpoint
-
-    @property
-    def router_controller(self):
-        """
-        The router controller to use (python module where handler functions live)
-        """
-        return self._router_controller
-
-    @property
-    def strict_validation(self):
-        """
-        If True, validate all requests against the spec
-        """
-        return self._strict_validation
-
-    @property
-    def pythonic_params(self):
-        """
-        If True, convert CamelCase into pythonic_variable_names
-        """
-        return self._pythonic_params
-
-    @property
-    def validate_responses(self):
-        """
-        If True, check the response against the response schema, and return an
-        error if the response does not validate.
-        """
-        return self._validate_responses
-
-    @staticmethod
-    def _get_file_arguments(files, arguments, has_kwargs=False):
-        return {k: v for k, v in files.items() if k in arguments or has_kwargs}
-
-    @abc.abstractmethod
-    def _get_val_from_param(self, value, query_defn):
-        """
-        Convert input parameters into the correct type
-        """
-
-    def _query_args_helper(self, query_defns, query_arguments,
-                           function_arguments, has_kwargs, sanitize):
-        res = {}
-        for key, value in query_arguments.items():
-            key = sanitize(key)
-            if not has_kwargs and key not in function_arguments:
-                logger.debug("Query Parameter '%s' not in function arguments", key)
-            else:
-                logger.debug("Query Parameter '%s' in function arguments", key)
-                try:
-                    query_defn = query_defns[key]
-                except KeyError:  # pragma: no cover
-                    logger.error("Function argument '{}' not defined in specification".format(key))
-                else:
-                    logger.debug('%s is a %s', key, query_defn)
-                    res.update({key: self._get_val_from_param(value, query_defn)})
-        return res
-
-    @abc.abstractmethod
-    def _get_query_arguments(self, query, arguments, has_kwargs, sanitize):
-        """
-        extract handler function arguments from the query parameters
-        """
-
-    @abc.abstractmethod
-    def _get_body_argument(self, body, arguments, has_kwargs, sanitize):
-        """
-        extract handler function arguments from the request body
-        """
-
-    def _get_path_arguments(self, path_params, sanitize):
-        """
-        extract handler function arguments from path parameters
-        """
-        kwargs = {}
-        path_defns = {p["name"]: p for p in self.parameters if p["in"] == "path"}
-        for key, value in path_params.items():
-            sanitized_key = sanitize(key)
-            if key in path_defns:
-                kwargs[sanitized_key] = self._get_val_from_param(value, path_defns[key])
-            else:  # Assume path params mechanism used for injection
-                kwargs[sanitized_key] = value
-        return kwargs
-
-    @abc.abstractproperty
-    def parameters(self):
-        """
-        Returns the parameters for this operation
-        """
-
-    @abc.abstractproperty
-    def produces(self):
-        """
-        Content-Types that the operation produces
-        """
-
-    @abc.abstractproperty
-    def consumes(self):
-        """
-        Content-Types that the operation consumes
-        """
-
-    @abc.abstractproperty
-    def body_schema(self):
-        """
-        The body schema definition for this operation.
-        """
-
-    @abc.abstractproperty
-    def body_definition(self):
-        """
-        The body definition for this operation.
-        :rtype: dict
-        """
-
-    def get_arguments(self, path_params, query_params, body, files, arguments,
-                      has_kwargs, sanitize):
-        """
-        get arguments for handler function
-        """
-        ret = {}
-        ret.update(self._get_path_arguments(path_params, sanitize))
-        ret.update(self._get_query_arguments(query_params, arguments,
-                                             has_kwargs, sanitize))
-
-        if self.method.upper() in ["PATCH", "POST", "PUT"]:
-            ret.update(self._get_body_argument(body, arguments,
-                                               has_kwargs, sanitize))
-            ret.update(self._get_file_arguments(files, arguments, has_kwargs))
-        return ret
-
-    def response_definition(self, status_code=None,
-                            content_type=None):
-        """
-        response definition for this endpoint
-        """
-        content_type = content_type or self.get_mimetype()
-        response_definition = self.responses.get(
-            str(status_code),
-            self.responses.get("default", {})
-        )
-        return response_definition
-
-    @abc.abstractmethod
-    def response_schema(self, status_code=None, content_type=None):
-        """
-        response schema for this endpoint
-        """
-
-    @abc.abstractmethod
-    def example_response(self, status_code=None, content_type=None):
-        """
-        Returns an example from the spec
-        """
-
-    @abc.abstractmethod
-    def get_path_parameter_types(self):
-        """
-        Returns the types for parameters in the path
-        """
-
-    @abc.abstractmethod
-    def with_definitions(self, schema):
-        """
-        Returns the given schema, but with the definitions from the spec
-        attached. This allows any remaining references to be resolved by a
-        validator (for example).
-        """
-
-    def get_mimetype(self):
-        """
-        If the endpoint has no 'produces' then the default is
-        'application/json'.
-
-        :rtype str
-        """
-        if all_json(self.produces):
-            try:
-                return self.produces[0]
-            except IndexError:
-                return DEFAULT_MIMETYPE
-        elif len(self.produces) == 1:
-            return self.produces[0]
-        else:
-            return DEFAULT_MIMETYPE
-
-    @property
-    def _uri_parsing_decorator(self):
-        """
-        Returns a decorator that parses request data and handles things like
-        array types, and duplicate parameter definitions.
-        """
-        return self._uri_parser_class(self.parameters, self.body_definition)
-
-    @property
-    def function(self):
-        """
-        Operation function with decorators
-
-        :rtype: types.FunctionType
-        """
-        function = parameter_to_arg(
-            self, self._resolution.function, self.pythonic_params,
-            self._pass_context_arg_name
-        )
-
-        if self.validate_responses:
-            logger.debug('... Response validation enabled.')
-            response_decorator = self.__response_validation_decorator
-            logger.debug('... Adding response decorator (%r)', response_decorator)
-            function = response_decorator(function)
-
-        produces_decorator = self.__content_type_decorator
-        logger.debug('... Adding produces decorator (%r)', produces_decorator)
-        function = produces_decorator(function)
-
-        for validation_decorator in self.__validation_decorators:
-            function = validation_decorator(function)
-
-        uri_parsing_decorator = self._uri_parsing_decorator
-        function = uri_parsing_decorator(function)
-
-        # NOTE: the security decorator should be applied last to check auth before anything else :-)
-        security_decorator = self.security_decorator
-        logger.debug('... Adding security decorator (%r)', security_decorator)
-        function = security_decorator(function)
-
-        function = self._request_response_decorator(function)
-
-        if UWSGIMetricsCollector.is_available():  # pragma: no cover
-            decorator = UWSGIMetricsCollector(self.path, self.method)
-            function = decorator(function)
-
-        return function
-
-    @property
-    def __content_type_decorator(self):
-        """
-        Get produces decorator.
-
-        If the operation mimetype format is json then the function return value is jsonified
-
-        From Swagger Specification:
-
-        **Produces**
-
-        A list of MIME types the operation can produce. This overrides the produces definition at the Swagger Object.
-        An empty value MAY be used to clear the global definition.
-
-        :rtype: types.FunctionType
-        """
-
-        logger.debug('... Produces: %s', self.produces, extra=vars(self))
-
-        mimetype = self.get_mimetype()
-        if all_json(self.produces):  # endpoint will return json
-            logger.debug('... Produces json', extra=vars(self))
-            # TODO: Refactor this.
-            return lambda f: f
-
-        elif len(self.produces) == 1:
-            logger.debug('... Produces %s', mimetype, extra=vars(self))
-            decorator = Produces(mimetype)
-            return decorator
-
-        else:
-            return BaseSerializer()
-
-    @property
-    def __validation_decorators(self):
-        """
-        :rtype: types.FunctionType
-        """
-        ParameterValidator = self.validator_map['parameter']
-        RequestBodyValidator = self.validator_map['body']
-        if self.parameters:
-            yield ParameterValidator(self.parameters,
-                                     self.api,
-                                     strict_validation=self.strict_validation)
-        if self.body_schema:
-            yield RequestBodyValidator(self.body_schema, self.consumes, self.api,
-                                       is_nullable(self.body_definition),
-                                       strict_validation=self.strict_validation)
-
-    @property
-    def __response_validation_decorator(self):
-        """
-        Get a decorator for validating the generated Response.
-        :rtype: types.FunctionType
-        """
-        ResponseValidator = self.validator_map['response']
-        return ResponseValidator(self, self.get_mimetype())
-
-    def json_loads(self, data):
-        """
-        A wrapper for calling the API specific JSON loader.
-
-        :param data: The JSON data in textual form.
-        :type data: bytes
-        """
-        return self.api.json_loads(data)
diff --git a/airflow/_vendor/connexion/operations/compat.py b/airflow/_vendor/connexion/operations/compat.py
deleted file mode 100644
index b6bb061..0000000
--- a/airflow/_vendor/connexion/operations/compat.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# This is a dummy module for backwards compatability with < v2.0
-from .secure import *  # noqa
-from .swagger2 import *  # noqa
diff --git a/airflow/_vendor/connexion/operations/openapi.py b/airflow/_vendor/connexion/operations/openapi.py
deleted file mode 100644
index 4ea6af7..0000000
--- a/airflow/_vendor/connexion/operations/openapi.py
+++ /dev/null
@@ -1,380 +0,0 @@
-import logging
-from copy import copy, deepcopy
-
-from airflow._vendor.connexion.operations.abstract import AbstractOperation
-
-from ..decorators.uri_parsing import OpenAPIURIParser
-from ..utils import deep_get, deep_merge, is_null, is_nullable, make_type
-
-logger = logging.getLogger("connexion.operations.openapi3")
-
-
-class OpenAPIOperation(AbstractOperation):
-
-    """
-    A single API operation on a path.
-    """
-
-    def __init__(self, api, method, path, operation, resolver, path_parameters=None,
-                 app_security=None, components=None, validate_responses=False,
-                 strict_validation=False, randomize_endpoint=None, validator_map=None,
-                 pythonic_params=False, uri_parser_class=None, pass_context_arg_name=None):
-        """
-        This class uses the OperationID identify the module and function that will handle the operation
-
-        From Swagger Specification:
-
-        **OperationID**
-
-        A friendly name for the operation. The id MUST be unique among all operations described in the API.
-        Tools and libraries MAY use the operation id to uniquely identify an operation.
-
-        :param method: HTTP method
-        :type method: str
-        :param path:
-        :type path: str
-        :param operation: swagger operation object
-        :type operation: dict
-        :param resolver: Callable that maps operationID to a function
-        :param path_parameters: Parameters defined in the path level
-        :type path_parameters: list
-        :param app_security: list of security rules the application uses by default
-        :type app_security: list
-        :param components: `Components Object
-            <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#componentsObject>`_
-        :type components: dict
-        :param validate_responses: True enables validation. Validation errors generate HTTP 500 responses.
-        :type validate_responses: bool
-        :param strict_validation: True enables validation on invalid request parameters
-        :type strict_validation: bool
-        :param randomize_endpoint: number of random characters to append to operation name
-        :type randomize_endpoint: integer
-        :param validator_map: Custom validators for the types "parameter", "body" and "response".
-        :type validator_map: dict
-        :param pythonic_params: When True CamelCase parameters are converted to snake_case and an underscore is appended
-        to any shadowed built-ins
-        :type pythonic_params: bool
-        :param uri_parser_class: class to use for uri parsing
-        :type uri_parser_class: AbstractURIParser
-        :param pass_context_arg_name: If not None will try to inject the request context to the function using this
-        name.
-        :type pass_context_arg_name: str|None
-        """
-        self.components = components or {}
-
-        def component_get(oas3_name):
-            return self.components.get(oas3_name, {})
-
-        # operation overrides globals
-        security_schemes = component_get('securitySchemes')
-        app_security = operation.get('security', app_security)
-        uri_parser_class = uri_parser_class or OpenAPIURIParser
-
-        self._router_controller = operation.get('x-openapi-router-controller')
-
-        super(OpenAPIOperation, self).__init__(
-            api=api,
-            method=method,
-            path=path,
-            operation=operation,
-            resolver=resolver,
-            app_security=app_security,
-            security_schemes=security_schemes,
-            validate_responses=validate_responses,
-            strict_validation=strict_validation,
-            randomize_endpoint=randomize_endpoint,
-            validator_map=validator_map,
-            pythonic_params=pythonic_params,
-            uri_parser_class=uri_parser_class,
-            pass_context_arg_name=pass_context_arg_name
-        )
-
-        self._definitions_map = {
-            'components': {
-                'schemas': component_get('schemas'),
-                'examples': component_get('examples'),
-                'requestBodies': component_get('requestBodies'),
-                'parameters': component_get('parameters'),
-                'securitySchemes': component_get('securitySchemes'),
-                'responses': component_get('responses'),
-                'headers': component_get('headers'),
-            }
-        }
-
-        self._request_body = operation.get('requestBody', {})
-
-        self._parameters = operation.get('parameters', [])
-        if path_parameters:
-            self._parameters += path_parameters
-
-        self._responses = operation.get('responses', {})
-
-        # TODO figure out how to support multiple mimetypes
-        # NOTE we currently just combine all of the possible mimetypes,
-        #      but we need to refactor to support mimetypes by response code
-        response_content_types = []
-        for _, defn in self._responses.items():
-            response_content_types += defn.get('content', {}).keys()
-        self._produces = response_content_types or ['application/json']
-
-        request_content = self._request_body.get('content', {})
-        self._consumes = list(request_content.keys()) or ['application/json']
-
-        logger.debug('consumes: %s' % self.consumes)
-        logger.debug('produces: %s' % self.produces)
-
-    @classmethod
-    def from_spec(cls, spec, api, path, method, resolver, *args, **kwargs):
-        return cls(
-            api,
-            method,
-            path,
-            spec.get_operation(path, method),
-            resolver=resolver,
-            path_parameters=spec.get_path_params(path),
-            app_security=spec.security,
-            components=spec.components,
-            *args,
-            **kwargs
-        )
-
-    @property
-    def request_body(self):
-        return self._request_body
-
-    @property
-    def parameters(self):
-        return self._parameters
-
-    @property
-    def consumes(self):
-        return self._consumes
-
-    @property
-    def produces(self):
-        return self._produces
-
-    def with_definitions(self, schema):
-        if self.components:
-            schema['schema']['components'] = self.components
-        return schema
-
-    def response_schema(self, status_code=None, content_type=None):
-        response_definition = self.response_definition(
-            status_code, content_type
-        )
-        content_definition = response_definition.get("content", response_definition)
-        content_definition = content_definition.get(content_type, content_definition)
-        if "schema" in content_definition:
-            return self.with_definitions(content_definition).get("schema", {})
-        return {}
-
-    def example_response(self, status_code=None, content_type=None):
-        """
-        Returns example response from spec
-        """
-        # simply use the first/lowest status code, this is probably 200 or 201
-        status_code = status_code or sorted(self._responses.keys())[0]
-
-        content_type = content_type or self.get_mimetype()
-        examples_path = [str(status_code), 'content', content_type, 'examples']
-        example_path = [str(status_code), 'content', content_type, 'example']
-        schema_example_path = [
-            str(status_code), 'content', content_type, 'schema', 'example'
-        ]
-        schema_path = [str(status_code), 'content', content_type, 'schema']
-
-        try:
-            status_code = int(status_code)
-        except ValueError:
-            status_code = 200
-        try:
-            # TODO also use example header?
-            return (
-                list(deep_get(self._responses, examples_path).values())[0]['value'],
-                status_code
-            )
-        except (KeyError, IndexError):
-            pass
-        try:
-            return (deep_get(self._responses, example_path), status_code)
-        except KeyError:
-            pass
-        try:
-            return (deep_get(self._responses, schema_example_path),
-                    status_code)
-        except KeyError:
-            pass
-
-        try:
-            return (self._nested_example(deep_get(self._responses, schema_path)),
-                    status_code)
-        except KeyError:
-            return (None, status_code)
-
-    def _nested_example(self, schema):
-        try:
-            return schema["example"]
-        except KeyError:
-            pass
-        try:
-            # Recurse if schema is an object
-            return {key: self._nested_example(value)
-                    for (key, value) in schema["properties"].items()}
-        except KeyError:
-            pass
-        try:
-            # Recurse if schema is an array
-            return [self._nested_example(schema["items"])]
-        except KeyError:
-            raise
-
-    def get_path_parameter_types(self):
-        types = {}
-        path_parameters = (p for p in self.parameters if p["in"] == "path")
-        for path_defn in path_parameters:
-            path_schema = path_defn["schema"]
-            if path_schema.get('type') == 'string' and path_schema.get('format') == 'path':
-                # path is special case for type 'string'
-                path_type = 'path'
-            else:
-                path_type = path_schema.get('type')
-            types[path_defn['name']] = path_type
-        return types
-
-    @property
-    def body_schema(self):
-        """
-        The body schema definition for this operation.
-        """
-        return self.body_definition.get('schema', {})
-
-    @property
-    def body_definition(self):
-        """
-        The body complete definition for this operation.
-
-        **There can be one "body" parameter at most.**
-
-        :rtype: dict
-        """
-        if self._request_body:
-            if len(self.consumes) > 1:
-                logger.warning(
-                    'this operation accepts multiple content types, using %s',
-                    self.consumes[0])
-            res = self._request_body.get('content', {}).get(self.consumes[0], {})
-            return self.with_definitions(res)
-        return {}
-
-    def _get_body_argument(self, body, arguments, has_kwargs, sanitize):
-        x_body_name = sanitize(self.body_schema.get('x-body-name', 'body'))
-        if is_nullable(self.body_schema) and is_null(body):
-            return {x_body_name: None}
-
-        default_body = self.body_schema.get('default', {})
-        body_props = {k: {"schema": v} for k, v
-                      in self.body_schema.get("properties", {}).items()}
-
-        # by OpenAPI specification `additionalProperties` defaults to `true`
-        # see: https://github.com/OAI/OpenAPI-Specification/blame/3.0.2/versions/3.0.2.md#L2305
-        additional_props = self.body_schema.get("additionalProperties", True)
-
-        if body is None:
-            body = deepcopy(default_body)
-
-        if self.body_schema.get("type") != "object":
-            if x_body_name in arguments or has_kwargs:
-                return {x_body_name: body}
-            return {}
-
-        body_arg = deepcopy(default_body)
-        body_arg.update(body or {})
-
-        res = {}
-        if body_props or additional_props:
-            res = self._get_typed_body_values(body_arg, body_props, additional_props)
-
-        if x_body_name in arguments or has_kwargs:
-            return {x_body_name: res}
-        return {}
-
-    def _get_typed_body_values(self, body_arg, body_props, additional_props):
-        """
-        Return a copy of the provided body_arg dictionary
-        whose values will have the appropriate types
-        as defined in the provided schemas.
-
-        :type body_arg: type dict
-        :type body_props: dict
-        :type additional_props: dict|bool
-        :rtype: dict
-        """
-        additional_props_defn = {"schema": additional_props} if isinstance(additional_props, dict) else None
-        res = {}
-
-        for key, value in body_arg.items():
-            try:
-                prop_defn = body_props[key]
-                res[key] = self._get_val_from_param(value, prop_defn)
-            except KeyError:  # pragma: no cover
-                if not additional_props:
-                    logger.error("Body property '{}' not defined in body schema".format(key))
-                    continue
-                if additional_props_defn is not None:
-                    value = self._get_val_from_param(value, additional_props_defn)
-                res[key] = value
-
-        return res
-
-    def _build_default_obj_recursive(self, _properties, res):
-        """ takes disparate and nested default keys, and builds up a default object
-        """
-        for key, prop in _properties.items():
-            if 'default' in prop and key not in res:
-                res[key] = copy(prop['default'])
-            elif prop.get('type') == 'object' and 'properties' in prop:
-                res.setdefault(key, {})
-                res[key] = self._build_default_obj_recursive(prop['properties'], res[key])
-        return res
-
-    def _get_default_obj(self, schema):
-        try:
-            return deepcopy(schema["default"])
-        except KeyError:
-            _properties = schema.get("properties", {})
-            return self._build_default_obj_recursive(_properties, {})
-
-    def _get_query_defaults(self, query_defns):
-        defaults = {}
-        for k, v in query_defns.items():
-            try:
-                if v["schema"]["type"] == "object":
-                    defaults[k] = self._get_default_obj(v["schema"])
-                else:
-                    defaults[k] = v["schema"]["default"]
-            except KeyError:
-                pass
-        return defaults
-
-    def _get_query_arguments(self, query, arguments, has_kwargs, sanitize):
-        query_defns = {sanitize(p["name"]): p
-                       for p in self.parameters
-                       if p["in"] == "query"}
-        default_query_params = self._get_query_defaults(query_defns)
-
-        query_arguments = deepcopy(default_query_params)
-        query_arguments = deep_merge(query_arguments, query)
-        return self._query_args_helper(query_defns, query_arguments,
-                                       arguments, has_kwargs, sanitize)
-
-    def _get_val_from_param(self, value, query_defn):
-        query_schema = query_defn["schema"]
-
-        if is_nullable(query_schema) and is_null(value):
-            return None
-
-        if query_schema["type"] == "array":
-            return [make_type(part, query_schema["items"]["type"]) for part in value]
-        else:
-            return make_type(value, query_schema["type"])
diff --git a/airflow/_vendor/connexion/operations/secure.py b/airflow/_vendor/connexion/operations/secure.py
deleted file mode 100644
index eef5e99..0000000
--- a/airflow/_vendor/connexion/operations/secure.py
+++ /dev/null
@@ -1,164 +0,0 @@
-import functools
-import logging
-
-from ..decorators.decorator import RequestResponseDecorator
-from ..decorators.security import (get_apikeyinfo_func, get_basicinfo_func,
-                                   get_bearerinfo_func,
-                                   get_scope_validate_func, get_tokeninfo_func,
-                                   security_deny, security_passthrough,
-                                   verify_apikey, verify_basic, verify_bearer,
-                                   verify_none, verify_oauth, verify_security)
-
-logger = logging.getLogger("connexion.operations.secure")
-
-DEFAULT_MIMETYPE = 'application/json'
-
-
-class SecureOperation(object):
-
-    def __init__(self, api, security, security_schemes):
-        """
-        :param security: list of security rules the application uses by default
-        :type security: list
-        :param security_definitions: `Security Definitions Object
-            <https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#security-definitions-object>`_
-        :type security_definitions: dict
-        """
-        self._api = api
-        self._security = security
-        self._security_schemes = security_schemes
-
-    @property
-    def api(self):
-        return self._api
-
-    @property
-    def security(self):
-        return self._security
-
-    @property
-    def security_schemes(self):
-        return self._security_schemes
-
-    @property
-    def security_decorator(self):
-        """
-        Gets the security decorator for operation
-
-        From Swagger Specification:
-
-        **Security Definitions Object**
-
-        A declaration of the security schemes available to be used in the specification.
-
-        This does not enforce the security schemes on the operations and only serves to provide the relevant details
-        for each scheme.
-
-
-        **Operation Object -> security**
-
-        A declaration of which security schemes are applied for this operation. The list of values describes alternative
-        security schemes that can be used (that is, there is a logical OR between the security requirements).
-        This definition overrides any declared top-level security. To remove a top-level security declaration,
-        an empty array can be used.
-
-
-        **Security Requirement Object**
-
-        Lists the required security schemes to execute this operation. The object can have multiple security schemes
-        declared in it which are all required (that is, there is a logical AND between the schemes).
-
-        The name used for each property **MUST** correspond to a security scheme declared in the Security Definitions.
-
-        :rtype: types.FunctionType
-        """
-        logger.debug('... Security: %s', self.security, extra=vars(self))
-        if not self.security:
-            return security_passthrough
-
-        auth_funcs = []
-        required_scopes = None
-        for security_req in self.security:
-            if not security_req:
-                auth_funcs.append(verify_none())
-                continue
-            elif len(security_req) > 1:
-                logger.warning("... More than one security scheme in security requirement defined. "
-                               "**DENYING ALL REQUESTS**", extra=vars(self))
-                return security_deny
-
-            scheme_name, scopes = next(iter(security_req.items()))
-            security_scheme = self.security_schemes[scheme_name]
-
-            if security_scheme['type'] == 'oauth2':
-                required_scopes = scopes
-                token_info_func = get_tokeninfo_func(security_scheme)
-                scope_validate_func = get_scope_validate_func(security_scheme)
-                if not token_info_func:
-                    logger.warning("... x-tokenInfoFunc missing", extra=vars(self))
-                    continue
-
-                auth_funcs.append(verify_oauth(token_info_func, scope_validate_func))
-
-            # Swagger 2.0
-            elif security_scheme['type'] == 'basic':
-                basic_info_func = get_basicinfo_func(security_scheme)
-                if not basic_info_func:
-                    logger.warning("... x-basicInfoFunc missing", extra=vars(self))
-                    continue
-
-                auth_funcs.append(verify_basic(basic_info_func))
-
-            # OpenAPI 3.0.0
-            elif security_scheme['type'] == 'http':
-                scheme = security_scheme['scheme'].lower()
-                if scheme == 'basic':
-                    basic_info_func = get_basicinfo_func(security_scheme)
-                    if not basic_info_func:
-                        logger.warning("... x-basicInfoFunc missing", extra=vars(self))
-                        continue
-
-                    auth_funcs.append(verify_basic(basic_info_func))
-                elif scheme == 'bearer':
-                    bearer_info_func = get_bearerinfo_func(security_scheme)
-                    if not bearer_info_func:
-                        logger.warning("... x-bearerInfoFunc missing", extra=vars(self))
-                        continue
-                    auth_funcs.append(verify_bearer(bearer_info_func))
-                else:
-                    logger.warning("... Unsupported http authorization scheme %s" % scheme, extra=vars(self))
-
-            elif security_scheme['type'] == 'apiKey':
-                scheme = security_scheme.get('x-authentication-scheme', '').lower()
-                if scheme == 'bearer':
-                    bearer_info_func = get_bearerinfo_func(security_scheme)
-                    if not bearer_info_func:
-                        logger.warning("... x-bearerInfoFunc missing", extra=vars(self))
-                        continue
-                    auth_funcs.append(verify_bearer(bearer_info_func))
-                else:
-                    apikey_info_func = get_apikeyinfo_func(security_scheme)
-                    if not apikey_info_func:
-                        logger.warning("... x-apikeyInfoFunc missing", extra=vars(self))
-                        continue
-
-                    auth_funcs.append(verify_apikey(apikey_info_func, security_scheme['in'], security_scheme['name']))
-
-            else:
-                logger.warning("... Unsupported security scheme type %s" % security_scheme['type'], extra=vars(self))
-
-        return functools.partial(verify_security, auth_funcs, required_scopes)
-
-    def get_mimetype(self):
-        return DEFAULT_MIMETYPE
-
-    @property
-    def _request_response_decorator(self):
-        """
-        Guarantees that instead of the internal representation of the
-        operation handler response
-        (connexion.lifecycle.ConnexionRequest) a framework specific
-        object is returned.
-        :rtype: types.FunctionType
-        """
-        return RequestResponseDecorator(self.api, self.get_mimetype())
diff --git a/airflow/_vendor/connexion/operations/swagger2.py b/airflow/_vendor/connexion/operations/swagger2.py
deleted file mode 100644
index 1b4a79d..0000000
--- a/airflow/_vendor/connexion/operations/swagger2.py
+++ /dev/null
@@ -1,310 +0,0 @@
-import logging
-from copy import deepcopy
-
-from airflow._vendor.connexion.operations.abstract import AbstractOperation
-
-from ..decorators.uri_parsing import Swagger2URIParser
-from ..exceptions import InvalidSpecification
-from ..utils import deep_get, is_null, is_nullable, make_type
-
-logger = logging.getLogger("connexion.operations.swagger2")
-
-
-class Swagger2Operation(AbstractOperation):
-
-    """
-    Exposes a Swagger 2.0 operation under the AbstractOperation interface.
-    The primary purpose of this class is to provide the `function()` method
-    to the API. A Swagger2Operation is plugged into the API with the provided
-    (path, method) pair. It resolves the handler function for this operation
-    with the provided resolver, and wraps the handler function with multiple
-    decorators that provide security, validation, serialization,
-    and deserialization.
-    """
-
-    def __init__(self, api, method, path, operation, resolver, app_produces, app_consumes,
-                 path_parameters=None, app_security=None, security_definitions=None,
-                 definitions=None, parameter_definitions=None,
-                 response_definitions=None, validate_responses=False, strict_validation=False,
-                 randomize_endpoint=None, validator_map=None, pythonic_params=False,
-                 uri_parser_class=None, pass_context_arg_name=None):
-        """
-        :param api: api that this operation is attached to
-        :type api: apis.AbstractAPI
-        :param method: HTTP method
-        :type method: str
-        :param path: relative path to this operation
-        :type path: str
-        :param operation: swagger operation object
-        :type operation: dict
-        :param resolver: Callable that maps operationID to a function
-        :type resolver: resolver.Resolver
-        :param app_produces: list of content types the application can return by default
-        :type app_produces: list
-        :param app_consumes: list of content types the application consumes by default
-        :type app_consumes: list
-        :param path_parameters: Parameters defined in the path level
-        :type path_parameters: list
-        :param app_security: list of security rules the application uses by default
-        :type app_security: list
-        :param security_definitions: `Security Definitions Object
-            <https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#security-definitions-object>`_
-        :type security_definitions: dict
-        :param definitions: `Definitions Object
-            <https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#definitionsObject>`_
-        :type definitions: dict
-        :param parameter_definitions: Global parameter definitions
-        :type parameter_definitions: dict
-        :param response_definitions: Global response definitions
-        :type response_definitions: dict
-        :param validate_responses: True enables validation. Validation errors generate HTTP 500 responses.
-        :type validate_responses: bool
-        :param strict_validation: True enables validation on invalid request parameters
-        :type strict_validation: bool
-        :param randomize_endpoint: number of random characters to append to operation name
-        :type randomize_endpoint: integer
-        :param validator_map: Custom validators for the types "parameter", "body" and "response".
-        :type validator_map: dict
-        :param pythonic_params: When True CamelCase parameters are converted to snake_case and an underscore is appended
-        to any shadowed built-ins
-        :type pythonic_params: bool
-        :param uri_parser_class: class to use for uri parsing
-        :type uri_parser_class: AbstractURIParser
-        :param pass_context_arg_name: If not None will try to inject the request context to the function using this
-        name.
-        :type pass_context_arg_name: str|None
-        """
-        app_security = operation.get('security', app_security)
-        uri_parser_class = uri_parser_class or Swagger2URIParser
-
-        self._router_controller = operation.get('x-swagger-router-controller')
-
-        super(Swagger2Operation, self).__init__(
-            api=api,
-            method=method,
-            path=path,
-            operation=operation,
-            resolver=resolver,
-            app_security=app_security,
-            security_schemes=security_definitions,
-            validate_responses=validate_responses,
-            strict_validation=strict_validation,
-            randomize_endpoint=randomize_endpoint,
-            validator_map=validator_map,
-            pythonic_params=pythonic_params,
-            uri_parser_class=uri_parser_class,
-            pass_context_arg_name=pass_context_arg_name
-        )
-
-        self._produces = operation.get('produces', app_produces)
-        self._consumes = operation.get('consumes', app_consumes)
-
-        self.definitions = definitions or {}
-
-        self.definitions_map = {
-            'definitions': self.definitions,
-            'parameters': parameter_definitions,
-            'responses': response_definitions
-        }
-
-        self._parameters = operation.get('parameters', [])
-        if path_parameters:
-            self._parameters += path_parameters
-
-        self._responses = operation.get('responses', {})
-        logger.debug(self._responses)
-
-        logger.debug('consumes: %s', self.consumes)
-        logger.debug('produces: %s', self.produces)
-
-    @classmethod
-    def from_spec(cls, spec, api, path, method, resolver, *args, **kwargs):
-        return cls(
-            api,
-            method,
-            path,
-            spec.get_operation(path, method),
-            resolver=resolver,
-            path_parameters=spec.get_path_params(path),
-            app_security=spec.security,
-            app_produces=spec.produces,
-            app_consumes=spec.consumes,
-            security_definitions=spec.security_definitions,
-            definitions=spec.definitions,
-            parameter_definitions=spec.parameter_definitions,
-            response_definitions=spec.response_definitions,
-            *args,
-            **kwargs
-        )
-
-    @property
-    def parameters(self):
-        return self._parameters
-
-    @property
-    def consumes(self):
-        return self._consumes
-
-    @property
-    def produces(self):
-        return self._produces
-
-    def get_path_parameter_types(self):
-        types = {}
-        path_parameters = (p for p in self.parameters if p["in"] == "path")
-        for path_defn in path_parameters:
-            if path_defn.get('type') == 'string' and path_defn.get('format') == 'path':
-                # path is special case for type 'string'
-                path_type = 'path'
-            else:
-                path_type = path_defn.get('type')
-            types[path_defn['name']] = path_type
-        return types
-
-    def with_definitions(self, schema):
-        if "schema" in schema:
-            schema['schema']['definitions'] = self.definitions
-        return schema
-
-    def response_schema(self, status_code=None, content_type=None):
-        response_definition = self.response_definition(
-            status_code, content_type
-        )
-        return self.with_definitions(response_definition.get("schema", {}))
-
-    def example_response(self, status_code=None, *args, **kwargs):
-        """
-        Returns example response from spec
-        """
-        # simply use the first/lowest status code, this is probably 200 or 201
-        status_code = status_code or sorted(self._responses.keys())[0]
-        examples_path = [str(status_code), 'examples']
-        schema_example_path = [str(status_code), 'schema', 'example']
-        schema_path = [str(status_code), 'schema']
-
-        try:
-            status_code = int(status_code)
-        except ValueError:
-            status_code = 200
-        try:
-            return (
-                list(deep_get(self._responses, examples_path).values())[0],
-                status_code
-            )
-        except KeyError:
-            pass
-        try:
-            return (deep_get(self._responses, schema_example_path),
-                    status_code)
-        except KeyError:
-            pass
-
-        try:
-            return (self._nested_example(deep_get(self._responses, schema_path)),
-                    status_code)
-        except KeyError:
-            return (None, status_code)
-
-    def _nested_example(self, schema):
-        try:
-            return schema["example"]
-        except KeyError:
-            pass
-        try:
-            # Recurse if schema is an object
-            return {key: self._nested_example(value)
-                    for (key, value) in schema["properties"].items()}
-        except KeyError:
-            pass
-        try:
-            # Recurse if schema is an array
-            return [self._nested_example(schema["items"])]
-        except KeyError:
-            raise
-
-    @property
-    def body_schema(self):
-        """
-        The body schema definition for this operation.
-        """
-        return self.with_definitions(self.body_definition).get('schema', {})
-
-    @property
-    def body_definition(self):
-        """
-        The body complete definition for this operation.
-
-        **There can be one "body" parameter at most.**
-
-        :rtype: dict
-        """
-        body_parameters = [p for p in self.parameters if p['in'] == 'body']
-        if len(body_parameters) > 1:
-            raise InvalidSpecification(
-                "{method} {path} There can be one 'body' parameter at most".format(
-                    method=self.method,
-                    path=self.path))
-        return body_parameters[0] if body_parameters else {}
-
-    def _get_query_arguments(self, query, arguments, has_kwargs, sanitize):
-        query_defns = {sanitize(p["name"]): p
-                       for p in self.parameters
-                       if p["in"] == "query"}
-        default_query_params = {k: v['default']
-                                for k, v in query_defns.items()
-                                if 'default' in v}
-        query_arguments = deepcopy(default_query_params)
-        query_arguments.update(query)
-        return self._query_args_helper(query_defns, query_arguments,
-                                       arguments, has_kwargs, sanitize)
-
-    def _get_body_argument(self, body, arguments, has_kwargs, sanitize):
-        kwargs = {}
-        body_parameters = [p for p in self.parameters if p['in'] == 'body'] or [{}]
-        if body is None:
-            body = deepcopy(body_parameters[0].get('schema', {}).get('default'))
-        body_name = sanitize(body_parameters[0].get('name'))
-
-        form_defns = {sanitize(p['name']): p
-                      for p in self.parameters
-                      if p['in'] == 'formData'}
-
-        default_form_params = {k: v['default']
-                               for k, v in form_defns.items()
-                               if 'default' in v}
-
-        # Add body parameters
-        if body_name:
-            if not has_kwargs and body_name not in arguments:
-                logger.debug("Body parameter '%s' not in function arguments", body_name)
-            else:
-                logger.debug("Body parameter '%s' in function arguments", body_name)
-                kwargs[body_name] = body
-
-        # Add formData parameters
-        form_arguments = deepcopy(default_form_params)
-        if form_defns and body:
-            form_arguments.update(body)
-        for key, value in form_arguments.items():
-            if not has_kwargs and key not in arguments:
-                logger.debug("FormData parameter '%s' not in function arguments", key)
-            else:
-                logger.debug("FormData parameter '%s' in function arguments", key)
-                try:
-                    form_defn = form_defns[key]
-                except KeyError:  # pragma: no cover
-                    logger.error("Function argument '{}' not defined in specification".format(key))
-                else:
-                    kwargs[key] = self._get_val_from_param(value, form_defn)
-        return kwargs
-
-    def _get_val_from_param(self, value, query_defn):
-        if is_nullable(query_defn) and is_null(value):
-            return None
-
-        query_schema = query_defn
-
-        if query_schema["type"] == "array":
-            return [make_type(part, query_defn["items"]["type"]) for part in value]
-        else:
-            return make_type(value, query_defn["type"])
diff --git a/airflow/_vendor/connexion/options.py b/airflow/_vendor/connexion/options.py
deleted file mode 100644
index 9043323..0000000
--- a/airflow/_vendor/connexion/options.py
+++ /dev/null
@@ -1,144 +0,0 @@
-import logging
-import pathlib
-from typing import Optional  # NOQA
-
-try:
-    from swagger_ui_bundle import (swagger_ui_2_path,
-                                   swagger_ui_3_path)
-except ImportError:
-    swagger_ui_2_path = swagger_ui_3_path = None
-
-MODULE_PATH = pathlib.Path(__file__).absolute().parent
-NO_UI_MSG = """The swagger_ui directory could not be found.
-    Please install connexion with extra install: pip install connexion[swagger-ui]
-    or provide the path to your local installation by passing swagger_path=<your path>
-"""
-
-logger = logging.getLogger("connexion.options")
-
-
-class ConnexionOptions(object):
-
-    def __init__(self, options=None, oas_version=(2,)):
-        self._options = {}
-        self.oas_version = oas_version
-        if self.oas_version >= (3, 0, 0):
-            self.openapi_spec_name = '/openapi.json'
-            self.swagger_ui_local_path = swagger_ui_3_path
-        else:
-            self.openapi_spec_name = '/swagger.json'
-            self.swagger_ui_local_path = swagger_ui_2_path
-
-        if options:
-            self._options.update(filter_values(options))
-
-    def extend(self, new_values=None):
-        # type: (Optional[dict]) -> ConnexionOptions
-        """
-        Return a new instance of `ConnexionOptions` using as default the currently
-        defined options.
-        """
-        if new_values is None:
-            new_values = {}
-
-        options = dict(self._options)
-        options.update(filter_values(new_values))
-        return ConnexionOptions(options, self.oas_version)
-
-    def as_dict(self):
-        return self._options
-
-    @property
-    def openapi_spec_available(self):
-        # type: () -> bool
-        """
-        Whether to make available the OpenAPI Specification under
-        `openapi_spec_path`.
-
-        Default: True
-        """
-        deprecated_option = self._options.get('swagger_json', True)
-        serve_spec = self._options.get('serve_spec', deprecated_option)
-        if 'swagger_json' in self._options:
-            deprecation_warning = ("The 'swagger_json' option is deprecated. "
-                                   "Please use 'serve_spec' instead")
-            logger.warning(deprecation_warning)
-        return serve_spec
-
-    @property
-    def openapi_console_ui_available(self):
-        # type: () -> bool
-        """
-        Whether to make the OpenAPI Console UI available under the path
-        defined in `openapi_console_ui_path` option.
-
-        Default: True
-        """
-        if (self._options.get('swagger_ui', True) and
-                self.openapi_console_ui_from_dir is None):
-            logger.warning(NO_UI_MSG)
-            return False
-        return self._options.get('swagger_ui', True)
-
-    @property
-    def openapi_spec_path(self):
-        # type: () -> str
-        """
-        Path to mount the OpenAPI Console UI and make it accessible via a browser.
-
-        Default: /openapi.json for openapi3, otherwise /swagger.json
-        """
-        return self._options.get('openapi_spec_path', self.openapi_spec_name)
-
-    @property
-    def openapi_console_ui_path(self):
-        # type: () -> str
-        """
-        Path to mount the OpenAPI Console UI and make it accessible via a browser.
-
-        Default: /ui
-        """
-        return self._options.get('swagger_url', '/ui')
-
-    @property
-    def openapi_console_ui_from_dir(self):
-        # type: () -> str
-        """
-        Custom OpenAPI Console UI directory from where Connexion will serve
-        the static files.
-
-        Default: Connexion's vendored version of the OpenAPI Console UI.
-        """
-        return self._options.get('swagger_path', self.swagger_ui_local_path)
-
-    @property
-    def openapi_console_ui_config(self):
-        # type: () -> dict
-        """
-        Custom OpenAPI Console UI config.
-
-        Default: None
-        """
-        return self._options.get('swagger_ui_config', None)
-
-    @property
-    def uri_parser_class(self):
-        # type: () -> AbstractURIParser
-        """
-        The class to use for parsing URIs into path and query parameters.
-        Default: None
-        """
-        return self._options.get('uri_parser_class', None)
-
-
-def filter_values(dictionary):
-    # type: (dict) -> dict
-    """
-    Remove `None` value entries in the dictionary.
-
-    :param dictionary:
-    :return:
-    """
-    return dict([(key, value)
-                 for key, value in dictionary.items()
-                 if value is not None])
diff --git a/airflow/_vendor/connexion/problem.py b/airflow/_vendor/connexion/problem.py
deleted file mode 100644
index c55b4be..0000000
--- a/airflow/_vendor/connexion/problem.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from .lifecycle import ConnexionResponse
-
-
-def problem(status, title, detail, type=None, instance=None, headers=None, ext=None):
-    """
-    Returns a `Problem Details <https://tools.ietf.org/html/draft-ietf-appsawg-http-problem-00>`_ error response.
-
-
-    :param status: The HTTP status code generated by the origin server for this occurrence of the problem.
-    :type status: int
-    :param title: A short, human-readable summary of the problem type.  It SHOULD NOT change from occurrence to
-                  occurrence of the problem, except for purposes of localisation.
-    :type title: str
-    :param detail: An human readable explanation specific to this occurrence of the problem.
-    :type detail: str
-    :param type: An absolute URI that identifies the problem type.  When dereferenced, it SHOULD provide human-readable
-                 documentation for the problem type (e.g., using HTML).  When this member is not present its value is
-                 assumed to be "about:blank".
-    :type: type: str
-    :param instance: An absolute URI that identifies the specific occurrence of the problem.  It may or may not yield
-                     further information if dereferenced.
-    :type instance: str
-    :param headers: HTTP headers to include in the response
-    :type headers: dict | None
-    :param ext: Extension members to include in the body
-    :type ext: dict | None
-    :return: error response
-    :rtype: ConnexionResponse
-    """
-    if not type:
-        type = 'about:blank'
-
-    problem_response = {'type': type, 'title': title, 'detail': detail, 'status': status}
-    if instance:
-        problem_response['instance'] = instance
-    if ext:
-        problem_response.update(ext)
-
-    mimetype = content_type = 'application/problem+json'
-    return ConnexionResponse(status, mimetype, content_type,
-                             body=problem_response,
-                             headers=headers)
diff --git a/airflow/_vendor/connexion/resolver.py b/airflow/_vendor/connexion/resolver.py
deleted file mode 100644
index bdfd69b..0000000
--- a/airflow/_vendor/connexion/resolver.py
+++ /dev/null
@@ -1,192 +0,0 @@
-import logging
-import re
-import sys
-
-from airflow._vendor.connexion import utils
-from airflow._vendor.connexion.exceptions import ResolverError
-
-logger = logging.getLogger('connexion.resolver')
-
-
-class Resolution(object):
-    def __init__(self, function, operation_id):
-        """
-        Represents the result of operation resolution
-
-        :param function: The endpoint function
-        :type function: types.FunctionType
-        """
-        self.function = function
-        self.operation_id = operation_id
-
-
-class Resolver(object):
-    def __init__(self, function_resolver=utils.get_function_from_name):
-        """
-        Standard resolver
-
-        :param function_resolver: Function that resolves functions using an operationId
-        :type function_resolver: types.FunctionType
-        """
-        self.function_resolver = function_resolver
-
-    def resolve(self, operation):
-        """
-        Default operation resolver
-
-        :type operation: connexion.operations.AbstractOperation
-        """
-        operation_id = self.resolve_operation_id(operation)
-        return Resolution(self.resolve_function_from_operation_id(operation_id), operation_id)
-
-    def resolve_operation_id(self, operation):
-        """
-        Default operationId resolver
-
-        :type operation: connexion.operations.AbstractOperation
-        """
-        operation_id = operation.operation_id
-        router_controller = operation.router_controller
-        if operation.router_controller is None:
-            return operation_id
-        return '{}.{}'.format(router_controller, operation_id)
-
-    def resolve_function_from_operation_id(self, operation_id):
-        """
-        Invokes the function_resolver
-
-        :type operation_id: str
-        """
-        try:
-            return self.function_resolver(operation_id)
-        except ImportError as e:
-            msg = 'Cannot resolve operationId "{}"! Import error was "{}"'.format(operation_id, str(e))
-            raise ResolverError(msg, sys.exc_info())
-        except (AttributeError, ValueError) as e:
-            raise ResolverError(str(e), sys.exc_info())
-
-
-class RestyResolver(Resolver):
-    """
-    Resolves endpoint functions using REST semantics (unless overridden by specifying operationId)
-    """
-
-    def __init__(self, default_module_name, collection_endpoint_name='search'):
-        """
-        :param default_module_name: Default module name for operations
-        :type default_module_name: str
-        """
-        Resolver.__init__(self)
-        self.default_module_name = default_module_name
-        self.collection_endpoint_name = collection_endpoint_name
-
-    def resolve_operation_id(self, operation):
-        """
-        Resolves the operationId using REST semantics unless explicitly configured in the spec
-
-        :type operation: connexion.operations.AbstractOperation
-        """
-        if operation.operation_id:
-            return Resolver.resolve_operation_id(self, operation)
-
-        return self.resolve_operation_id_using_rest_semantics(operation)
-
-    def resolve_operation_id_using_rest_semantics(self, operation):
-        """
-        Resolves the operationId using REST semantics
-
-        :type operation: connexion.operations.AbstractOperation
-        """
-        path_match = re.search(
-            r'^/?(?P<resource_name>([\w\-](?<!/))*)(?P<trailing_slash>/*)(?P<extended_path>.*)$', operation.path
-        )
-
-        def get_controller_name():
-            x_router_controller = operation.router_controller
-
-            name = self.default_module_name
-            resource_name = path_match.group('resource_name')
-
-            if x_router_controller:
-                name = x_router_controller
-
-            elif resource_name:
-                resource_controller_name = resource_name.replace('-', '_')
-                name += '.' + resource_controller_name
-
-            return name
-
-        def get_function_name():
-            method = operation.method
-
-            is_collection_endpoint = \
-                method.lower() == 'get' \
-                and path_match.group('resource_name') \
-                and not path_match.group('extended_path')
-
-            return self.collection_endpoint_name if is_collection_endpoint else method.lower()
-
-        return '{}.{}'.format(get_controller_name(), get_function_name())
-
-
-class MethodViewResolver(RestyResolver):
-    """
-    Resolves endpoint functions based on Flask's MethodView semantics, e.g. ::
-
-            paths:
-                /foo_bar:
-                    get:
-                        # Implied function call: api.FooBarView().get
-
-            class FooBarView(MethodView):
-                def get(self):
-                    return ...
-                def post(self):
-                    return ...
-    """
-
-    def resolve_operation_id(self, operation):
-        """
-        Resolves the operationId using REST semantics unless explicitly configured in the spec
-        Once resolved with REST semantics the view_name is capitalised and has 'View' added
-        to it so it now matches the Class names of the MethodView
-
-        :type operation: connexion.operations.AbstractOperation
-        """
-        if operation.operation_id:
-            # If operation_id is defined then use the higher level API to resolve
-            return RestyResolver.resolve_operation_id(self, operation)
-
-        # Use RestyResolver to get operation_id for us (follow their naming conventions/structure)
-        operation_id = self.resolve_operation_id_using_rest_semantics(operation)
-        module_name, view_base, meth_name = operation_id.rsplit('.', 2)
-        view_name = view_base[0].upper() + view_base[1:] + 'View'
-
-        return "{}.{}.{}".format(module_name, view_name, meth_name)
-
-    def resolve_function_from_operation_id(self, operation_id):
-        """
-        Invokes the function_resolver
-
-        :type operation_id: str
-        """
-
-        try:
-            module_name, view_name, meth_name = operation_id.rsplit('.', 2)
-            if operation_id and not view_name.endswith('View'):
-                # If operation_id is not a view then assume it is a standard function
-                return self.function_resolver(operation_id)
-
-            mod = __import__(module_name, fromlist=[view_name])
-            view_cls = getattr(mod, view_name)
-            # Find the class and instantiate it
-            view = view_cls()
-            func = getattr(view, meth_name)
-            # Return the method function of the class
-            return func
-        except ImportError as e:
-            msg = 'Cannot resolve operationId "{}"! Import error was "{}"'.format(
-                operation_id, str(e))
-            raise ResolverError(msg, sys.exc_info())
-        except (AttributeError, ValueError) as e:
-            raise ResolverError(str(e), sys.exc_info())
diff --git a/airflow/_vendor/connexion/setup.cfg b/airflow/_vendor/connexion/setup.cfg
deleted file mode 100644
index adf5ed7..0000000
--- a/airflow/_vendor/connexion/setup.cfg
+++ /dev/null
@@ -1,7 +0,0 @@
-[bdist_wheel]
-universal = 1
-
-[egg_info]
-tag_build = 
-tag_date = 0
-
diff --git a/airflow/_vendor/connexion/setup.py b/airflow/_vendor/connexion/setup.py
deleted file mode 100755
index d329556..0000000
--- a/airflow/_vendor/connexion/setup.py
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-import inspect
-import os
-import sys
-
-from setuptools import find_packages, setup
-from setuptools.command.test import test as TestCommand
-
-__location__ = os.path.join(os.getcwd(), os.path.dirname(inspect.getfile(inspect.currentframe())))
-
-
-def read_version(package):
-    with open(os.path.join(package, '__init__.py'), 'r') as fd:
-        for line in fd:
-            if line.startswith('__version__ = '):
-                return line.split()[-1].strip().strip("'")
-
-
-version = read_version('connexion')
-
-install_requires = [
-    'clickclick>=1.2',
-    'jsonschema>=2.5.1',
-    'PyYAML>=5.1',
-    'requests>=2.9.1',
-    'inflection>=0.3.1',
-    'openapi-spec-validator>=0.2.4',
-]
-
-swagger_ui_require = 'swagger-ui-bundle>=0.0.2'
-flask_require = 'flask>=1.0.4'
-aiohttp_require = [
-    'aiohttp>=2.3.10',
-    'aiohttp-jinja2>=0.14.0'
-]
-
-tests_require = [
-    'decorator',
-    'pytest',
-    'pytest-cov',
-    'testfixtures',
-    flask_require,
-    swagger_ui_require
-]
-
-tests_require.extend(aiohttp_require)
-tests_require.append('pytest-aiohttp')
-tests_require.append('aiohttp-remotes')
-
-
-class PyTest(TestCommand):
-
-    user_options = [('cov-html=', None, 'Generate junit html report')]
-
-    def initialize_options(self):
-        TestCommand.initialize_options(self)
-        self.cov = None
-        self.pytest_args = ['--cov', 'connexion', '--cov-report', 'term-missing',
-                            '--cov-config=py3-coveragerc', '-v']
-        self.cov_html = False
-
-    def finalize_options(self):
-        TestCommand.finalize_options(self)
-        if self.cov_html:
-            self.pytest_args.extend(['--cov-report', 'html'])
-        self.pytest_args.extend(['tests'])
-
-    def run_tests(self):
-        import pytest
-
-        errno = pytest.main(self.pytest_args)
-        sys.exit(errno)
-
-
-def readme():
-    try:
-        return open('README.rst', encoding='utf-8').read()
-    except TypeError:
-        return open('README.rst').read()
-
-
-setup(
-    name='connexion',
-    packages=find_packages(),
-    version=version,
-    description='Connexion - API first applications with OpenAPI/Swagger and Flask',
-    long_description=readme(),
-    author='Zalando SE',
-    url='https://github.com/zalando/connexion',
-    keywords='openapi oai swagger rest api oauth flask microservice framework',
-    license='Apache License Version 2.0',
-    setup_requires=['flake8'],
-    python_requires=">=3.6",
-    install_requires=install_requires + [flask_require],
-    tests_require=tests_require,
-    extras_require={
-        'tests': tests_require,
-        'flask': flask_require,
-        'swagger-ui': swagger_ui_require,
-        'aiohttp': aiohttp_require
-    },
-    cmdclass={'test': PyTest},
-    test_suite='tests',
-    classifiers=[
-        'Programming Language :: Python',
-        'Programming Language :: Python :: 3.6',
-        'Programming Language :: Python :: 3.7',
-        'Programming Language :: Python :: 3.8',
-        'Development Status :: 5 - Production/Stable',
-        'Intended Audience :: Developers',
-        'Operating System :: OS Independent',
-        'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
-        'Topic :: Software Development :: Libraries :: Application Frameworks'
-    ],
-    include_package_data=True,  # needed to include swagger-ui (see MANIFEST.in)
-    entry_points={'console_scripts': ['connexion = connexion.cli:main']}
-)
diff --git a/airflow/_vendor/connexion/spec.py b/airflow/_vendor/connexion/spec.py
deleted file mode 100644
index 5ab7e0c..0000000
--- a/airflow/_vendor/connexion/spec.py
+++ /dev/null
@@ -1,262 +0,0 @@
-import abc
-import copy
-import pathlib
-
-import jinja2
-import yaml
-from openapi_spec_validator.exceptions import OpenAPIValidationError
-from urllib.parse import urlsplit
-
-from .exceptions import InvalidSpecification
-from .json_schema import resolve_refs
-from .operations import OpenAPIOperation, Swagger2Operation
-from .utils import deep_get
-
-try:
-    import collections.abc as collections_abc  # python 3.3+
-except ImportError:
-    import collections as collections_abc
-
-
-NO_SPEC_VERSION_ERR_MSG = """Unable to get the spec version.
-You are missing either '"swagger": "2.0"' or '"openapi": "3.0.0"'
-from the top level of your spec."""
-
-
-def canonical_base_path(base_path):
-    """
-    Make given "basePath" a canonical base URL which can be prepended to paths starting with "/".
-    """
-    return base_path.rstrip('/')
-
-
-class Specification(collections_abc.Mapping):
-
-    def __init__(self, raw_spec):
-        self._raw_spec = copy.deepcopy(raw_spec)
-        self._set_defaults(raw_spec)
-        self._validate_spec(raw_spec)
-        self._spec = resolve_refs(raw_spec)
-
-    @classmethod
-    @abc.abstractmethod
-    def _set_defaults(cls, spec):
-        """ set some default values in the spec
-        """
-
-    @classmethod
-    @abc.abstractmethod
-    def _validate_spec(cls, spec):
-        """ validate spec against schema
-        """
-
-    def get_path_params(self, path):
-        return deep_get(self._spec, ["paths", path]).get("parameters", [])
-
-    def get_operation(self, path, method):
-        return deep_get(self._spec, ["paths", path, method])
-
-    @property
-    def raw(self):
-        return self._raw_spec
-
-    @property
-    def version(self):
-        return self._get_spec_version(self._spec)
-
-    @property
-    def security(self):
-        return self._spec.get('security')
-
-    def __getitem__(self, k):
-        return self._spec[k]
-
-    def __iter__(self):
-        return self._spec.__iter__()
-
-    def __len__(self):
-        return self._spec.__len__()
-
-    @staticmethod
-    def _load_spec_from_file(arguments, specification):
-        """
-        Loads a YAML specification file, optionally rendering it with Jinja2.
-        Takes:
-          arguments - passed to Jinja2 renderer
-          specification - path to specification
-        """
-        arguments = arguments or {}
-
-        with specification.open(mode='rb') as openapi_yaml:
-            contents = openapi_yaml.read()
-            try:
-                openapi_template = contents.decode()
-            except UnicodeDecodeError:
-                openapi_template = contents.decode('utf-8', 'replace')
-
-            openapi_string = jinja2.Template(openapi_template).render(**arguments)
-            return yaml.safe_load(openapi_string)
-
-    @classmethod
-    def from_file(cls, spec, arguments=None):
-        """
-        Takes in a path to a YAML file, and returns a Specification
-        """
-        specification_path = pathlib.Path(spec)
-        spec = cls._load_spec_from_file(arguments, specification_path)
-        return cls.from_dict(spec)
-
-    @staticmethod
-    def _get_spec_version(spec):
-        try:
-            version_string = spec.get('openapi') or spec.get('swagger')
-        except AttributeError:
-            raise InvalidSpecification(NO_SPEC_VERSION_ERR_MSG)
-        if version_string is None:
-            raise InvalidSpecification(NO_SPEC_VERSION_ERR_MSG)
-        try:
-            version_tuple = tuple(map(int, version_string.split(".")))
-        except TypeError:
-            err = ('Unable to convert version string to semantic version tuple: '
-                   '{version_string}.')
-            err = err.format(version_string=version_string)
-            raise InvalidSpecification(err)
-        return version_tuple
-
-    @classmethod
-    def from_dict(cls, spec):
-        """
-        Takes in a dictionary, and returns a Specification
-        """
-        def enforce_string_keys(obj):
-            # YAML supports integer keys, but JSON does not
-            if isinstance(obj, dict):
-                return {
-                    str(k): enforce_string_keys(v)
-                    for k, v
-                    in obj.items()
-                }
-            return obj
-
-        spec = enforce_string_keys(spec)
-        version = cls._get_spec_version(spec)
-        if version < (3, 0, 0):
-            return Swagger2Specification(spec)
-        return OpenAPISpecification(spec)
-
-    def clone(self):
-        return type(self)(copy.deepcopy(self._raw_spec))
-
-    @classmethod
-    def load(cls, spec, arguments=None):
-        if not isinstance(spec, dict):
-            return cls.from_file(spec, arguments=arguments)
-        return cls.from_dict(spec)
-
-    def with_base_path(self, base_path):
-        new_spec = self.clone()
-        new_spec.base_path = base_path
-        return new_spec
-
-
-class Swagger2Specification(Specification):
-    yaml_name = 'swagger.yaml'
-    operation_cls = Swagger2Operation
-
-    @classmethod
-    def _set_defaults(cls, spec):
-        spec.setdefault('produces', [])
-        spec.setdefault('consumes', ['application/json'])
-        spec.setdefault('definitions', {})
-        spec.setdefault('parameters', {})
-        spec.setdefault('responses', {})
-
-    @property
-    def produces(self):
-        return self._spec['produces']
-
-    @property
-    def consumes(self):
-        return self._spec['consumes']
-
-    @property
-    def definitions(self):
-        return self._spec['definitions']
-
-    @property
-    def parameter_definitions(self):
-        return self._spec['parameters']
-
-    @property
-    def response_definitions(self):
-        return self._spec['responses']
-
-    @property
-    def security_definitions(self):
-        return self._spec.get('securityDefinitions', {})
-
-    @property
-    def base_path(self):
-        return canonical_base_path(self._spec.get('basePath', ''))
-
-    @base_path.setter
-    def base_path(self, base_path):
-        base_path = canonical_base_path(base_path)
-        self._raw_spec['basePath'] = base_path
-        self._spec['basePath'] = base_path
-
-    @classmethod
-    def _validate_spec(cls, spec):
-        from openapi_spec_validator import validate_v2_spec as validate_spec
-        try:
-            validate_spec(spec)
-        except OpenAPIValidationError as e:
-            raise InvalidSpecification.create_from(e)
-
-
-class OpenAPISpecification(Specification):
-    yaml_name = 'openapi.yaml'
-    operation_cls = OpenAPIOperation
-
-    @classmethod
-    def _set_defaults(cls, spec):
-        spec.setdefault('components', {})
-
-    @property
-    def security_definitions(self):
-        return self._spec['components'].get('securitySchemes', {})
-
-    @property
-    def components(self):
-        return self._spec['components']
-
-    @classmethod
-    def _validate_spec(cls, spec):
-        from openapi_spec_validator import validate_v3_spec as validate_spec
-        try:
-            validate_spec(spec)
-        except OpenAPIValidationError as e:
-            raise InvalidSpecification.create_from(e)
-
-    @property
-    def base_path(self):
-        servers = self._spec.get('servers', [])
-        try:
-            # assume we're the first server in list
-            server = copy.deepcopy(servers[0])
-            server_vars = server.pop("variables", {})
-            server['url'] = server['url'].format(
-                **{k: v['default'] for k, v
-                   in server_vars.items()}
-            )
-            base_path = urlsplit(server['url']).path
-        except IndexError:
-            base_path = ''
-        return canonical_base_path(base_path)
-
-    @base_path.setter
-    def base_path(self, base_path):
-        base_path = canonical_base_path(base_path)
-        user_servers = [{'url': base_path}]
-        self._raw_spec['servers'] = user_servers
-        self._spec['servers'] = user_servers
diff --git a/airflow/_vendor/connexion/utils.py b/airflow/_vendor/connexion/utils.py
deleted file mode 100644
index a19463f..0000000
--- a/airflow/_vendor/connexion/utils.py
+++ /dev/null
@@ -1,250 +0,0 @@
-import functools
-import importlib
-
-import yaml
-
-
-def boolean(s):
-    '''
-    Convert JSON/Swagger boolean value to Python, raise ValueError otherwise
-
-    >>> boolean('true')
-    True
-
-    >>> boolean('false')
-    False
-    '''
-    if isinstance(s, bool):
-        return s
-    elif not hasattr(s, 'lower'):
-        raise ValueError('Invalid boolean value')
-    elif s.lower() == 'true':
-        return True
-    elif s.lower() == 'false':
-        return False
-    else:
-        raise ValueError('Invalid boolean value')
-
-
-# https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#data-types
-TYPE_MAP = {'integer': int,
-            'number': float,
-            'string': str,
-            'boolean': boolean,
-            'array': list,
-            'object': dict}  # map of swagger types to python types
-
-
-def make_type(value, _type):
-    type_func = TYPE_MAP[_type]  # convert value to right type
-    return type_func(value)
-
-
-def deep_merge(a, b):
-    """ merges b into a
-        in case of conflict the value from b is used
-    """
-    for key in b:
-        if key in a:
-            if isinstance(a[key], dict) and isinstance(b[key], dict):
-                deep_merge(a[key], b[key])
-            elif a[key] == b[key]:
-                pass
-            else:
-                # b overwrites a
-                a[key] = b[key]
-        else:
-            a[key] = b[key]
-    return a
-
-
-def deep_getattr(obj, attr):
-    """
-    Recurses through an attribute chain to get the ultimate value.
-    """
-
-    attrs = attr.split('.')
-
-    return functools.reduce(getattr, attrs, obj)
-
-
-def deep_get(obj, keys):
-    """
-    Recurses through a nested object get a leaf value.
-
-    There are cases where the use of inheritance or polymorphism-- the use of allOf or
-    oneOf keywords-- will cause the obj to be a list. In this case the keys will
-    contain one or more strings containing integers.
-
-    :type obj: list or dict
-    :type keys: list of strings
-    """
-    if not keys:
-        return obj
-
-    if isinstance(obj, list):
-        return deep_get(obj[int(keys[0])], keys[1:])
-    else:
-        return deep_get(obj[keys[0]], keys[1:])
-
-
-def get_function_from_name(function_name):
-    """
-    Tries to get function by fully qualified name (e.g. "mymodule.myobj.myfunc")
-
-    :type function_name: str
-    """
-    if function_name is None:
-        raise ValueError("Empty function name")
-
-    if '.' in function_name:
-        module_name, attr_path = function_name.rsplit('.', 1)
-    else:
-        module_name = ''
-        attr_path = function_name
-
-    module = None
-    last_import_error = None
-
-    while not module:
-        try:
-            module = importlib.import_module(module_name)
-        except ImportError as import_error:
-            last_import_error = import_error
-            if '.' in module_name:
-                module_name, attr_path1 = module_name.rsplit('.', 1)
-                attr_path = '{0}.{1}'.format(attr_path1, attr_path)
-            else:
-                raise
-    try:
-        function = deep_getattr(module, attr_path)
-    except AttributeError:
-        if last_import_error:
-            raise last_import_error
-        else:
-            raise
-    return function
-
-
-def is_json_mimetype(mimetype):
-    """
-    :type mimetype: str
-    :rtype: bool
-    """
-    maintype, subtype = mimetype.split('/')  # type: str, str
-    return maintype == 'application' and (subtype == 'json' or subtype.endswith('+json'))
-
-
-def all_json(mimetypes):
-    """
-    Returns True if all mimetypes are serialized with json
-
-    :type mimetypes: list
-    :rtype: bool
-
-    >>> all_json(['application/json'])
-    True
-    >>> all_json(['application/x.custom+json'])
-    True
-    >>> all_json([])
-    True
-    >>> all_json(['application/xml'])
-    False
-    >>> all_json(['text/json'])
-    False
-    >>> all_json(['application/json', 'other/type'])
-    False
-    >>> all_json(['application/json', 'application/x.custom+json'])
-    True
-    """
-    return all(is_json_mimetype(mimetype) for mimetype in mimetypes)
-
-
-def is_nullable(param_def):
-    return (
-        param_def.get('schema', param_def).get('nullable', False) or
-        param_def.get('x-nullable', False)  # swagger2
-    )
-
-
-def is_null(value):
-    if hasattr(value, 'strip') and value.strip() in ['null', 'None']:
-        return True
-
-    if value is None:
-        return True
-
-    return False
-
-
-def has_coroutine(function, api=None):
-    """
-    Checks if function is a coroutine.
-    If ``function`` is a decorator (has a ``__wrapped__`` attribute)
-    this function will also look at the wrapped function.
-    """
-    import asyncio
-
-    def iscorofunc(func):
-        iscorofunc = asyncio.iscoroutinefunction(func)
-        while not iscorofunc and hasattr(func, '__wrapped__'):
-            func = func.__wrapped__
-            iscorofunc = asyncio.iscoroutinefunction(func)
-        return iscorofunc
-
-    if api is None:
-        return iscorofunc(function)
-
-    else:
-        return any(
-            iscorofunc(func) for func in (
-                function, api.get_request, api.get_response
-            )
-        )
-
-
-def yamldumper(openapi):
-    """
-    Returns a nicely-formatted yaml spec.
-    :param openapi: a spec dictionary.
-    :return: a nicely-formatted, serialized yaml spec.
-    """
-    def should_use_block(value):
-        char_list = (
-          u"\u000a"  # line feed
-          u"\u000d"  # carriage return
-          u"\u001c"  # file separator
-          u"\u001d"  # group separator
-          u"\u001e"  # record separator
-          u"\u0085"  # next line
-          u"\u2028"  # line separator
-          u"\u2029"  # paragraph separator
-        )
-        for c in char_list:
-            if c in value:
-                return True
-        return False
-
-    def my_represent_scalar(self, tag, value, style=None):
-        if should_use_block(value):
-            style = '|'
-        else:
-            style = self.default_style
-
-        node = yaml.representer.ScalarNode(tag, value, style=style)
-        if self.alias_key is not None:
-            self.represented_objects[self.alias_key] = node
-        return node
-
-    class NoAnchorDumper(yaml.dumper.SafeDumper):
-        """A yaml Dumper that does not replace duplicate entries
-           with yaml anchors.
-        """
-
-        def ignore_aliases(self, *args):
-            return True
-
-    # Dump long lines as "|".
-    yaml.representer.SafeRepresenter.represent_scalar = my_represent_scalar
-
-    return yaml.dump(openapi, allow_unicode=True, Dumper=NoAnchorDumper)
diff --git a/airflow/api_connexion/endpoints/connection_endpoint.py b/airflow/api_connexion/endpoints/connection_endpoint.py
index 71e4b97..f3373f5 100644
--- a/airflow/api_connexion/endpoints/connection_endpoint.py
+++ b/airflow/api_connexion/endpoints/connection_endpoint.py
@@ -17,11 +17,11 @@
 
 import os
 
+from connexion import NoContent
 from flask import request
 from marshmallow import ValidationError
 from sqlalchemy import func
 
-from airflow._vendor.connexion import NoContent
 from airflow.api_connexion import security
 from airflow.api_connexion.exceptions import AlreadyExists, BadRequest, NotFound
 from airflow.api_connexion.parameters import apply_sorting, check_limit, format_parameters
diff --git a/airflow/api_connexion/endpoints/dag_endpoint.py b/airflow/api_connexion/endpoints/dag_endpoint.py
index 3e4ab00..c164fcc 100644
--- a/airflow/api_connexion/endpoints/dag_endpoint.py
+++ b/airflow/api_connexion/endpoints/dag_endpoint.py
@@ -14,12 +14,12 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+from connexion import NoContent
 from flask import current_app, g, request
 from marshmallow import ValidationError
 from sqlalchemy.sql.expression import or_
 
 from airflow import DAG
-from airflow._vendor.connexion import NoContent
 from airflow.api_connexion import security
 from airflow.api_connexion.exceptions import AlreadyExists, BadRequest, NotFound
 from airflow.api_connexion.parameters import check_limit, format_parameters
diff --git a/airflow/api_connexion/endpoints/dag_run_endpoint.py b/airflow/api_connexion/endpoints/dag_run_endpoint.py
index c838b4c..a0524b1 100644
--- a/airflow/api_connexion/endpoints/dag_run_endpoint.py
+++ b/airflow/api_connexion/endpoints/dag_run_endpoint.py
@@ -17,11 +17,11 @@
 from typing import Optional
 
 import pendulum
+from connexion import NoContent
 from flask import current_app, g, request
 from marshmallow import ValidationError
 from sqlalchemy import or_
 
-from airflow._vendor.connexion import NoContent
 from airflow.api.common.experimental.mark_tasks import (
     set_dag_run_state_to_failed,
     set_dag_run_state_to_success,
diff --git a/airflow/api_connexion/endpoints/role_and_permission_endpoint.py b/airflow/api_connexion/endpoints/role_and_permission_endpoint.py
index 55f7b38..54e9617 100644
--- a/airflow/api_connexion/endpoints/role_and_permission_endpoint.py
+++ b/airflow/api_connexion/endpoints/role_and_permission_endpoint.py
@@ -15,12 +15,12 @@
 # specific language governing permissions and limitations
 # under the License.
 
+from connexion import NoContent
 from flask import current_app, request
 from flask_appbuilder.security.sqla.models import Permission, Role
 from marshmallow import ValidationError
 from sqlalchemy import func
 
-from airflow._vendor.connexion import NoContent
 from airflow.api_connexion import security
 from airflow.api_connexion.exceptions import AlreadyExists, BadRequest, NotFound
 from airflow.api_connexion.parameters import apply_sorting, check_limit, format_parameters
diff --git a/airflow/api_connexion/endpoints/user_endpoint.py b/airflow/api_connexion/endpoints/user_endpoint.py
index 5bd2f3e..f93072d 100644
--- a/airflow/api_connexion/endpoints/user_endpoint.py
+++ b/airflow/api_connexion/endpoints/user_endpoint.py
@@ -14,6 +14,7 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+from connexion import NoContent
 from flask import current_app, request
 from flask_appbuilder.security.sqla.models import User
 from marshmallow import ValidationError
@@ -191,3 +192,4 @@ def delete_user(username):
     user.roles = []  # Clear foreign keys on this user first.
     security_manager.get_session.delete(user)
     security_manager.get_session.commit()
+    return NoContent, 204
diff --git a/airflow/api_connexion/exceptions.py b/airflow/api_connexion/exceptions.py
index c279731..194bfdb 100644
--- a/airflow/api_connexion/exceptions.py
+++ b/airflow/api_connexion/exceptions.py
@@ -17,8 +17,8 @@
 from typing import Dict, Optional
 
 import werkzeug
+from connexion import FlaskApi, ProblemException, problem
 
-from airflow._vendor.connexion import FlaskApi, ProblemException, problem
 from airflow.utils.docs import get_docs_url
 
 doc_link = get_docs_url("stable-rest-api-ref.html")
diff --git a/airflow/exceptions.py b/airflow/exceptions.py
index f9779b7..e04d5c8 100644
--- a/airflow/exceptions.py
+++ b/airflow/exceptions.py
@@ -23,7 +23,7 @@ import datetime
 import warnings
 from typing import Any, Dict, List, NamedTuple, Optional
 
-from airflow.api_connexion.exceptions import NotFound as ApiConnextionNotFound
+from airflow.api_connexion.exceptions import NotFound as ApiConnexionNotFound
 from airflow.utils.code_utils import prepare_code_snippet
 from airflow.utils.platform import is_tty
 
@@ -43,7 +43,7 @@ class AirflowBadRequest(AirflowException):
     status_code = 400
 
 
-class AirflowNotFoundException(AirflowException, ApiConnextionNotFound):
+class AirflowNotFoundException(AirflowException, ApiConnexionNotFound):
     """Raise when the requested object/resource is not available in the system"""
 
     status_code = 404
diff --git a/airflow/www/extensions/init_views.py b/airflow/www/extensions/init_views.py
index f84c67f..83dbc50 100644
--- a/airflow/www/extensions/init_views.py
+++ b/airflow/www/extensions/init_views.py
@@ -19,10 +19,9 @@ import logging
 import warnings
 from os import path
 
+from connexion import App, ProblemException
 from flask import Flask, request
 
-from airflow._vendor import connexion
-from airflow._vendor.connexion import ProblemException
 from airflow.api_connexion.exceptions import common_error_handler
 from airflow.configuration import conf
 from airflow.security import permissions
@@ -191,7 +190,7 @@ def init_api_connexion(app: Flask) -> None:
             return views.not_found(ex)
 
     spec_dir = path.join(ROOT_APP_DIR, 'api_connexion', 'openapi')
-    connexion_app = connexion.App(__name__, specification_dir=spec_dir, skip_error_handlers=True)
+    connexion_app = App(__name__, specification_dir=spec_dir, skip_error_handlers=True)
     connexion_app.app = app
     api_bp = connexion_app.add_api(
         specification='v1.yaml', base_path=base_path, validate_responses=True, strict_validation=True
diff --git a/licenses/LICENSE-connexion.txt b/licenses/LICENSE-connexion.txt
deleted file mode 100644
index 9fb11f9..0000000
--- a/licenses/LICENSE-connexion.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-License
-
-Copyright 2015 Zalando SE
-
-Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
diff --git a/setup.cfg b/setup.cfg
index 0f80dd3..b83ef9b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -30,7 +30,6 @@ license_files =
 # Start of licenses generated automatically
    licenses/LICENSE-bootstrap.txt
    licenses/LICENSE-bootstrap3-typeahead.txt
-   licenses/LICENSE-connexion.txt
    licenses/LICENSE-d3-shape.txt
    licenses/LICENSE-d3-tip.txt
    licenses/LICENSE-d3js.txt
@@ -92,6 +91,7 @@ install_requires =
     # Required by vendored-in connexion
     clickclick>=1.2
     colorlog>=4.0.2, <7.0
+    connexion[swagger-ui,flask]>=2.10.0
     croniter>=0.3.17
     cryptography>=0.9.3
     dataclasses;python_version<"3.7"
@@ -112,8 +112,6 @@ install_requires =
     httpx
     importlib_metadata>=1.7;python_version<"3.9"
     importlib_resources~=5.2;python_version<"3.9"
-    # Required by vendored-in connexion
-    inflection>=0.3.1
     iso8601>=0.1.12
     # Logging is broken with itsdangerous > 2
     itsdangerous>=1.1.0, <2.0
@@ -127,8 +125,6 @@ install_requires =
     markdown>=2.5.2, <4.0
     markupsafe>=1.1.1
     marshmallow-oneofschema>=2.0.1
-    # Required by vendored-in connexion
-    openapi-spec-validator>=0.2.4
     packaging>=14.0
     pendulum~=2.0
     pep562~=1.0;python_version<"3.7"
@@ -146,14 +142,10 @@ install_requires =
     # (pip installs the right version).
     # More info: https://github.com/apache/airflow/issues/13149#issuecomment-748705193
     python3-openid~=3.2
-    # Required by vendored-in connexion
-    pyyaml>=5.1
     rich>=9.2.0
     setproctitle>=1.1.8, <2
     sqlalchemy>=1.3.18
     sqlalchemy_jsonfield~=1.0
-    # Required by vendored-in connexion
-    swagger-ui-bundle>=0.0.2
     tabulate>=0.7.5, <0.9
     tenacity>=6.2.0
     termcolor>=1.1.0