Ejemplo n.º 1
0
    def add_path(self, path=None, operations=None, **kwargs):
        """Add a new path object to the spec.

        https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#paths-object-
        """
        if path and 'basePath' in self.options:
            pattern = '^{0}'.format(re.escape(self.options['basePath']))
            path = re.sub(pattern, '', path)
        path = Path(path=path, operations=operations)
        # Execute plugins' helpers
        for func in self._path_helpers:
            ret = func(self, path=path, operations=operations, **kwargs)
            if isinstance(ret, Path):
                path.update(ret)

        if not path.path:
            raise APISpecError('Path template is not specified')

        # Process response helpers for any path operations defined.
        # Rule is that method + http status exist in both operations and helpers
        methods = set(iterkeys(path.operations)) & set(
            iterkeys(self._response_helpers))
        for method in methods:
            responses = path.operations[method]['responses']
            statuses = set(iterkeys(responses)) & set(
                iterkeys(self._response_helpers[method]))
            for status_code in statuses:
                for func in self._response_helpers[method][status_code]:
                    responses[status_code].update(func(self, **kwargs))

        self._paths.setdefault(path.path, path).update(path)
Ejemplo n.º 2
0
    def add_path(self, path=None, operations=None, **kwargs):
        """Add a new path object to the spec.

        https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#pathsObject

        :param str|Path|None path: URL Path component or Path instance
        :param dict|None operations: describes the http methods and options for `path`
        :param dict kwargs: parameters used by any path helpers see :meth:`register_path_helper`
        """
        def normalize_path(path):
            if path and 'basePath' in self.options:
                pattern = '^{0}'.format(re.escape(self.options['basePath']))
                path = re.sub(pattern, '', path)

            return path

        p = path
        if isinstance(path, Path):
            p = path.path

        p = normalize_path(p)

        if isinstance(path, Path):
            path.path = p
        else:
            path = Path(path=p,
                        operations=operations,
                        openapi_version=self.openapi_version.vstring)
        # Execute plugins' helpers
        for func in self._path_helpers:
            try:
                ret = func(self, path=path, operations=operations, **kwargs)
            except TypeError:
                continue
            if isinstance(ret, Path):
                ret.path = normalize_path(ret.path)
                path.update(ret)
                operations = ret.operations
        if operations:
            for func in self._operation_helpers:
                func(self, path=path, operations=operations, **kwargs)

        if not path.path:
            raise APISpecError('Path template is not specified')

        # Process response helpers for any path operations defined.
        # Rule is that method + http status exist in both operations and helpers
        methods = set(iterkeys(path.operations)) & set(
            iterkeys(self._response_helpers))
        for method in methods:
            responses = path.operations[method]['responses']
            statuses = set(iterkeys(responses)) & set(
                iterkeys(self._response_helpers[method]))
            for status_code in statuses:
                for func in self._response_helpers[method][status_code]:
                    responses[status_code].update(func(self, **kwargs))

        self._paths.setdefault(path.path,
                               path.operations).update(path.operations)
Ejemplo n.º 3
0
def clean_operations(operations, openapi_major_version):
    """Ensure that all parameters with "in" equal to "path" are also required
    as required by the OpenAPI specification, as well as normalizing any
    references to global parameters. Also checks for invalid HTTP methods.

    See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#parameterObject.

    :param dict operations: Dict mapping status codes to operations
    :param int openapi_major_version: The major version of the OpenAPI standard
        to use. Supported values are 2 and 3.
    """
    invalid = {
        key
        for key in set(iterkeys(operations)) -
        set(VALID_METHODS[openapi_major_version]) if not key.startswith("x-")
    }
    if invalid:
        raise APISpecError("One or more HTTP methods are invalid: {}".format(
            ", ".join(invalid)))

    def get_ref(obj_type, obj, openapi_major_version):
        """Return object or rererence

        If obj is a dict, it is assumed to be a complete description and it is returned as is.
        Otherwise, it is assumed to be a reference name as string and the corresponding $ref
        string is returned.

        :param str obj_type: "parameter" or "response"
        :param dict|str obj: parameter or response in dict form or as ref_id string
        :param int openapi_major_version: The major version of the OpenAPI standard
        """
        if isinstance(obj, dict):
            return obj
        return build_reference(obj_type, openapi_major_version, obj)

    for operation in (operations or {}).values():
        if "parameters" in operation:
            parameters = operation["parameters"]
            for parameter in parameters:
                if (isinstance(parameter, dict) and "in" in parameter
                        and parameter["in"] == "path"):
                    parameter["required"] = True
            operation["parameters"] = [
                get_ref("parameter", p, openapi_major_version)
                for p in parameters
            ]
        if "responses" in operation:
            responses = OrderedDict()
            for code, response in iteritems(operation["responses"]):
                try:
                    code = int(code)  # handles IntEnums like http.HTTPStatus
                except (TypeError, ValueError):
                    if openapi_major_version < 3:
                        warnings.warn(
                            "Non-integer code not allowed in OpenAPI < 3")

                responses[str(code)] = get_ref("response", response,
                                               openapi_major_version)
            operation["responses"] = responses
Ejemplo n.º 4
0
 def __init__(self, path=None, operations=None, **kwargs):
     self.path = path
     operations = operations or {}
     clean_operations(operations)
     invalid = set(iterkeys(operations)) - set(VALID_METHODS)
     if invalid:
         raise APISpecError(
             'One or more HTTP methods are invalid: {0}'.format(
                 ", ".join(invalid)))
     self.operations = operations
     kwargs.update(self.operations)
     super(Path, self).__init__(**kwargs)
Ejemplo n.º 5
0
 def __init__(self, path=None, operations=None, openapi_version='2.0'):
     self.path = path
     operations = operations or OrderedDict()
     openapi_version = OpenAPIVersion(openapi_version)
     clean_operations(operations, openapi_version.major)
     invalid = {
         key
         for key in set(iterkeys(operations)) - set(VALID_METHODS)
         if not key.startswith('x-')
     }
     if invalid:
         raise APISpecError(
             'One or more HTTP methods are invalid: {0}'.format(
                 ', '.join(invalid)), )
     self.operations = operations
Ejemplo n.º 6
0
def clean_operations(operations, openapi_major_version):
    """Ensure that all parameters with "in" equal to "path" are also required
    as required by the OpenAPI specification, as well as normalizing any
    references to global parameters. Also checks for invalid HTTP methods.

    See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameterObject.

    :param dict operations: Dict mapping status codes to operations
    :param int openapi_major_version: The major version of the OpenAPI standard
        to use. Supported values are 2 and 3.
    """
    invalid = {
        key
        for key in set(iterkeys(operations)) - set(VALID_METHODS)
        if not key.startswith('x-')
    }
    if invalid:
        raise APISpecError(
            'One or more HTTP methods are invalid: {0}'.format(
                ', '.join(invalid)), )

    def get_ref(param, openapi_major_version):
        if isinstance(param, dict):
            return param

        ref_paths = {
            2: 'parameters',
            3: 'components/parameters',
        }
        ref_path = ref_paths[openapi_major_version]
        return {'$ref': '#/{0}/{1}'.format(ref_path, param)}

    for operation in (operations or {}).values():
        if 'parameters' in operation:
            parameters = operation.get('parameters')
            for parameter in parameters:
                if (isinstance(parameter, dict) and 'in' in parameter
                        and parameter['in'] == 'path'):
                    parameter['required'] = True
            operation['parameters'] = [
                get_ref(p, openapi_major_version) for p in parameters
            ]
Ejemplo n.º 7
0
def clean_operations(operations, openapi_major_version):
    """Ensure that all parameters with "in" equal to "path" are also required
    as required by the OpenAPI specification, as well as normalizing any
    references to global parameters. Also checks for invalid HTTP methods.

    See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#parameterObject.

    :param dict operations: Dict mapping status codes to operations
    :param int openapi_major_version: The major version of the OpenAPI standard
        to use. Supported values are 2 and 3.
    """
    invalid = {
        key
        for key in set(iterkeys(operations)) -
        set(VALID_METHODS[openapi_major_version]) if not key.startswith("x-")
    }
    if invalid:
        raise APISpecError("One or more HTTP methods are invalid: {}".format(
            ", ".join(invalid)))

    for operation in (operations or {}).values():
        if "parameters" in operation:
            operation["parameters"] = clean_parameters(operation["parameters"],
                                                       openapi_major_version)
        if "responses" in operation:
            responses = OrderedDict()
            for code, response in iteritems(operation["responses"]):
                try:
                    code = int(code)  # handles IntEnums like http.HTTPStatus
                except (TypeError, ValueError):
                    if openapi_major_version < 3:
                        warnings.warn(
                            "Non-integer code not allowed in OpenAPI < 3")

                responses[str(code)] = get_ref("response", response,
                                               openapi_major_version)
            operation["responses"] = responses
Ejemplo n.º 8
0
    def add_path(self, path=None, operations=None, **kwargs):
        """Add a new path object to the spec.

        https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#pathsObject

        :param str|Path|None path: URL Path component or Path instance
        :param dict|None operations: describes the http methods and options for `path`
        :param dict kwargs: parameters used by any path helpers see :meth:`register_path_helper`
        """
        def normalize_path(path):
            if path and 'basePath' in self.options:
                pattern = '^{0}'.format(re.escape(self.options['basePath']))
                path = re.sub(pattern, '', path)
            return path

        if isinstance(path, Path):
            path.path = normalize_path(path.path)
            if operations:
                path.operations.update(operations)
        else:
            path = Path(
                path=normalize_path(path),
                operations=operations,
                openapi_version=self.openapi_version,
            )

        # Execute path helpers
        for plugin in self.plugins:
            try:
                ret = plugin.path_helper(path=path,
                                         operations=path.operations,
                                         **kwargs)
            except PluginMethodNotImplementedError:
                continue
            if isinstance(ret, Path):
                ret.path = normalize_path(ret.path)
                path.update(ret)
        # Deprecated interface
        for func in self._path_helpers:
            try:
                ret = func(self,
                           path=path,
                           operations=path.operations,
                           **kwargs)
            except TypeError:
                continue
            if isinstance(ret, Path):
                ret.path = normalize_path(ret.path)
                path.update(ret)
        if not path.path:
            raise APISpecError('Path template is not specified')

        # Execute operation helpers
        for plugin in self.plugins:
            try:
                plugin.operation_helper(path=path,
                                        operations=path.operations,
                                        **kwargs)
            except PluginMethodNotImplementedError:
                continue
        # Deprecated interface
        for func in self._operation_helpers:
            func(self, path=path, operations=path.operations, **kwargs)

        # Execute response helpers
        # TODO: cache response helpers output for each (method, status_code) couple
        for method, operation in iteritems(path.operations):
            if method in VALID_METHODS and 'responses' in operation:
                for status_code, response in iteritems(operation['responses']):
                    for plugin in self.plugins:
                        try:
                            response.update(
                                plugin.response_helper(method, status_code, **
                                                       kwargs) or {})
                        except PluginMethodNotImplementedError:
                            continue
        # Deprecated interface
        # Rule is that method + http status exist in both operations and helpers
        methods = set(iterkeys(path.operations)) & set(
            iterkeys(self._response_helpers))
        for method in methods:
            responses = path.operations[method]['responses']
            statuses = set(iterkeys(responses)) & set(
                iterkeys(self._response_helpers[method]))
            for status_code in statuses:
                for func in self._response_helpers[method][status_code]:
                    responses[status_code].update(func(self, **kwargs), )

        self._paths.setdefault(path.path,
                               path.operations).update(path.operations)
Ejemplo n.º 9
0
def clean_operations(operations, openapi_major_version):
    """Ensure that all parameters with "in" equal to "path" are also required
    as required by the OpenAPI specification, as well as normalizing any
    references to global parameters. Also checks for invalid HTTP methods.

    See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameterObject.

    :param dict operations: Dict mapping status codes to operations
    :param int openapi_major_version: The major version of the OpenAPI standard
        to use. Supported values are 2 and 3.
    """
    invalid = {
        key
        for key in set(iterkeys(operations)) - set(VALID_METHODS)
        if not key.startswith('x-')
    }
    if invalid:
        raise APISpecError(
            'One or more HTTP methods are invalid: {0}'.format(
                ', '.join(invalid)), )

    def get_ref(obj_type, obj, openapi_major_version):
        """Return object or rererence

        If obj is a dict, it is assumed to be a complete description and it is returned as is.
        Otherwise, it is assumed to be a reference name as string and the corresponding $ref
        string is returned.

        :param str obj_type: 'parameter' or 'response'
        :param dict|str obj: parameter or response in dict form or as ref_id string
        :param int openapi_major_version: The major version of the OpenAPI standard
        """
        if isinstance(obj, dict):
            return obj

        ref_paths = {
            'parameter': {
                2: 'parameters',
                3: 'components/parameters',
            },
            'response': {
                2: 'responses',
                3: 'components/responses',
            },
        }
        ref_path = ref_paths[obj_type][openapi_major_version]
        return {'$ref': '#/{0}/{1}'.format(ref_path, obj)}

    for operation in (operations or {}).values():
        if 'parameters' in operation:
            parameters = operation['parameters']
            for parameter in parameters:
                if (isinstance(parameter, dict) and 'in' in parameter
                        and parameter['in'] == 'path'):
                    parameter['required'] = True
            operation['parameters'] = [
                get_ref('parameter', p, openapi_major_version)
                for p in parameters
            ]
        if 'responses' in operation:
            for code, response in iteritems(operation['responses']):
                operation['responses'][code] = get_ref('response', response,
                                                       openapi_major_version)
Ejemplo n.º 10
0
def clean_operations(operations, openapi_major_version):
    """Ensure that all parameters with "in" equal to "path" are also required
    as required by the OpenAPI specification, as well as normalizing any
    references to global parameters. Also checks for invalid HTTP methods.

    See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#parameterObject.

    :param dict operations: Dict mapping status codes to operations
    :param int openapi_major_version: The major version of the OpenAPI standard
        to use. Supported values are 2 and 3.
    """
    invalid = {
        key
        for key in set(iterkeys(operations)) -
        set(VALID_METHODS[openapi_major_version]) if not key.startswith("x-")
    }
    if invalid:
        raise APISpecError("One or more HTTP methods are invalid: {}".format(
            ", ".join(invalid)))

    def get_ref(obj_type, obj, openapi_major_version):
        """Return object or rererence

        If obj is a dict, it is assumed to be a complete description and it is returned as is.
        Otherwise, it is assumed to be a reference name as string and the corresponding $ref
        string is returned.

        :param str obj_type: 'parameter' or 'response'
        :param dict|str obj: parameter or response in dict form or as ref_id string
        :param int openapi_major_version: The major version of the OpenAPI standard
        """
        if isinstance(obj, dict):
            return obj

        ref_paths = {
            "parameter": {
                2: "parameters",
                3: "components/parameters"
            },
            "response": {
                2: "responses",
                3: "components/responses"
            },
        }
        ref_path = ref_paths[obj_type][openapi_major_version]
        return {"$ref": "#/{}/{}".format(ref_path, obj)}

    for operation in (operations or {}).values():
        if "parameters" in operation:
            parameters = operation["parameters"]
            for parameter in parameters:
                if (isinstance(parameter, dict) and "in" in parameter
                        and parameter["in"] == "path"):
                    parameter["required"] = True
            operation["parameters"] = [
                get_ref("parameter", p, openapi_major_version)
                for p in parameters
            ]
        if "responses" in operation:
            for code, response in iteritems(operation["responses"]):
                operation["responses"][code] = get_ref("response", response,
                                                       openapi_major_version)