fix: add Gitea Actions CI workflow for automated testing
This commit is contained in:
6
api_testgen/core/__init__.py
Normal file
6
api_testgen/core/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
"""Core module for API TestGen."""
|
||||
|
||||
from .spec_parser import SpecParser
|
||||
from .auth import AuthConfig
|
||||
|
||||
__all__ = ["SpecParser", "AuthConfig"]
|
||||
313
api_testgen/core/auth.py
Normal file
313
api_testgen/core/auth.py
Normal file
@@ -0,0 +1,313 @@
|
||||
"""Authentication configuration for API TestGen."""
|
||||
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
from enum import Enum
|
||||
|
||||
from .exceptions import AuthConfigError, MissingSecuritySchemeError
|
||||
|
||||
|
||||
class AuthType(str, Enum):
|
||||
"""Types of authentication."""
|
||||
API_KEY = "apiKey"
|
||||
BEARER = "bearer"
|
||||
BASIC = "basic"
|
||||
NONE = "none"
|
||||
|
||||
|
||||
class AuthConfig:
|
||||
"""Authentication configuration for generated tests."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize authentication configuration."""
|
||||
self._auth_methods: Dict[str, Dict[str, Any]] = {}
|
||||
|
||||
def add_api_key(
|
||||
self,
|
||||
scheme_name: str,
|
||||
header_name: str = "X-API-Key",
|
||||
api_key: str = "",
|
||||
) -> "AuthConfig":
|
||||
"""Add API key authentication.
|
||||
|
||||
Args:
|
||||
scheme_name: Name of the security scheme in OpenAPI spec.
|
||||
header_name: Name of the header containing the API key.
|
||||
api_key: The API key value (can be set later).
|
||||
|
||||
Returns:
|
||||
Self for method chaining.
|
||||
"""
|
||||
self._auth_methods[scheme_name] = {
|
||||
"type": AuthType.API_KEY,
|
||||
"header_name": header_name,
|
||||
"api_key": api_key,
|
||||
}
|
||||
return self
|
||||
|
||||
def add_bearer(
|
||||
self,
|
||||
scheme_name: str,
|
||||
token: str = "",
|
||||
token_prefix: str = "Bearer",
|
||||
) -> "AuthConfig":
|
||||
"""Add Bearer token authentication.
|
||||
|
||||
Args:
|
||||
scheme_name: Name of the security scheme in OpenAPI spec.
|
||||
token: The Bearer token value (can be set later).
|
||||
token_prefix: The token prefix (default: Bearer).
|
||||
|
||||
Returns:
|
||||
Self for method chaining.
|
||||
"""
|
||||
self._auth_methods[scheme_name] = {
|
||||
"type": AuthType.BEARER,
|
||||
"token": token,
|
||||
"token_prefix": token_prefix,
|
||||
}
|
||||
return self
|
||||
|
||||
def add_basic(
|
||||
self,
|
||||
scheme_name: str,
|
||||
username: str = "",
|
||||
password: str = "",
|
||||
) -> "AuthConfig":
|
||||
"""Add Basic authentication.
|
||||
|
||||
Args:
|
||||
scheme_name: Name of the security scheme in OpenAPI spec.
|
||||
username: The username (can be set later).
|
||||
password: The password (can be set later).
|
||||
|
||||
Returns:
|
||||
Self for method chaining.
|
||||
"""
|
||||
self._auth_methods[scheme_name] = {
|
||||
"type": AuthType.BASIC,
|
||||
"username": username,
|
||||
"password": password,
|
||||
}
|
||||
return self
|
||||
|
||||
def get_auth_method(self, scheme_name: str) -> Optional[Dict[str, Any]]:
|
||||
"""Get authentication method by scheme name.
|
||||
|
||||
Args:
|
||||
scheme_name: Name of the security scheme.
|
||||
|
||||
Returns:
|
||||
Authentication method configuration or None.
|
||||
"""
|
||||
return self._auth_methods.get(scheme_name)
|
||||
|
||||
def get_all_methods(self) -> Dict[str, Dict[str, Any]]:
|
||||
"""Get all configured authentication methods.
|
||||
|
||||
Returns:
|
||||
Dictionary of scheme names and their configurations.
|
||||
"""
|
||||
return self._auth_methods.copy()
|
||||
|
||||
def get_headers(self, scheme_name: str) -> Dict[str, str]:
|
||||
"""Get authentication headers for a scheme.
|
||||
|
||||
Args:
|
||||
scheme_name: Name of the security scheme.
|
||||
|
||||
Returns:
|
||||
Dictionary of header names and values.
|
||||
|
||||
Raises:
|
||||
AuthConfigError: If scheme is not configured.
|
||||
"""
|
||||
method = self.get_auth_method(scheme_name)
|
||||
if not method:
|
||||
raise AuthConfigError(f"Authentication scheme '{scheme_name}' not configured")
|
||||
|
||||
if method["type"] == AuthType.API_KEY:
|
||||
return {method["header_name"]: method["api_key"]}
|
||||
elif method["type"] == AuthType.BEARER:
|
||||
return {"Authorization": f"{method['token_prefix']} {method['token']}"}
|
||||
elif method["type"] == AuthType.BASIC:
|
||||
import base64
|
||||
credentials = f"{method['username']}:{method['password']}"
|
||||
encoded = base64.b64encode(credentials.encode()).decode()
|
||||
return {"Authorization": f"Basic {encoded}"}
|
||||
return {}
|
||||
|
||||
def build_from_spec(
|
||||
self,
|
||||
security_schemes: Dict[str, Any],
|
||||
security_requirements: List[Dict[str, Any]],
|
||||
) -> "AuthConfig":
|
||||
"""Build auth configuration from OpenAPI security schemes.
|
||||
|
||||
Args:
|
||||
security_schemes: Security schemes from OpenAPI spec.
|
||||
security_requirements: Security requirements from endpoint.
|
||||
|
||||
Returns:
|
||||
Self for method chaining.
|
||||
|
||||
Raises:
|
||||
MissingSecuritySchemeError: If required scheme is not defined.
|
||||
"""
|
||||
for requirement in security_requirements:
|
||||
for scheme_name in requirement.keys():
|
||||
if scheme_name not in self._auth_methods:
|
||||
if scheme_name not in security_schemes:
|
||||
raise MissingSecuritySchemeError(
|
||||
f"Security scheme '{scheme_name}' not found in spec"
|
||||
)
|
||||
scheme = security_schemes[scheme_name]
|
||||
self._add_scheme_from_spec(scheme_name, scheme)
|
||||
|
||||
return self
|
||||
|
||||
def _add_scheme_from_spec(self, scheme_name: str, scheme: Dict[str, Any]) -> None:
|
||||
"""Add authentication scheme from OpenAPI spec definition.
|
||||
|
||||
Args:
|
||||
scheme_name: Name of the security scheme.
|
||||
scheme: The security scheme definition from OpenAPI spec.
|
||||
"""
|
||||
scheme_type = scheme.get("type", "")
|
||||
|
||||
if scheme_type == "apiKey":
|
||||
self.add_api_key(
|
||||
scheme_name,
|
||||
header_name=scheme.get("name", "X-API-Key"),
|
||||
)
|
||||
elif scheme_type == "http":
|
||||
scheme_scheme = scheme.get("scheme", "").lower()
|
||||
if scheme_scheme == "bearer":
|
||||
self.add_bearer(scheme_name)
|
||||
elif scheme_scheme == "basic":
|
||||
self.add_basic(scheme_name)
|
||||
elif scheme_type == "openIdConnect":
|
||||
self.add_bearer(scheme_name)
|
||||
elif scheme_type == "oauth2":
|
||||
self.add_bearer(scheme_name)
|
||||
|
||||
def generate_auth_code(self, scheme_name: str, framework: str = "pytest") -> str:
|
||||
"""Generate authentication code for a test framework.
|
||||
|
||||
Args:
|
||||
scheme_name: Name of the security scheme.
|
||||
framework: Target test framework (pytest, jest, go).
|
||||
|
||||
Returns:
|
||||
String containing authentication code snippet.
|
||||
"""
|
||||
method = self.get_auth_method(scheme_name)
|
||||
if not method:
|
||||
return ""
|
||||
|
||||
if framework == "pytest":
|
||||
return self._generate_pytest_auth(method)
|
||||
elif framework == "jest":
|
||||
return self._generate_jest_auth(method)
|
||||
elif framework == "go":
|
||||
return self._generate_go_auth(method)
|
||||
return ""
|
||||
|
||||
def _generate_pytest_auth(self, method: Dict[str, Any]) -> str:
|
||||
"""Generate pytest authentication code.
|
||||
|
||||
Args:
|
||||
method: Authentication method configuration.
|
||||
|
||||
Returns:
|
||||
String containing pytest auth code.
|
||||
"""
|
||||
if method["type"] == AuthType.API_KEY:
|
||||
return f'''
|
||||
@pytest.fixture
|
||||
def api_key_headers():
|
||||
return {{"{method['header_name']}": "{method['api_key']}"}}
|
||||
'''
|
||||
elif method["type"] == AuthType.BEARER:
|
||||
return f'''
|
||||
@pytest.fixture
|
||||
def bearer_headers():
|
||||
return {{"Authorization": "{method['token_prefix']} {method['token']}"}}
|
||||
'''
|
||||
elif method["type"] == AuthType.BASIC:
|
||||
return f'''
|
||||
import base64
|
||||
|
||||
@pytest.fixture
|
||||
def basic_headers():
|
||||
credentials = f"{{"{method['username']}"}}:{{"{method['password']}"}}"
|
||||
encoded = base64.b64encode(credentials.encode()).decode()
|
||||
return {{"Authorization": f"Basic {{encoded}}"}}
|
||||
'''
|
||||
return ""
|
||||
|
||||
def _generate_jest_auth(self, method: Dict[str, Any]) -> str:
|
||||
"""Generate Jest authentication code.
|
||||
|
||||
Args:
|
||||
method: Authentication method configuration.
|
||||
|
||||
Returns:
|
||||
String containing Jest auth code.
|
||||
"""
|
||||
if method["type"] == AuthType.API_KEY:
|
||||
return f'''
|
||||
const getApiKeyHeaders = () => ({{
|
||||
"{method['header_name']}": process.env.API_KEY || "{method['api_key']}",
|
||||
}});
|
||||
'''
|
||||
elif method["type"] == AuthType.BEARER:
|
||||
return f'''
|
||||
const getBearerHeaders = () => ({{
|
||||
Authorization: `${{process.env.TOKEN_PREFIX || "{method['token_prefix']}"}} ${{process.env.TOKEN || "{method['token']}"}}`,
|
||||
}});
|
||||
'''
|
||||
elif method["type"] == AuthType.BASIC:
|
||||
return f'''
|
||||
const getBasicHeaders = () => {{
|
||||
const credentials = Buffer.from(`${{process.env.USERNAME || "{method['username']}"}}:${{process.env.PASSWORD || "{method['password']}"}}`).toString('base64');
|
||||
return {{ Authorization: `Basic ${{credentials}}` }};
|
||||
}};
|
||||
'''
|
||||
return ""
|
||||
|
||||
def _generate_go_auth(self, method: Dict[str, Any]) -> str:
|
||||
"""Generate Go authentication code.
|
||||
|
||||
Args:
|
||||
method: Authentication method configuration.
|
||||
|
||||
Returns:
|
||||
String containing Go auth code.
|
||||
"""
|
||||
if method["type"] == AuthType.API_KEY:
|
||||
return f'''
|
||||
func getAPIKeyHeaders() map[string]string {{
|
||||
return map[string]string{{
|
||||
"{method['header_name']}": os.Getenv("API_KEY"),
|
||||
}}
|
||||
}}
|
||||
'''
|
||||
elif method["type"] == AuthType.BEARER:
|
||||
return f'''
|
||||
func getBearerHeaders() map[string]string {{
|
||||
return map[string]string{{
|
||||
"Authorization": fmt.Sprintf("%s %s", os.Getenv("TOKEN_PREFIX"), os.Getenv("TOKEN")),
|
||||
}}
|
||||
}}
|
||||
'''
|
||||
elif method["type"] == AuthType.BASIC:
|
||||
return f'''
|
||||
func getBasicHeaders(username, password string) map[string]string {{
|
||||
auth := username + ":" + password
|
||||
encoded := base64.StdEncoding.EncodeToString([]byte(auth))
|
||||
return map[string]string{{
|
||||
"Authorization": "Basic " + encoded,
|
||||
}}
|
||||
}}
|
||||
'''
|
||||
return ""
|
||||
36
api_testgen/core/exceptions.py
Normal file
36
api_testgen/core/exceptions.py
Normal file
@@ -0,0 +1,36 @@
|
||||
"""Custom exceptions for API TestGen."""
|
||||
|
||||
|
||||
class SpecParserError(Exception):
|
||||
"""Base exception for spec parser errors."""
|
||||
pass
|
||||
|
||||
|
||||
class InvalidOpenAPISpecError(SpecParserError):
|
||||
"""Raised when OpenAPI specification is invalid."""
|
||||
pass
|
||||
|
||||
|
||||
class UnsupportedVersionError(SpecParserError):
|
||||
"""Raised when OpenAPI version is not supported."""
|
||||
pass
|
||||
|
||||
|
||||
class AuthConfigError(Exception):
|
||||
"""Base exception for auth configuration errors."""
|
||||
pass
|
||||
|
||||
|
||||
class MissingSecuritySchemeError(AuthConfigError):
|
||||
"""Raised when security scheme is not defined in spec."""
|
||||
pass
|
||||
|
||||
|
||||
class GeneratorError(Exception):
|
||||
"""Base exception for generator errors."""
|
||||
pass
|
||||
|
||||
|
||||
class TemplateRenderError(GeneratorError):
|
||||
"""Raised when template rendering fails."""
|
||||
pass
|
||||
307
api_testgen/core/spec_parser.py
Normal file
307
api_testgen/core/spec_parser.py
Normal file
@@ -0,0 +1,307 @@
|
||||
"""OpenAPI Specification Parser."""
|
||||
|
||||
import yaml
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
from openapi_spec_validator import validate
|
||||
from openapi_spec_validator.versions import consts as validator_consts
|
||||
|
||||
from .exceptions import InvalidOpenAPISpecError, UnsupportedVersionError
|
||||
|
||||
|
||||
class SpecParser:
|
||||
"""Parse and validate OpenAPI/Swagger specifications."""
|
||||
|
||||
SUPPORTED_VERSIONS = ["2.0", "3.0.0", "3.0.1", "3.0.2", "3.0.3", "3.1.0"]
|
||||
|
||||
def __init__(self, spec_path: Union[str, Path]):
|
||||
"""Initialize the spec parser.
|
||||
|
||||
Args:
|
||||
spec_path: Path to OpenAPI specification file (YAML or JSON).
|
||||
"""
|
||||
self.spec_path = Path(spec_path)
|
||||
self.spec: Dict[str, Any] = {}
|
||||
self.version: str = ""
|
||||
self.base_path: str = ""
|
||||
self.servers: List[Dict[str, str]] = []
|
||||
|
||||
def load(self) -> Dict[str, Any]:
|
||||
"""Load and validate the OpenAPI specification.
|
||||
|
||||
Returns:
|
||||
The parsed specification dictionary.
|
||||
|
||||
Raises:
|
||||
InvalidOpenAPISpecError: If the specification is invalid.
|
||||
UnsupportedVersionError: If the OpenAPI version is not supported.
|
||||
"""
|
||||
self.spec = self._load_file()
|
||||
self._validate()
|
||||
self._extract_metadata()
|
||||
return self.spec
|
||||
|
||||
def _load_file(self) -> Dict[str, Any]:
|
||||
"""Load the specification file.
|
||||
|
||||
Returns:
|
||||
Parsed specification dictionary.
|
||||
|
||||
Raises:
|
||||
InvalidOpenAPISpecError: If the file cannot be loaded or parsed.
|
||||
"""
|
||||
if not self.spec_path.exists():
|
||||
raise InvalidOpenAPISpecError(f"Specification file not found: {self.spec_path}")
|
||||
|
||||
try:
|
||||
with open(self.spec_path, 'r', encoding='utf-8') as f:
|
||||
if self.spec_path.suffix in ['.yaml', '.yml']:
|
||||
return yaml.safe_load(f) or {}
|
||||
elif self.spec_path.suffix == '.json':
|
||||
return json.load(f)
|
||||
else:
|
||||
return yaml.safe_load(f) or {}
|
||||
except (yaml.YAMLError, json.JSONDecodeError) as e:
|
||||
raise InvalidOpenAPISpecError(f"Failed to parse specification: {e}")
|
||||
|
||||
def _validate(self) -> None:
|
||||
"""Validate the specification.
|
||||
|
||||
Raises:
|
||||
InvalidOpenAPISpecError: If the specification is invalid.
|
||||
UnsupportedVersionError: If the OpenAPI version is not supported.
|
||||
"""
|
||||
try:
|
||||
validate(self.spec)
|
||||
except Exception as e:
|
||||
raise InvalidOpenAPISpecError(f"Invalid OpenAPI specification: {e}")
|
||||
|
||||
version = self._get_version()
|
||||
if version not in self.SUPPORTED_VERSIONS:
|
||||
raise UnsupportedVersionError(
|
||||
f"Unsupported OpenAPI version: {version}. "
|
||||
f"Supported versions: {', '.join(self.SUPPORTED_VERSIONS)}"
|
||||
)
|
||||
|
||||
def _get_version(self) -> str:
|
||||
"""Extract the OpenAPI version from the spec.
|
||||
|
||||
Returns:
|
||||
The OpenAPI version string.
|
||||
"""
|
||||
if "openapi" in self.spec:
|
||||
return self.spec["openapi"]
|
||||
elif "swagger" in self.spec:
|
||||
return self.spec["swagger"]
|
||||
return "2.0"
|
||||
|
||||
def _extract_metadata(self) -> None:
|
||||
"""Extract metadata from the specification."""
|
||||
self.version = self._get_version()
|
||||
self.base_path = self.spec.get("basePath", "")
|
||||
self.servers = self.spec.get("servers", [])
|
||||
|
||||
def get_paths(self) -> Dict[str, Any]:
|
||||
"""Get all paths from the specification.
|
||||
|
||||
Returns:
|
||||
Dictionary of paths and their operations.
|
||||
"""
|
||||
return self.spec.get("paths", {})
|
||||
|
||||
def get_endpoints(self) -> List[Dict[str, Any]]:
|
||||
"""Extract all endpoints from the specification.
|
||||
|
||||
Returns:
|
||||
List of endpoint dictionaries with path, method, and details.
|
||||
"""
|
||||
endpoints = []
|
||||
paths = self.get_paths()
|
||||
|
||||
for path, path_item in paths.items():
|
||||
for method, operation in path_item.items():
|
||||
if method.lower() in ["get", "post", "put", "patch", "delete", "options", "head"]:
|
||||
endpoint = {
|
||||
"path": path,
|
||||
"method": method.lower(),
|
||||
"operation_id": operation.get("operationId", ""),
|
||||
"summary": operation.get("summary", ""),
|
||||
"description": operation.get("description", ""),
|
||||
"tags": operation.get("tags", []),
|
||||
"parameters": self._extract_parameters(path_item, operation),
|
||||
"request_body": self._extract_request_body(operation),
|
||||
"responses": self._extract_responses(operation),
|
||||
"security": self._extract_security(operation),
|
||||
}
|
||||
endpoints.append(endpoint)
|
||||
|
||||
return endpoints
|
||||
|
||||
def _extract_parameters(self, path_item: Dict, operation: Dict) -> List[Dict[str, Any]]:
|
||||
"""Extract parameters from path item and operation.
|
||||
|
||||
Args:
|
||||
path_item: The path item dictionary.
|
||||
operation: The operation dictionary.
|
||||
|
||||
Returns:
|
||||
List of parameter dictionaries.
|
||||
"""
|
||||
parameters = []
|
||||
|
||||
for param in path_item.get("parameters", []):
|
||||
if param.get("in") != "body":
|
||||
parameters.append(self._normalize_parameter(param))
|
||||
|
||||
for param in operation.get("parameters", []):
|
||||
if param.get("in") != "body":
|
||||
parameters.append(self._normalize_parameter(param))
|
||||
|
||||
return parameters
|
||||
|
||||
def _normalize_parameter(self, param: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Normalize a parameter.
|
||||
|
||||
Args:
|
||||
param: The parameter dictionary.
|
||||
|
||||
Returns:
|
||||
Normalized parameter dictionary.
|
||||
"""
|
||||
return {
|
||||
"name": param.get("name", ""),
|
||||
"in": param.get("in", ""),
|
||||
"description": param.get("description", ""),
|
||||
"required": param.get("required", False),
|
||||
"schema": param.get("schema", {}),
|
||||
"type": param.get("type", ""),
|
||||
"enum": param.get("enum", []),
|
||||
"default": param.get("default"),
|
||||
}
|
||||
|
||||
def _extract_request_body(self, operation: Dict) -> Optional[Dict[str, Any]]:
|
||||
"""Extract request body from operation.
|
||||
|
||||
Args:
|
||||
operation: The operation dictionary.
|
||||
|
||||
Returns:
|
||||
Request body dictionary or None.
|
||||
"""
|
||||
if self.version.startswith("3."):
|
||||
request_body = operation.get("requestBody", {})
|
||||
if not request_body:
|
||||
return None
|
||||
|
||||
content = request_body.get("content", {})
|
||||
media_types = list(content.keys())
|
||||
|
||||
return {
|
||||
"description": request_body.get("description", ""),
|
||||
"required": request_body.get("required", False),
|
||||
"media_types": media_types,
|
||||
"schema": content.get(media_types[0], {}).get("schema", {}) if media_types else {},
|
||||
}
|
||||
else:
|
||||
params = operation.get("parameters", [])
|
||||
for param in params:
|
||||
if param.get("in") == "body":
|
||||
return {
|
||||
"description": param.get("description", ""),
|
||||
"required": param.get("required", False),
|
||||
"schema": param.get("schema", {}),
|
||||
}
|
||||
return None
|
||||
|
||||
def _extract_responses(self, operation: Dict) -> Dict[str, Any]:
|
||||
"""Extract responses from operation.
|
||||
|
||||
Args:
|
||||
operation: The operation dictionary.
|
||||
|
||||
Returns:
|
||||
Dictionary of response status codes and their details.
|
||||
"""
|
||||
responses = {}
|
||||
|
||||
for status_code, response in operation.get("responses", {}).items():
|
||||
content = response.get("content", {})
|
||||
|
||||
if self.version.startswith("3."):
|
||||
media_types = list(content.keys())
|
||||
schema = content.get(media_types[0], {}).get("schema", {}) if media_types else {}
|
||||
else:
|
||||
schema = response.get("schema", {})
|
||||
|
||||
responses[status_code] = {
|
||||
"description": response.get("description", ""),
|
||||
"schema": schema,
|
||||
"media_type": list(content.keys())[0] if content else "application/json",
|
||||
}
|
||||
|
||||
return responses
|
||||
|
||||
def _extract_security(self, operation: Dict) -> List[Dict[str, Any]]:
|
||||
"""Extract security requirements from operation.
|
||||
|
||||
Args:
|
||||
operation: The operation dictionary.
|
||||
|
||||
Returns:
|
||||
List of security requirement dictionaries.
|
||||
"""
|
||||
return operation.get("security", self.spec.get("security", []))
|
||||
|
||||
def get_security_schemes(self) -> Dict[str, Any]:
|
||||
"""Get security schemes from the specification.
|
||||
|
||||
Returns:
|
||||
Dictionary of security scheme names and their definitions.
|
||||
"""
|
||||
if self.version.startswith("3."):
|
||||
return self.spec.get("components", {}).get("securitySchemes", {})
|
||||
else:
|
||||
return self.spec.get("securityDefinitions", {})
|
||||
|
||||
def get_definitions(self) -> Dict[str, Any]:
|
||||
"""Get schema definitions from the specification.
|
||||
|
||||
Returns:
|
||||
Dictionary of schema definitions.
|
||||
"""
|
||||
if self.version.startswith("3."):
|
||||
return self.spec.get("components", {}).get("schemas", {})
|
||||
else:
|
||||
return self.spec.get("definitions", {})
|
||||
|
||||
def get_info(self) -> Dict[str, str]:
|
||||
"""Get API info from the specification.
|
||||
|
||||
Returns:
|
||||
Dictionary with title, version, and description.
|
||||
"""
|
||||
info = self.spec.get("info", {})
|
||||
return {
|
||||
"title": info.get("title", "API"),
|
||||
"version": info.get("version", "1.0.0"),
|
||||
"description": info.get("description", ""),
|
||||
}
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""Convert the spec to a dictionary.
|
||||
|
||||
Returns:
|
||||
Dictionary representation of the parsed spec.
|
||||
"""
|
||||
return {
|
||||
"version": self.version,
|
||||
"base_path": self.base_path,
|
||||
"servers": self.servers,
|
||||
"info": self.get_info(),
|
||||
"paths": self.get_paths(),
|
||||
"endpoints": self.get_endpoints(),
|
||||
"security_schemes": self.get_security_schemes(),
|
||||
"definitions": self.get_definitions(),
|
||||
}
|
||||
Reference in New Issue
Block a user