failed CONTEXT LOOP UNSUBMITTED agent_error ยท 25 tool calls ยท 215 s ยท fastapi/fastapi
๐ Fix OpenAPI security scheme OAuth2 scopes declaration, deduplicate security schemes with different scopes ๐ Fix OpenAPI security scheme OAuth2 scopes declaration, deduplicate security schemes with different scopes This should fix https://github.com/fastapi/fastapi/issues/14454
| # | Tool | Arguments | Result |
|---|---|---|---|
| 1 | run_command | {
"command": "grep -rn \"securitySchemes\" fastapi/openapi | head -20"
} | {"status": "ok", "stdout": "fastapi/openapi/models.py:422: securitySchemes: Optional[Dict[str, Union[SecurityScheme, Reference]]] = None\nfastapi/openapi/utils.full{"status": "ok", "stdout": "fastapi/openapi/models.py:422: securitySchemes: Optional[Dict[str, Union[SecurityScheme, Reference]]] = None\nfastapi/openapi/utils.py:523: components.setdefault(\"securitySchemes\", {}).update(\nfastapi/openapi/utils.py:542: components.setdefault(\"securitySchemes\", {}).update(\n", "exit_code": 0} |
| 2 | read_file | {
"filepath": "fastapi/openapi/utils.py",
"start_line": 500,
"end_line": 560
} | {"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": " webhook_paths: Dict[str, Dict[str, Any]] = {}\n operation_ids: Set[str] = set()\n all_fielfull{"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": " webhook_paths: Dict[str, Dict[str, Any]] = {}\n operation_ids: Set[str] = set()\n all_fields = get_fields_from_routes(list(routes or []) + list(webhooks or []))\n model_name_map = get_compat_model_name_map(all_fields)\n field_mapping, definitions = get_definitions(\n fields=all_fields,\n model_name_map=model_name_map,\n separate_input_output_schemas=separate_input_output_schemas,\n )\n for route in routes or []:\n if isinstance(route, routing.APIRoute):\n result = get_openapi_path(\n route=route,\n operation_ids=operation_ids,\n model_name_map=model_name_map,\n field_mapping=field_mapping,\n separate_input_output_schemas=separate_input_output_schemas,\n )\n if result:\n path, security_schemes, path_definitions = result\n if path:\n paths.setdefault(route.path_format, {}).update(path)\n if security_schemes:\n components.setdefault(\"securitySchemes\", {}).update(\n security_schemes\n )\n if path_definitions:\n definitions.update(path_definitions)\n for webhook in webhooks or []:\n if isinstance(webhook, routing.APIRoute):\n result = get_openapi_path(\n route=webhook,\n operation_ids=operation_ids,\n model_name_map=model_name_map,\n field_mapping=field_mapping,\n separate_input_output_schemas=separate_input_output_schemas,\n )\n if result:\n path, security_schemes, path_definitions = result\n if path:\n webhook_paths.setdefault(webhook.path_format, {}).update(path)\n if security_schemes:\n co |
| 3 | run_command | {
"command": "grep -rn \"get_openapi_path\" fastapi/openapi | head -20"
} | {"status": "ok", "stdout": "fastapi/openapi/utils.py:250:def get_openapi_path(\nfastapi/openapi/utils.py:321: ) = get_openapi_path(\nfastapi/openapi/utils.py:51full{"status": "ok", "stdout": "fastapi/openapi/utils.py:250:def get_openapi_path(\nfastapi/openapi/utils.py:321: ) = get_openapi_path(\nfastapi/openapi/utils.py:511: result = get_openapi_path(\nfastapi/openapi/utils.py:530: result = get_openapi_path(\n", "exit_code": 0} |
| 4 | read_file | {
"end_line": 350,
"filepath": "fastapi/openapi/utils.py",
"start_line": 250
} | {"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": "def get_openapi_path(\n *,\n route: routing.APIRoute,\n operation_ids: Set[str],\n model_nafull{"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": "def get_openapi_path(\n *,\n route: routing.APIRoute,\n operation_ids: Set[str],\n model_name_map: ModelNameMap,\n field_mapping: Dict[\n Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue\n ],\n separate_input_output_schemas: bool = True,\n) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:\n path = {}\n security_schemes: Dict[str, Any] = {}\n definitions: Dict[str, Any] = {}\n assert route.methods is not None, \"Methods must be a list\"\n if isinstance(route.response_class, DefaultPlaceholder):\n current_response_class: Type[Response] = route.response_class.value\n else:\n current_response_class = route.response_class\n assert current_response_class, \"A response class is needed to generate OpenAPI\"\n route_response_media_type: Optional[str] = current_response_class.media_type\n if route.include_in_schema:\n for method in route.methods:\n operation = get_openapi_operation_metadata(\n route=route, method=method, operation_ids=operation_ids\n )\n parameters: List[Dict[str, Any]] = []\n flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True)\n security_definitions, operation_security = get_openapi_security_definitions(\n flat_dependant=flat_dependant\n )\n if operation_security:\n operation.setdefault(\"security\", []).extend(operation_security)\n if security_definitions:\n security_schemes.update(security_definitions)\n operation_parameters = _get_openapi_operation_parameters(\n dependant=route.dependant,\n model_name_map=model_name_map,\n field_mapping=field_mapping,\n separate_input_output_schemas=separate_input_output_schemas,\n )\n |
| 5 | run_command | {
"command": "grep -rn \"get_openapi_security_definitions\" fastapi/openapi | head -20"
} | {"status": "ok", "stdout": "fastapi/openapi/utils.py:78:def get_openapi_security_definitions(\nfastapi/openapi/utils.py:277: security_definitions, operation_secfull{"status": "ok", "stdout": "fastapi/openapi/utils.py:78:def get_openapi_security_definitions(\nfastapi/openapi/utils.py:277: security_definitions, operation_security = get_openapi_security_definitions(\n", "exit_code": 0} |
| 6 | read_file | {
"end_line": 120,
"filepath": "fastapi/openapi/utils.py",
"start_line": 70
} | {"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": " \"2XX\": \"Success\",\n \"3XX\": \"Redirection\",\n \"4XX\": \"Client Error\",\n \"5XX\": full{"status": "ok", "filepath": "fastapi/openapi/utils.py", "content": " \"2XX\": \"Success\",\n \"3XX\": \"Redirection\",\n \"4XX\": \"Client Error\",\n \"5XX\": \"Server Error\",\n \"DEFAULT\": \"Default Response\",\n}\n\n\ndef get_openapi_security_definitions(\n flat_dependant: Dependant,\n) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]:\n security_definitions = {}\n operation_security = []\n for security_requirement in flat_dependant.security_requirements:\n security_definition = jsonable_encoder(\n security_requirement.security_scheme.model,\n by_alias=True,\n exclude_none=True,\n )\n security_name = security_requirement.security_scheme.scheme_name\n security_definitions[security_name] = security_definition\n operation_security.append({security_name: security_requirement.scopes})\n return security_definitions, operation_security\n\n\ndef _get_openapi_operation_parameters(\n *,\n dependant: Dependant,\n model_name_map: ModelNameMap,\n field_mapping: Dict[\n Tuple[ModelField, Literal[\"validation\", \"serialization\"]], JsonSchemaValue\n ],\n separate_input_output_schemas: bool = True,\n) -> List[Dict[str, Any]]:\n parameters = []\n flat_dependant = get_flat_dependant(dependant, skip_repeats=True)\n path_params = _get_flat_fields_from_params(flat_dependant.path_params)\n query_params = _get_flat_fields_from_params(flat_dependant.query_params)\n header_params = _get_flat_fields_from_params(flat_dependant.header_params)\n cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params)\n parameter_groups = [\n (ParamTypes.path, path_params),\n (ParamTypes.query, query_params),\n (ParamTypes.header, header_params),\n (ParamTypes.cookie, cookie_params),\n ]\n default_convert_underscores = True\n if len(flat_dependant.header_params) == 1:\n first_field = flat_dependant.header |
| 7 | run_command | {
"command": "grep -rn \"OAuth2\" fastapi/security | head -20"
} | {"status": "ok", "stdout": "fastapi/security/__init__.py:9:from .oauth2 import OAuth2 as OAuth2\nfastapi/security/__init__.py:10:from .oauth2 import OAuth2Authofull{"status": "ok", "stdout": "fastapi/security/__init__.py:9:from .oauth2 import OAuth2 as OAuth2\nfastapi/security/__init__.py:10:from .oauth2 import OAuth2AuthorizationCodeBearer as OAuth2AuthorizationCodeBearer\nfastapi/security/__init__.py:11:from .oauth2 import OAuth2PasswordBearer as OAuth2PasswordBearer\nfastapi/security/__init__.py:12:from .oauth2 import OAuth2PasswordRequestForm as OAuth2PasswordRequestForm\nfastapi/security/__init__.py:13:from .oauth2 import OAuth2PasswordRequestFormStrict as OAuth2PasswordRequestFormStrict\nfastapi/security/oauth2.py:5:from fastapi.openapi.models import OAuth2 as OAuth2Model\nfastapi/security/oauth2.py:17:class OAuth2PasswordRequestForm:\nfastapi/security/oauth2.py:20: for an OAuth2 password flow.\nfastapi/security/oauth2.py:22: The OAuth2 specification dictates that for a password flow the data should be\nfastapi/security/oauth2.py:29: [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\nfastapi/security/oauth2.py:37: from fastapi.security import OAuth2PasswordRequestForm\nfastapi/security/oauth2.py:43: def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):\nfastapi/security/oauth2.py:55: Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.\nfastapi/security/oauth2.py:70: The OAuth2 spec says it is required and MUST be the fixed string\nfastapi/security/oauth2.py:73: `OAuth2PasswordRequestFormStrict` dependency.\nfastapi/security/oauth2.py:82: `username` string. The OAuth2 spec requires the exact field name\nfastapi/security/oauth2.py:92: `password` string. The OAuth2 spec requires the exact field name\nfastapi/security/oauth2.py:127: But the OAuth2 specification recommends sending the `client_id` and\nfastapi/security/oauth2.py:138: as part of the form fields. But the OAuth2 specification recommends\nf |
| 8 | read_file | {
"end_line": 300,
"filepath": "fastapi/security/oauth2.py",
"start_line": 1
} | {"status": "ok", "filepath": "fastapi/security/oauth2.py", "content": "from typing import Any, Dict, List, Optional, Union, cast\n\nfrom annotated_doc import Dofull{"status": "ok", "filepath": "fastapi/security/oauth2.py", "content": "from typing import Any, Dict, List, Optional, Union, cast\n\nfrom annotated_doc import Doc\nfrom fastapi.exceptions import HTTPException\nfrom fastapi.openapi.models import OAuth2 as OAuth2Model\nfrom fastapi.openapi.models import OAuthFlows as OAuthFlowsModel\nfrom fastapi.param_functions import Form\nfrom fastapi.security.base import SecurityBase\nfrom fastapi.security.utils import get_authorization_scheme_param\nfrom starlette.requests import Request\nfrom starlette.status import HTTP_401_UNAUTHORIZED\n\n# TODO: import from typing when deprecating Python 3.9\nfrom typing_extensions import Annotated\n\n\nclass OAuth2PasswordRequestForm:\n \"\"\"\n This is a dependency class to collect the `username` and `password` as form data\n for an OAuth2 password flow.\n\n The OAuth2 specification dictates that for a password flow the data should be\n collected using form data (instead of JSON) and that it should have the specific\n fields `username` and `password`.\n\n All the initialization parameters are extracted from the request.\n\n Read more about it in the\n [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n\n ## Example\n\n ```python\n from typing import Annotated\n\n from fastapi import Depends, FastAPI\n from fastapi.security import OAuth2PasswordRequestForm\n\n app = FastAPI()\n\n\n @app.post(\"/login\")\n def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):\n data = {}\n data[\"scopes\"] = []\n for scope in form_data.scopes:\n data[\"scopes\"].append(scope)\n if form_data.client_id:\n data[\"client_id\"] = form_data.client_id\n if form_data.client_secret:\n data[\"client_secret\"] = form_data.client_secret\n return data\n ```\n\n Note that for OAuth2 the scope `items:read` i |
| 9 | read_file | {
"end_line": 666,
"filepath": "fastapi/security/oauth2.py",
"start_line": 151
} | {"status": "ok", "filepath": "fastapi/security/oauth2.py", "content": "\n\nclass OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):\n \"\"\"\n This is full{"status": "ok", "filepath": "fastapi/security/oauth2.py", "content": "\n\nclass OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):\n \"\"\"\n This is a dependency class to collect the `username` and `password` as form data\n for an OAuth2 password flow.\n\n The OAuth2 specification dictates that for a password flow the data should be\n collected using form data (instead of JSON) and that it should have the specific\n fields `username` and `password`.\n\n All the initialization parameters are extracted from the request.\n\n The only difference between `OAuth2PasswordRequestFormStrict` and\n `OAuth2PasswordRequestForm` is that `OAuth2PasswordRequestFormStrict` requires the\n client to send the form field `grant_type` with the value `\"password\"`, which\n is required in the OAuth2 specification (it seems that for no particular reason),\n while for `OAuth2PasswordRequestForm` `grant_type` is optional.\n\n Read more about it in the\n [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).\n\n ## Example\n\n ```python\n from typing import Annotated\n\n from fastapi import Depends, FastAPI\n from fastapi.security import OAuth2PasswordRequestForm\n\n app = FastAPI()\n\n\n @app.post(\"/login\")\n def login(form_data: Annotated[OAuth2PasswordRequestFormStrict, Depends()]):\n data = {}\n data[\"scopes\"] = []\n for scope in form_data.scopes:\n data[\"scopes\"].append(scope)\n if form_data.client_id:\n data[\"client_id\"] = form_data.client_id\n if form_data.client_secret:\n data[\"client_secret\"] = form_data.client_secret\n return data\n ```\n\n Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.\n You could have custom internal logic to separate it by colon characters (`:`) or\n similar, and get the two parts `items` a |
| 10 | read_file | {
"end_line": 666,
"filepath": "fastapi/security/oauth2.py",
"start_line": 301
} | {"status": "ok", "filepath": "fastapi/security/oauth2.py", "content": " username=username,\n password=password,\n scope=scope,\n client_id=client_id,\n client_sfull{"status": "ok", "filepath": "fastapi/security/oauth2.py", "content": " username=username,\n password=password,\n scope=scope,\n client_id=client_id,\n client_secret=client_secret,\n )\n\n\nclass OAuth2(SecurityBase):\n \"\"\"\n This is the base class for OAuth2 authentication, an instance of it would be used\n as a dependency. All other OAuth2 classes inherit from it and customize it for\n each OAuth2 flow.\n\n You normally would not create a new class inheriting from it but use one of the\n existing subclasses, and maybe compose them if you want to support multiple flows.\n\n Read more about it in the\n [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/).\n \"\"\"\n\n def __init__(\n self,\n *,\n flows: Annotated[\n Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]],\n Doc(\n \"\"\"\n The dictionary of OAuth2 flows.\n \"\"\"\n ),\n ] = OAuthFlowsModel(),\n scheme_name: Annotated[\n Optional[str],\n Doc(\n \"\"\"\n Security scheme name.\n\n It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n \"\"\"\n ),\n ] = None,\n description: Annotated[\n Optional[str],\n Doc(\n \"\"\"\n Security scheme description.\n\n It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n \"\"\"\n ),\n ] = None,\n auto_error: Annotated[\n bool,\n Doc(\n \"\"\"\n By default, if no HTTP Authorization header is provided, required for\n OAuth2 authentication, it will automatically cancel the request and\n send the client an error.\n\n |
| 11 | read_file | {
"end_line": 550,
"filepath": "fastapi/security/oauth2.py",
"start_line": 451
} | {"status": "ok", "filepath": "fastapi/security/oauth2.py", "content": " description: Annotated[\n Optional[str],\n Doc(\n \"\"\"\n Security scheme description.\full{"status": "ok", "filepath": "fastapi/security/oauth2.py", "content": " description: Annotated[\n Optional[str],\n Doc(\n \"\"\"\n Security scheme description.\n\n It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n \"\"\"\n ),\n ] = None,\n auto_error: Annotated[\n bool,\n Doc(\n \"\"\"\n By default, if no HTTP Authorization header is provided, required for\n OAuth2 authentication, it will automatically cancel the request and\n send the client an error.\n\n If `auto_error` is set to `False`, when the HTTP Authorization header\n is not available, instead of erroring out, the dependency result will\n be `None`.\n\n This is useful when you want to have optional authentication.\n\n It is also useful when you want to have authentication that can be\n provided in one of multiple optional ways (for example, with OAuth2\n or in a cookie).\n \"\"\"\n ),\n ] = True,\n refreshUrl: Annotated[\n Optional[str],\n Doc(\n \"\"\"\n The URL to refresh the token and obtain a new one.\n \"\"\"\n ),\n ] = None,\n ):\n if not scopes:\n scopes = {}\n flows = OAuthFlowsModel(\n password=cast(\n Any,\n {\n \"tokenUrl\": tokenUrl,\n \"refreshUrl\": refreshUrl,\n \"scopes\": scopes,\n },\n )\n )\n super().__init__(\n flows=flows,\n scheme_name=scheme_name,\n description=description,\n auto_error=auto_error,\n )\n\n async def __call__(se |
| 12 | read_file | {
"end_line": 666,
"filepath": "fastapi/security/oauth2.py",
"start_line": 551
} | {"status": "ok", "filepath": "fastapi/security/oauth2.py", "content": " It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n \"\"\"\n ),\n full{"status": "ok", "filepath": "fastapi/security/oauth2.py", "content": " It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n \"\"\"\n ),\n ] = None,\n scopes: Annotated[\n Optional[Dict[str, str]],\n Doc(\n \"\"\"\n The OAuth2 scopes that would be required by the *path operations* that\n use this dependency.\n \"\"\"\n ),\n ] = None,\n description: Annotated[\n Optional[str],\n Doc(\n \"\"\"\n Security scheme description.\n\n It will be included in the generated OpenAPI (e.g. visible at `/docs`).\n \"\"\"\n ),\n ] = None,\n auto_error: Annotated[\n bool,\n Doc(\n \"\"\"\n By default, if no HTTP Authorization header is provided, required for\n OAuth2 authentication, it will automatically cancel the request and\n send the client an error.\n\n If `auto_error` is set to `False`, when the HTTP Authorization header\n is not available, instead of erroring out, the dependency result will\n be `None`.\n\n This is useful when you want to have optional authentication.\n\n It is also useful when you want to have authentication that can be\n provided in one of multiple optional ways (for example, with OAuth2\n or in a cookie).\n \"\"\"\n ),\n ] = True,\n ):\n if not scopes:\n scopes = {}\n flows = OAuthFlowsModel(\n authorizationCode=cast(\n Any,\n {\n \"authorizationUrl\": authorizationUrl,\n \"tokenUrl\": tokenUrl,\n \"refreshUrl\": refreshUrl,\n |
| 13 | read_file | {
"end_line": 100,
"filepath": "fastapi/openapi/models.py",
"start_line": 1
} | {"status": "ok", "filepath": "fastapi/openapi/models.py", "content": "from enum import Enum\nfrom typing import Any, Callable, Dict, Iterable, List, Optional, Sfull{"status": "ok", "filepath": "fastapi/openapi/models.py", "content": "from enum import Enum\nfrom typing import Any, Callable, Dict, Iterable, List, Optional, Set, Type, Union\n\nfrom fastapi._compat import (\n PYDANTIC_V2,\n CoreSchema,\n GetJsonSchemaHandler,\n JsonSchemaValue,\n _model_rebuild,\n with_info_plain_validator_function,\n)\nfrom fastapi.logger import logger\nfrom pydantic import AnyUrl, BaseModel, Field\nfrom typing_extensions import Annotated, Literal, TypedDict\nfrom typing_extensions import deprecated as typing_deprecated\n\ntry:\n import email_validator\n\n assert email_validator # make autoflake ignore the unused import\n from pydantic import EmailStr\nexcept ImportError: # pragma: no cover\n\n class EmailStr(str): # type: ignore\n @classmethod\n def __get_validators__(cls) -> Iterable[Callable[..., Any]]:\n yield cls.validate\n\n @classmethod\n def validate(cls, v: Any) -> str:\n logger.warning(\n \"email-validator not installed, email fields will be treated as str.\\n\"\n \"To install, run: pip install email-validator\"\n )\n return str(v)\n\n @classmethod\n def _validate(cls, __input_value: Any, _: Any) -> str:\n logger.warning(\n \"email-validator not installed, email fields will be treated as str.\\n\"\n \"To install, run: pip install email-validator\"\n )\n return str(__input_value)\n\n @classmethod\n def __get_pydantic_json_schema__(\n cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler\n ) -> JsonSchemaValue:\n return {\"type\": \"string\", \"format\": \"email\"}\n\n @classmethod\n def __get_pydantic_core_schema__(\n cls, source: Type[Any], handler: Callable[[Any], CoreSchema]\n ) -> CoreSchema:\n return with_info_plain_validator_function |
| 14 | read_file | {
"end_line": 451,
"filepath": "fastapi/openapi/models.py",
"start_line": 400
} | {"status": "ok", "filepath": "fastapi/openapi/models.py", "content": "class OAuth2(SecurityBase):\n type_: SecuritySchemeType = Field(default=SecuritySchemeTypefull{"status": "ok", "filepath": "fastapi/openapi/models.py", "content": "class OAuth2(SecurityBase):\n type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias=\"type\")\n flows: OAuthFlows\n\n\nclass OpenIdConnect(SecurityBase):\n type_: SecuritySchemeType = Field(\n default=SecuritySchemeType.openIdConnect, alias=\"type\"\n )\n openIdConnectUrl: str\n\n\nSecurityScheme = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer]\n\n\nclass Components(BaseModelWithConfig):\n schemas: Optional[Dict[str, Union[Schema, Reference]]] = None\n responses: Optional[Dict[str, Union[Response, Reference]]] = None\n parameters: Optional[Dict[str, Union[Parameter, Reference]]] = None\n examples: Optional[Dict[str, Union[Example, Reference]]] = None\n requestBodies: Optional[Dict[str, Union[RequestBody, Reference]]] = None\n headers: Optional[Dict[str, Union[Header, Reference]]] = None\n securitySchemes: Optional[Dict[str, Union[SecurityScheme, Reference]]] = None\n links: Optional[Dict[str, Union[Link, Reference]]] = None\n # Using Any for Specification Extensions\n callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference, Any]]] = None\n pathItems: Optional[Dict[str, Union[PathItem, Reference]]] = None\n\n\nclass Tag(BaseModelWithConfig):\n name: str\n description: Optional[str] = None\n externalDocs: Optional[ExternalDocumentation] = None\n\n\nclass OpenAPI(BaseModelWithConfig):\n openapi: str\n info: Info\n jsonSchemaDialect: Optional[str] = None\n servers: Optional[List[Server]] = None\n # Using Any for Specification Extensions\n paths: Optional[Dict[str, Union[PathItem, Any]]] = None\n webhooks: Optional[Dict[str, Union[PathItem, Reference]]] = None\n components: Optional[Components] = None\n security: Optional[List[Dict[str, List[str]]]] = None\n tags: Optional[List[Tag]] = None\n externalDocs: Optional[ExternalDocumentation] = None\n\n\n_model_rebuild |
| 15 | read_file | {
"end_line": 400,
"filepath": "fastapi/openapi/models.py",
"start_line": 350
} | {"status": "ok", "filepath": "fastapi/openapi/models.py", "content": " query = \"query\"\n header = \"header\"\n cookie = \"cookie\"\n\n\nclass APIKey(SecurityBfull{"status": "ok", "filepath": "fastapi/openapi/models.py", "content": " query = \"query\"\n header = \"header\"\n cookie = \"cookie\"\n\n\nclass APIKey(SecurityBase):\n type_: SecuritySchemeType = Field(default=SecuritySchemeType.apiKey, alias=\"type\")\n in_: APIKeyIn = Field(alias=\"in\")\n name: str\n\n\nclass HTTPBase(SecurityBase):\n type_: SecuritySchemeType = Field(default=SecuritySchemeType.http, alias=\"type\")\n scheme: str\n\n\nclass HTTPBearer(HTTPBase):\n scheme: Literal[\"bearer\"] = \"bearer\"\n bearerFormat: Optional[str] = None\n\n\nclass OAuthFlow(BaseModelWithConfig):\n refreshUrl: Optional[str] = None\n scopes: Dict[str, str] = {}\n\n\nclass OAuthFlowImplicit(OAuthFlow):\n authorizationUrl: str\n\n\nclass OAuthFlowPassword(OAuthFlow):\n tokenUrl: str\n\n\nclass OAuthFlowClientCredentials(OAuthFlow):\n tokenUrl: str\n\n\nclass OAuthFlowAuthorizationCode(OAuthFlow):\n authorizationUrl: str\n tokenUrl: str\n\n\nclass OAuthFlows(BaseModelWithConfig):\n implicit: Optional[OAuthFlowImplicit] = None\n password: Optional[OAuthFlowPassword] = None\n clientCredentials: Optional[OAuthFlowClientCredentials] = None\n authorizationCode: Optional[OAuthFlowAuthorizationCode] = None\n\n\nclass OAuth2(SecurityBase):\n", "start_line": 350, "end_line": 400, "total_lines": 451, "is_truncated": false} |
| 16 | run_command | {
"command": "python3 -c \"\nfrom fastapi import FastAPI, Depends\nfrom fastapi.security import OAuth2PasswordBearer, SecurityScopes\nfrom fastapi.openapi.utils import get_openapi\n\napp = FastAPI()\noauth2_scheme = OAuth2PasswordBearer(\n tokenUrl='token',\n scopes={'me': 'Read information about the current user.', 'admin': 'Admin access'}\n)\n\n@app.get('/me')\nasync def read_users_me(scopes: SecurityScopes, token: str = Depends(oauth2_scheme)):\n return {'token': token, 'scopes': scopes.scopes}\n\n@app.get('/admin')\nasync def read_users_admin(scopes: SecurityScopes, token: str = Depends(oauth2_scheme)):\n return {'token': token, 'scopes': scopes.scopes}\n\nopenapi_schema = get_openapi(\n title='Test OpenAPI',\n version='1.0.0',\n routes=app.routes,\n)\nimport json\nprint(json.dumps(openapi_schema, indent=2))\n\""
} | {"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"Test OpenAPI\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n \"/me\": {\nfull{"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"Test OpenAPI\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n \"/me\": {\n \"get\": {\n \"summary\": \"Read Users Me\",\n \"operationId\": \"read_users_me_me_get\",\n \"responses\": {\n \"200\": {\n \"description\": \"Successful Response\",\n \"content\": {\n \"application/json\": {\n \"schema\": {}\n }\n }\n }\n },\n \"security\": [\n {\n \"OAuth2PasswordBearer\": []\n }\n ]\n }\n },\n \"/admin\": {\n \"get\": {\n \"summary\": \"Read Users Admin\",\n \"operationId\": \"read_users_admin_admin_get\",\n \"responses\": {\n \"200\": {\n \"description\": \"Successful Response\",\n \"content\": {\n \"application/json\": {\n \"schema\": {}\n }\n }\n }\n },\n \"security\": [\n {\n \"OAuth2PasswordBearer\": []\n }\n ]\n }\n }\n },\n \"components\": {\n \"securitySchemes\": {\n \"OAuth2PasswordBearer\": {\n \"type\": \"oauth2\",\n \"flows\": {\n \"password\": {\n \"scopes\": {\n \"me\": \"Read information about the current user.\",\n \"admin\": \"Admin access\"\n },\n \"tokenUrl\": \"token\"\n }\n }\n }\n }\n }\n}\n", "exit_code": 0} |
| 17 | run_command | {
"command": "python3 -c \"\nfrom fastapi import FastAPI, Depends\nfrom fastapi.security import OAuth2PasswordBearer, SecurityScopes\nfrom fastapi.openapi.utils import get_openapi\n\napp = FastAPI()\noauth2_scheme_me = OAuth2PasswordBearer(\n tokenUrl='token',\n scopes={'me': 'Read information about the current user.'}\n)\noauth2_scheme_admin = OAuth2PasswordBearer(\n tokenUrl='token',\n scopes={'admin': 'Admin access'}\n)\n\n@app.get('/me')\nasync def read_users_me(token: str = Depends(oauth2_scheme_me)):\n return {'token': token}\n\n@app.get('/admin')\nasync def read_users_admin(token: str = Depends(oauth2_scheme_admin)):\n return {'token': token}\n\nopenapi_schema = get_openapi(\n title='Test OpenAPI',\n version='1.0.0',\n routes=app.routes,\n)\nimport json\nprint(json.dumps(openapi_schema, indent=2))\n\""
} | {"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"Test OpenAPI\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n \"/me\": {\nfull{"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"Test OpenAPI\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n \"/me\": {\n \"get\": {\n \"summary\": \"Read Users Me\",\n \"operationId\": \"read_users_me_me_get\",\n \"responses\": {\n \"200\": {\n \"description\": \"Successful Response\",\n \"content\": {\n \"application/json\": {\n \"schema\": {}\n }\n }\n }\n },\n \"security\": [\n {\n \"OAuth2PasswordBearer\": []\n }\n ]\n }\n },\n \"/admin\": {\n \"get\": {\n \"summary\": \"Read Users Admin\",\n \"operationId\": \"read_users_admin_admin_get\",\n \"responses\": {\n \"200\": {\n \"description\": \"Successful Response\",\n \"content\": {\n \"application/json\": {\n \"schema\": {}\n }\n }\n }\n },\n \"security\": [\n {\n \"OAuth2PasswordBearer\": []\n }\n ]\n }\n }\n },\n \"components\": {\n \"securitySchemes\": {\n \"OAuth2PasswordBearer\": {\n \"type\": \"oauth2\",\n \"flows\": {\n \"password\": {\n \"scopes\": {\n \"admin\": \"Admin access\"\n },\n \"tokenUrl\": \"token\"\n }\n }\n }\n }\n }\n}\n", "exit_code": 0} |
| 18 | run_command | {
"command": "python3 -c \"\nfrom fastapi import FastAPI, Depends, Security\nfrom fastapi.security import OAuth2PasswordBearer\nfrom fastapi.openapi.utils import get_openapi\n\napp = FastAPI()\noauth2_scheme = OAuth2PasswordBearer(\n tokenUrl='token',\n scopes={'me': 'Read information about the current user.', 'admin': 'Admin access'}\n)\n\n@app.get('/me')\nasync def read_users_me(token: str = Security(oauth2_scheme, scopes=['me'])):\n return {'token': token}\n\n@app.get('/admin')\nasync def read_users_admin(token: str = Security(oauth2_scheme, scopes=['admin'])):\n return {'token': token}\n\nopenapi_schema = get_openapi(\n title='Test OpenAPI',\n version='1.0.0',\n routes=app.routes,\n)\nimport json\nprint(json.dumps(openapi_schema, indent=2))\n\""
} | {"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"Test OpenAPI\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n \"/me\": {\nfull{"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"Test OpenAPI\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n \"/me\": {\n \"get\": {\n \"summary\": \"Read Users Me\",\n \"operationId\": \"read_users_me_me_get\",\n \"responses\": {\n \"200\": {\n \"description\": \"Successful Response\",\n \"content\": {\n \"application/json\": {\n \"schema\": {}\n }\n }\n }\n },\n \"security\": [\n {\n \"OAuth2PasswordBearer\": [\n \"me\"\n ]\n }\n ]\n }\n },\n \"/admin\": {\n \"get\": {\n \"summary\": \"Read Users Admin\",\n \"operationId\": \"read_users_admin_admin_get\",\n \"responses\": {\n \"200\": {\n \"description\": \"Successful Response\",\n \"content\": {\n \"application/json\": {\n \"schema\": {}\n }\n }\n }\n },\n \"security\": [\n {\n \"OAuth2PasswordBearer\": [\n \"admin\"\n ]\n }\n ]\n }\n }\n },\n \"components\": {\n \"securitySchemes\": {\n \"OAuth2PasswordBearer\": {\n \"type\": \"oauth2\",\n \"flows\": {\n \"password\": {\n \"scopes\": {\n \"me\": \"Read information about the current user.\",\n \"admin\": \"Admin access\"\n },\n \"tokenUrl\": \"token\"\n }\n }\n }\n }\n }\n}\n", "exit_code": 0} |
| 19 | run_command | {
"command": "python3 -c \"\nfrom fastapi import FastAPI, Depends, Security\nfrom fastapi.security import OAuth2PasswordBearer\nfrom fastapi.openapi.utils import get_openapi\n\napp = FastAPI()\noauth2_scheme_me = OAuth2PasswordBearer(\n tokenUrl='token',\n scopes={'me': 'Read information about the current user.'},\n scheme_name='OAuth2Me'\n)\noauth2_scheme_admin = OAuth2PasswordBearer(\n tokenUrl='token',\n scopes={'admin': 'Admin access'},\n scheme_name='OAuth2Admin'\n)\n\n@app.get('/me')\nasync def read_users_me(token: str = Security(oauth2_scheme_me, scopes=['me'])):\n return {'token': token}\n\n@app.get('/admin')\nasync def read_users_admin(token: str = Security(oauth2_scheme_admin, scopes=['admin'])):\n return {'token': token}\n\nopenapi_schema = get_openapi(\n title='Test OpenAPI',\n version='1.0.0',\n routes=app.routes,\n)\nimport json\nprint(json.dumps(openapi_schema, indent=2))\n\""
} | {"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"Test OpenAPI\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n \"/me\": {\nfull{"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"Test OpenAPI\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n \"/me\": {\n \"get\": {\n \"summary\": \"Read Users Me\",\n \"operationId\": \"read_users_me_me_get\",\n \"responses\": {\n \"200\": {\n \"description\": \"Successful Response\",\n \"content\": {\n \"application/json\": {\n \"schema\": {}\n }\n }\n }\n },\n \"security\": [\n {\n \"OAuth2Me\": [\n \"me\"\n ]\n }\n ]\n }\n },\n \"/admin\": {\n \"get\": {\n \"summary\": \"Read Users Admin\",\n \"operationId\": \"read_users_admin_admin_get\",\n \"responses\": {\n \"200\": {\n \"description\": \"Successful Response\",\n \"content\": {\n \"application/json\": {\n \"schema\": {}\n }\n }\n }\n },\n \"security\": [\n {\n \"OAuth2Admin\": [\n \"admin\"\n ]\n }\n ]\n }\n }\n },\n \"components\": {\n \"securitySchemes\": {\n \"OAuth2Me\": {\n \"type\": \"oauth2\",\n \"flows\": {\n \"password\": {\n \"scopes\": {\n \"me\": \"Read information about the current user.\"\n },\n \"tokenUrl\": \"token\"\n }\n }\n },\n \"OAuth2Admin\": {\n \"type\": \"oauth2\",\n \"flows\": {\n \"password\": {\n \"scopes\": {\n \"admin\": \"Admin access\"\n },\n \"tokenUrl\": \"token\"\n }\n }\n }\n }\n }\n}\n", "exit_code": 0} |
| 20 | run_command | {
"command": "python3 -c \"\nfrom fastapi import FastAPI, Depends\nfrom fastapi.security import OAuth2PasswordBearer\nfrom fastapi.openapi.utils import get_openapi\n\napp = FastAPI()\noauth2_scheme_me = OAuth2PasswordBearer(\n tokenUrl='token',\n scopes={'me': 'Read information about the current user.'}\n)\noauth2_scheme_admin = OAuth2PasswordBearer(\n tokenUrl='token',\n scopes={'admin': 'Admin access'}\n)\n\n@app.get('/me')\nasync def read_users_me(token: str = Depends(oauth2_scheme_me)):\n return {'token': token}\n\n@app.get('/admin')\nasync def read_users_admin(token: str = Depends(oauth2_scheme_admin)):\n return {'token': token}\n\nopenapi_schema = get_openapi(\n title='Test OpenAPI',\n version='1.0.0',\n routes=app.routes,\n)\nimport json\nprint(json.dumps(openapi_schema, indent=2))\n\""
} | {"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"Test OpenAPI\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n \"/me\": {\nfull{"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"Test OpenAPI\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n \"/me\": {\n \"get\": {\n \"summary\": \"Read Users Me\",\n \"operationId\": \"read_users_me_me_get\",\n \"responses\": {\n \"200\": {\n \"description\": \"Successful Response\",\n \"content\": {\n \"application/json\": {\n \"schema\": {}\n }\n }\n }\n },\n \"security\": [\n {\n \"OAuth2PasswordBearer\": []\n }\n ]\n }\n },\n \"/admin\": {\n \"get\": {\n \"summary\": \"Read Users Admin\",\n \"operationId\": \"read_users_admin_admin_get\",\n \"responses\": {\n \"200\": {\n \"description\": \"Successful Response\",\n \"content\": {\n \"application/json\": {\n \"schema\": {}\n }\n }\n }\n },\n \"security\": [\n {\n \"OAuth2PasswordBearer\": []\n }\n ]\n }\n }\n },\n \"components\": {\n \"securitySchemes\": {\n \"OAuth2PasswordBearer\": {\n \"type\": \"oauth2\",\n \"flows\": {\n \"password\": {\n \"scopes\": {\n \"admin\": \"Admin access\"\n },\n \"tokenUrl\": \"token\"\n }\n }\n }\n }\n }\n}\n", "exit_code": 0} |
| 21 | edit_file | {
"filepath": "fastapi/openapi/utils.py",
"new_string": " for security_requirement in flat_dependant.security_requirements:\n security_definition = jsonable_encoder(\n security_requirement.security_scheme.model,\n by_alias=True,\n exclude_none=True,\n )\n security_name = security_requirement.security_scheme.scheme_name\n if security_name in security_definitions:\n # Deduplicate security schemes with different scopes by merging them\n # if they are OAuth2 schemes.\n existing_definition = security_definitions[security_name]\n if (\n existing_definition.get(\"type\") == \"oauth2\"\n and security_definition.get(\"type\") == \"oauth2\"\n ):\n for flow_name, flow_data in security_definition.get(\"flows\", {}).items():\n existing_flow = existing_definition.setdefault(\"flows\", {}).setdefault(flow_name, {})\n existing_flow.setdefault(\"scopes\", {}).update(flow_data.get(\"scopes\", {}))\n else:\n security_definitions[security_name] = security_definition\n else:\n security_definitions[security_name] = security_definition\n operation_security.append({security_name: security_requirement.scopes})\n return security_definitions, operation_security",
"old_string": " for security_requirement in flat_dependant.security_requirements:\n security_definition = jsonable_encoder(\n security_requirement.security_scheme.model,\n by_alias=True,\n exclude_none=True,\n )\n security_name = security_requirement.security_scheme.scheme_name\n security_definitions[security_name] = security_definition\n operation_security.append({security_name: security_requirement.scopes})\n return security_definitions, operation_security"
} | {"status": "ok", "filepath": "fastapi/openapi/utils.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/openapi/utils.py\n+++ b/fastapi/openapi/ufull{"status": "ok", "filepath": "fastapi/openapi/utils.py", "occurrences": 1, "strategy": "exact", "diff": "--- a/fastapi/openapi/utils.py\n+++ b/fastapi/openapi/utils.py\n@@ -87,7 +87,21 @@\n exclude_none=True,\n )\n security_name = security_requirement.security_scheme.scheme_name\n- security_definitions[security_name] = security_definition\n+ if security_name in security_definitions:\n+ # Deduplicate security schemes with different scopes by merging them\n+ # if they are OAuth2 schemes.\n+ existing_definition = security_definitions[security_name]\n+ if (\n+ existing_definition.get(\"type\") == \"oauth2\"\n+ and security_definition.get(\"type\") == \"oauth2\"\n+ ):\n+ for flow_name, flow_data in security_definition.get(\"flows\", {}).items():\n+ existing_flow = existing_definition.setdefault(\"flows\", {}).setdefault(flow_name, {})\n+ existing_flow.setdefault(\"scopes\", {}).update(flow_data.get(\"scopes\", {}))\n+ else:\n+ security_definitions[security_name] = security_definition\n+ else:\n+ security_definitions[security_name] = security_definition\n operation_security.append({security_name: security_requirement.scopes})\n return security_definitions, operation_security\n \n", "is_truncated": false} |
| 22-25 ร4 | run_command | {
"command": "python3 -c \"\nfrom fastapi import FastAPI, Depends\nfrom fastapi.security import OAuth2PasswordBearer\nfrom fastapi.openapi.utils import get_openapi\n\napp = FastAPI()\noauth2_scheme_me = OAuth2PasswordBearer(\n tokenUrl='token',\n scopes={'me': 'Read information about the current user.'}\n)\noauth2_scheme_admin = OAuth2PasswordBearer(\n tokenUrl='token',\n scopes={'admin': 'Admin access'}\n)\n\n@app.get('/me')\nasync def read_users_me(token: str = Depends(oauth2_scheme_me)):\n return {'token': token}\n\n@app.get('/admin')\nasync def read_users_admin(token: str = Depends(oauth2_scheme_admin)):\n return {'token': token}\n\nopenapi_schema = get_openapi(\n title='Test OpenAPI',\n version='1.0.0',\n routes=app.routes,\n)\nimport json\nprint(json.dumps(openapi_schema, indent=2))\n\""
} | {"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"Test OpenAPI\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n \"/me\": {\nfull{"status": "ok", "stdout": "{\n \"openapi\": \"3.1.0\",\n \"info\": {\n \"title\": \"Test OpenAPI\",\n \"version\": \"1.0.0\"\n },\n \"paths\": {\n \"/me\": {\n \"get\": {\n \"summary\": \"Read Users Me\",\n \"operationId\": \"read_users_me_me_get\",\n \"responses\": {\n \"200\": {\n \"description\": \"Successful Response\",\n \"content\": {\n \"application/json\": {\n \"schema\": {}\n }\n }\n }\n },\n \"security\": [\n {\n \"OAuth2PasswordBearer\": []\n }\n ]\n }\n },\n \"/admin\": {\n \"get\": {\n \"summary\": \"Read Users Admin\",\n \"operationId\": \"read_users_admin_admin_get\",\n \"responses\": {\n \"200\": {\n \"description\": \"Successful Response\",\n \"content\": {\n \"application/json\": {\n \"schema\": {}\n }\n }\n }\n },\n \"security\": [\n {\n \"OAuth2PasswordBearer\": []\n }\n ]\n }\n }\n },\n \"components\": {\n \"securitySchemes\": {\n \"OAuth2PasswordBearer\": {\n \"type\": \"oauth2\",\n \"flows\": {\n \"password\": {\n \"scopes\": {\n \"admin\": \"Admin access\"\n },\n \"tokenUrl\": \"token\"\n }\n }\n }\n }\n }\n}\n", "exit_code": 0} |
diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py
index dbc93d28..88f92691 100644
--- a/fastapi/openapi/utils.py
+++ b/fastapi/openapi/utils.py
@@ -87,7 +87,21 @@ def get_openapi_security_definitions(
exclude_none=True,
)
security_name = security_requirement.security_scheme.scheme_name
- security_definitions[security_name] = security_definition
+ if security_name in security_definitions:
+ # Deduplicate security schemes with different scopes by merging them
+ # if they are OAuth2 schemes.
+ existing_definition = security_definitions[security_name]
+ if (
+ existing_definition.get("type") == "oauth2"
+ and security_definition.get("type") == "oauth2"
+ ):
+ for flow_name, flow_data in security_definition.get("flows", {}).items():
+ existing_flow = existing_definition.setdefault("flows", {}).setdefault(flow_name, {})
+ existing_flow.setdefault("scopes", {}).update(flow_data.get("scopes", {}))
+ else:
+ security_definitions[security_name] = security_definition
+ else:
+ security_definitions[security_name] = security_definition
operation_security.append({security_name: security_requirement.scopes})
return security_definitions, operation_security
โ
โ {"OAuth2AuthorizationCodeBearer": ["read", "write"]}], โ
โ }, โ
โ }, โ
โ }, โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
These changes are not applied.
Use --inline-snapshot=fix to apply them, or use the interactive mode with
--inline-snapshot=review
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ Problems โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
inline-snapshot is not able to format your code.
This issue can be solved by:
* installing inline-snapshot[black] which gives you the same formatting like in
older versions
* adding a `format-command` to your pyproject.toml (see
https://15r10nk.github.io/inline-snapshot/latest/configuration/#format-command
for more information).
==================================== ERRORS ====================================
___________________ ERROR at teardown of test_openapi_schema ___________________
some snapshots in this test have incorrect values.
If you just created this value with --inline-snapshot=create, the value is now created and you can ignore this message.
=================================== FAILURES ===================================
_____________________________ test_openapi_schema ______________________________
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
> assert response.json() == snapshot(
{
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
"get": {
"summary": "Root",
"operationId": "root__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
"security": [{"OAuth2AuthorizationCodeBearer": []}],
}
},
"/items/": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
"security": [
{"OAuth2AuthorizationCodeBearer": ["read"]},
],
},
"post": {
"summary": "Create Item",
"operationId": "create_item_items__post",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
"security": [
{"OAuth2AuthorizationCodeBearer": ["read", "write"]},
],
},
},
},
"components": {
"securitySchemes": {
"OAuth2AuthorizationCodeBearer": {
"type": "oauth2",
"flows": {
"authorizationCode": {
"scopes": {
"read": "Read access",
"write": "Write access",
},
"authorizationUrl": "authorize",
"tokenUrl": "token",
}
},
}
}
},
}
)
E AssertionError: assert {'openapi': '... 'token'}}}}}} == {'openapi': '... 'token'}}}}}}
E
E Omitting 3 identical items, use -vv to show
E Differing items:
E {'paths': {'/': {'get': {'summary': 'Root', 'operationId': 'root__get', 'responses': {'200': {'description': 'Successf...2AuthorizationCodeBearer': []}, {'OAuth2AuthorizationCodeBearer': [...]}, {'OAuth2AuthorizationCodeBearer': [...]}]}}}} != {'paths': {'/': {'get': {'summary': 'Root', 'operationId': 'root__get', 'responses': {'200': {'description': 'Successf...: {'description': 'Successful Response', 'content': {...}}}, 'security': [{'OAuth2AuthorizationCodeBearer': [...]}]}}}}
E Use -v to get more diff
tests/test_security_oauth2_authorization_code_bearer_scopes_openapi.py:66: AssertionError
=============================== warnings summary ===============================
../../../../../../kaggle/tmp/envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45
/kaggle/tmp/envs/overlays/starlette-0.50.0-py3-none-any/starlette/testclient.py:45: DeprecationWarning: The anyio.abc.BlockingPortal alias is deprecated, use anyio.from_thread.BlockingPortal instead.
_PortalFactoryType = Callable[[], AbstractContextManager[anyio.abc.BlockingPortal]]
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 2 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
1 failed, 3 passed, 1 warning, 1 error in 0.82s