mirror of https://github.com/tiangolo/fastapi.git
Merge branch 'master' into feat/enhanced-json-decode-errors
This commit is contained in:
commit
2fbf6f31fd
|
|
@ -14,11 +14,13 @@ hide:
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
|
* 🐛 Fix TYPE_CHECKING annotations for Python 3.14 (PEP 649). PR [#14789](https://github.com/fastapi/fastapi/pull/14789) by [@mgu](https://github.com/mgu).
|
||||||
* 🐛 Strip whitespaces from `Authorization` header credentials. PR [#14786](https://github.com/fastapi/fastapi/pull/14786) by [@WaveTheory1](https://github.com/WaveTheory1).
|
* 🐛 Strip whitespaces from `Authorization` header credentials. PR [#14786](https://github.com/fastapi/fastapi/pull/14786) by [@WaveTheory1](https://github.com/WaveTheory1).
|
||||||
* 🐛 Fix OpenAPI duplication of `anyOf` refs for app-level responses with specified `content` and `model` as `Union`. PR [#14463](https://github.com/fastapi/fastapi/pull/14463) by [@DJMcoder](https://github.com/DJMcoder).
|
* 🐛 Fix OpenAPI duplication of `anyOf` refs for app-level responses with specified `content` and `model` as `Union`. PR [#14463](https://github.com/fastapi/fastapi/pull/14463) by [@DJMcoder](https://github.com/DJMcoder).
|
||||||
|
|
||||||
### Refactors
|
### Refactors
|
||||||
|
|
||||||
|
* 🎨 Tweak types for mypy. PR [#14816](https://github.com/fastapi/fastapi/pull/14816) by [@tiangolo](https://github.com/tiangolo).
|
||||||
* 🏷️ Re-export `IncEx` type from Pydantic instead of duplicating it. PR [#14641](https://github.com/fastapi/fastapi/pull/14641) by [@mvanderlee](https://github.com/mvanderlee).
|
* 🏷️ Re-export `IncEx` type from Pydantic instead of duplicating it. PR [#14641](https://github.com/fastapi/fastapi/pull/14641) by [@mvanderlee](https://github.com/mvanderlee).
|
||||||
* 💡 Update comment for Pydantic internals. PR [#14814](https://github.com/fastapi/fastapi/pull/14814) by [@tiangolo](https://github.com/tiangolo).
|
* 💡 Update comment for Pydantic internals. PR [#14814](https://github.com/fastapi/fastapi/pull/14814) by [@tiangolo](https://github.com/tiangolo).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -204,7 +204,12 @@ def _get_signature(call: Callable[..., Any]) -> inspect.Signature:
|
||||||
except NameError:
|
except NameError:
|
||||||
# Handle type annotations with if TYPE_CHECKING, not used by FastAPI
|
# Handle type annotations with if TYPE_CHECKING, not used by FastAPI
|
||||||
# e.g. dependency return types
|
# e.g. dependency return types
|
||||||
signature = inspect.signature(call)
|
if sys.version_info >= (3, 14):
|
||||||
|
from annotationlib import Format
|
||||||
|
|
||||||
|
signature = inspect.signature(call, annotation_format=Format.FORWARDREF)
|
||||||
|
else:
|
||||||
|
signature = inspect.signature(call)
|
||||||
else:
|
else:
|
||||||
signature = inspect.signature(call)
|
signature = inspect.signature(call)
|
||||||
return signature
|
return signature
|
||||||
|
|
|
||||||
|
|
@ -219,9 +219,9 @@ def jsonable_encoder(
|
||||||
if isinstance(obj, encoder_type):
|
if isinstance(obj, encoder_type):
|
||||||
return encoder_instance(obj)
|
return encoder_instance(obj)
|
||||||
if include is not None and not isinstance(include, (set, dict)):
|
if include is not None and not isinstance(include, (set, dict)):
|
||||||
include = set(include)
|
include = set(include) # type: ignore[assignment]
|
||||||
if exclude is not None and not isinstance(exclude, (set, dict)):
|
if exclude is not None and not isinstance(exclude, (set, dict)):
|
||||||
exclude = set(exclude)
|
exclude = set(exclude) # type: ignore[assignment]
|
||||||
if isinstance(obj, BaseModel):
|
if isinstance(obj, BaseModel):
|
||||||
obj_dict = obj.model_dump(
|
obj_dict = obj.model_dump(
|
||||||
mode="json",
|
mode="json",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
from typing import TYPE_CHECKING, Annotated
|
||||||
|
|
||||||
|
from fastapi import Depends, FastAPI
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
from .utils import needs_py314
|
||||||
|
|
||||||
|
if TYPE_CHECKING: # pragma: no cover
|
||||||
|
|
||||||
|
class DummyUser: ...
|
||||||
|
|
||||||
|
|
||||||
|
@needs_py314
|
||||||
|
def test_stringified_annotation():
|
||||||
|
# python3.14: Use forward reference without "from __future__ import annotations"
|
||||||
|
async def get_current_user() -> DummyUser | None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def get(
|
||||||
|
current_user: Annotated[DummyUser | None, Depends(get_current_user)],
|
||||||
|
) -> str:
|
||||||
|
return "hello world"
|
||||||
|
|
||||||
|
response = client.get("/")
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import importlib
|
import importlib
|
||||||
|
import sys
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import Annotated, Any
|
from typing import Annotated, Any
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
@ -12,8 +13,13 @@ from fastapi.testclient import TestClient
|
||||||
name="module",
|
name="module",
|
||||||
params=[
|
params=[
|
||||||
"tutorial008_py39",
|
"tutorial008_py39",
|
||||||
# Fails with `NameError: name 'DepA' is not defined`
|
pytest.param(
|
||||||
pytest.param("tutorial008_an_py39", marks=pytest.mark.xfail),
|
"tutorial008_an_py39",
|
||||||
|
marks=pytest.mark.xfail(
|
||||||
|
sys.version_info < (3, 14),
|
||||||
|
reason="Fails with `NameError: name 'DepA' is not defined`",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def get_module(request: pytest.FixtureRequest):
|
def get_module(request: pytest.FixtureRequest):
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ needs_py39 = pytest.mark.skipif(sys.version_info < (3, 9), reason="requires pyth
|
||||||
needs_py310 = pytest.mark.skipif(
|
needs_py310 = pytest.mark.skipif(
|
||||||
sys.version_info < (3, 10), reason="requires python3.10+"
|
sys.version_info < (3, 10), reason="requires python3.10+"
|
||||||
)
|
)
|
||||||
needs_py_lt_314 = pytest.mark.skipif(
|
needs_py314 = pytest.mark.skipif(
|
||||||
sys.version_info >= (3, 14), reason="requires python3.13-"
|
sys.version_info < (3, 14), reason="requires python3.14+"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue