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)
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)
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
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)
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
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 ]
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
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)
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)
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)