@@ -152,17 +159,17 @@ connect_args={"check_same_thread": False}
这是为了防止意外地为不同的事物(不同的请求)共享相同的连接。
- 但是在 FastAPI 中,普遍使用def函数,多个线程可以为同一个请求与数据库交互,所以我们需要使用`connect_args={"check_same_thread": False}`来让SQLite允许这样。
+ 但是在 FastAPI 中,使用普通函数(def)时,多个线程可以为同一个请求与数据库交互,所以我们需要使用`connect_args={"check_same_thread": False}`来让SQLite允许这样。
此外,我们将确保每个请求都在依赖项中获得自己的数据库连接会话,因此不需要该默认机制。
### 创建一个`SessionLocal`类
-每个实例`SessionLocal`都会是一个数据库会话。当然该类本身还不是数据库会话。
+每个`SessionLocal`类的实例都会是一个数据库会话。当然该类本身还不是数据库会话。
但是一旦我们创建了一个`SessionLocal`类的实例,这个实例将是实际的数据库会话。
-我们命名它是`SessionLocal`为了将它与我们从 SQLAlchemy 导入的`Session`区别开来。
+我们将它命名为`SessionLocal`是为了将它与我们从 SQLAlchemy 导入的`Session`区别开来。
稍后我们将使用`Session`(从 SQLAlchemy 导入的那个)。
@@ -176,7 +183,7 @@ connect_args={"check_same_thread": False}
现在我们将使用`declarative_base()`返回一个类。
-稍后我们将用这个类继承,来创建每个数据库模型或类(ORM 模型):
+稍后我们将继承这个类,来创建每个数据库模型或类(ORM 模型):
```Python hl_lines="13"
{!../../../docs_src/sql_databases/sql_app/database.py!}
@@ -209,7 +216,7 @@ connect_args={"check_same_thread": False}
### 创建模型属性/列
-现在创建所有模型(类)属性。
+现在创建所有模型(类)的属性。
这些属性中的每一个都代表其相应数据库表中的一列。
@@ -252,13 +259,13 @@ connect_args={"check_same_thread": False}
### 创建初始 Pydantic*模型*/模式
-创建一个`ItemBase`和`UserBase`Pydantic*模型*(或者我们说“schema”)以及在创建或读取数据时具有共同的属性。
+创建一个`ItemBase`和`UserBase`Pydantic*模型*(或者我们说“schema”),他们拥有创建或读取数据时具有的共同属性。
-`ItemCreate`为 创建一个`UserCreate`继承自它们的所有属性(因此它们将具有相同的属性),以及创建所需的任何其他数据(属性)。
+然后创建一个继承自他们的`ItemCreate`和`UserCreate`,并添加创建时所需的其他数据(或属性)。
因此在创建时也应当有一个`password`属性。
-但是为了安全起见,`password`不会出现在其他同类 Pydantic*模型*中,例如用户请求时不应该从 API 返回响应中包含它。
+但是为了安全起见,`password`不会出现在其他同类 Pydantic*模型*中,例如通过API读取一个用户数据时,它不应当包含在内。
=== "Python 3.10+"
@@ -329,7 +336,7 @@ name: str
现在,在用于查询的 Pydantic*模型*`Item`中`User`,添加一个内部`Config`类。
-此类[`Config`](https://pydantic-docs.helpmanual.io/usage/model_config/)用于为 Pydantic 提供配置。
+此类[`Config`](https://docs.pydantic.dev/latest/api/config/)用于为 Pydantic 提供配置。
在`Config`类中,设置属性`orm_mode = True`。
@@ -368,7 +375,7 @@ Pydantic`orm_mode`将告诉 Pydantic*模型*读取数据,即它不是一个`di
id = data["id"]
```
-尝试从属性中获取它,如:
+它还会尝试从属性中获取它,如:
```Python
id = data.id
@@ -404,7 +411,7 @@ current_user.items
在这个文件中,我们将编写可重用的函数用来与数据库中的数据进行交互。
-**CRUD**分别为:**增加**、**查询**、**更改**和**删除**,即增删改查。
+**CRUD**分别为:增加(**C**reate)、查询(**R**ead)、更改(**U**pdate)、删除(**D**elete),即增删改查。
...虽然在这个例子中我们只是新增和查询。
@@ -414,7 +421,7 @@ current_user.items
导入之前的`models`(SQLAlchemy 模型)和`schemas`(Pydantic*模型*/模式)。
-创建一些实用函数来完成:
+创建一些工具函数来完成:
* 通过 ID 和电子邮件查询单个用户。
* 查询多个用户。
@@ -429,14 +436,14 @@ current_user.items
### 创建数据
-现在创建实用程序函数来创建数据。
+现在创建工具函数来创建数据。
它的步骤是:
* 使用您的数据创建一个 SQLAlchemy 模型*实例。*
-* 使用`add`来将该实例对象添加到您的数据库。
-* 使用`commit`来对数据库的事务提交(以便保存它们)。
-* 使用`refresh`来刷新您的数据库实例(以便它包含来自数据库的任何新数据,例如生成的 ID)。
+* 使用`add`来将该实例对象添加到数据库会话。
+* 使用`commit`来将更改提交到数据库(以便保存它们)。
+* 使用`refresh`来刷新您的实例对象(以便它包含来自数据库的任何新数据,例如生成的 ID)。
```Python hl_lines="18-24 31-36"
{!../../../docs_src/sql_databases/sql_app/crud.py!}
@@ -505,11 +512,11 @@ current_user.items
现在使用我们在`sql_app/database.py`文件中创建的`SessionLocal`来创建依赖项。
-我们需要每个请求有一个独立的数据库会话/连接(`SessionLocal`),在所有请求中使用相同的会话,然后在请求完成后关闭它。
+我们需要每个请求有一个独立的数据库会话/连接(`SessionLocal`),在整个请求中使用相同的会话,然后在请求完成后关闭它。
然后将为下一个请求创建一个新会话。
-为此,我们将创建一个新的依赖项`yield`,正如前面关于[Dependencies with`yield`](https://fastapi.tiangolo.com/zh/tutorial/dependencies/dependencies-with-yield/)的部分中所解释的那样。
+为此,我们将创建一个包含`yield`的依赖项,正如前面关于[Dependencies with`yield`](https://fastapi.tiangolo.com/zh/tutorial/dependencies/dependencies-with-yield/)的部分中所解释的那样。
我们的依赖项将创建一个新的 SQLAlchemy `SessionLocal`,它将在单个请求中使用,然后在请求完成后关闭它。
@@ -729,13 +736,13 @@ $ uvicorn sql_app.main:app --reload
## 中间件替代数据库会话
-如果你不能使用依赖项`yield`——例如,如果你没有使用**Python 3.7**并且不能安装上面提到的**Python 3.6**的“backports” ——你可以在类似的“中间件”中设置会话方法。
+如果你不能使用带有`yield`的依赖项——例如,如果你没有使用**Python 3.7**并且不能安装上面提到的**Python 3.6**的“backports” ——你可以使用类似的方法在“中间件”中设置会话。
-“中间件”基本功能是一个为每个请求执行的函数在请求之前进行执行相应的代码,以及在请求执行之后执行相应的代码。
+“中间件”基本上是一个对每个请求都执行的函数,其中一些代码在端点函数之前执行,另一些代码在端点函数之后执行。
### 创建中间件
-我们将添加中间件(只是一个函数)将为每个请求创建一个新的 SQLAlchemy`SessionLocal`,将其添加到请求中,然后在请求完成后关闭它。
+我们要添加的中间件(只是一个函数)将为每个请求创建一个新的 SQLAlchemy`SessionLocal`,将其添加到请求中,然后在请求完成后关闭它。
=== "Python 3.9+"
@@ -760,7 +767,7 @@ $ uvicorn sql_app.main:app --reload
`request.state`是每个`Request`对象的属性。它用于存储附加到请求本身的任意对象,例如本例中的数据库会话。您可以在[Starlette 的关于`Request`state](https://www.starlette.io/requests/#other-state)的文档中了解更多信息。
-对于这种情况下,它帮助我们确保在所有请求中使用单个数据库会话,然后关闭(在中间件中)。
+对于这种情况下,它帮助我们确保在整个请求中使用单个数据库会话,然后关闭(在中间件中)。
### 使用`yield`依赖项与使用中间件的区别
@@ -776,9 +783,9 @@ $ uvicorn sql_app.main:app --reload
* 即使处理该请求的*路径操作*不需要数据库。
!!! tip
- `tyield`当依赖项 足以满足用例时,使用`tyield`依赖项方法会更好。
+ 最好使用带有yield的依赖项,如果这足够满足用例需求
!!! info
- `yield`的依赖项是最近刚加入**FastAPI**中的。
+ 带有`yield`的依赖项是最近刚加入**FastAPI**中的。
所以本教程的先前版本只有带有中间件的示例,并且可能有多个应用程序使用中间件进行数据库会话管理。
diff --git a/docs/zh/docs/tutorial/testing.md b/docs/zh/docs/tutorial/testing.md
index 77fff7596..69841978c 100644
--- a/docs/zh/docs/tutorial/testing.md
+++ b/docs/zh/docs/tutorial/testing.md
@@ -8,7 +8,7 @@
## 使用 `TestClient`
-!!! 信息
+!!! info "信息"
要使用 `TestClient`,先要安装
`httpx`.
例:`pip install httpx`.
@@ -27,7 +27,7 @@
{!../../../docs_src/app_testing/tutorial001.py!}
```
-!!! 提示
+!!! tip "提示"
注意测试函数是普通的 `def`,不是 `async def`。
还有client的调用也是普通的调用,不是用 `await`。
@@ -39,7 +39,7 @@
**FastAPI** 提供了和 `starlette.testclient` 一样的 `fastapi.testclient`,只是为了方便开发者。但它直接来自Starlette。
-!!! 提示
+!!! tip "提示"
除了发送请求之外,如果你还想测试时在FastAPI应用中调用 `async` 函数(例如异步数据库函数), 可以在高级教程中看下 [Async Tests](../advanced/async-tests.md){.internal-link target=_blank} 。
## 分离测试
@@ -50,7 +50,7 @@
### **FastAPI** app 文件
-假设你有一个像 [更大的应用](./bigger-applications.md){.internal-link target=_blank} 中所描述的文件结构:
+假设你有一个像 [更大的应用](bigger-applications.md){.internal-link target=_blank} 中所描述的文件结构:
```
.
@@ -130,7 +130,7 @@
=== "Python 3.10+ non-Annotated"
- !!! tip
+ !!! tip "提示"
Prefer to use the `Annotated` version if possible.
```Python
@@ -139,7 +139,7 @@
=== "Python 3.8+ non-Annotated"
- !!! tip
+ !!! tip "提示"
Prefer to use the `Annotated` version if possible.
```Python
@@ -168,7 +168,7 @@
关于如何传数据给后端的更多信息 (使用`httpx` 或 `TestClient`),请查阅
HTTPX 文档.
-!!! 信息
+!!! info "信息"
注意 `TestClient` 接收可以被转化为JSON的数据,而不是Pydantic模型。
如果你在测试中有一个Pydantic模型,并且你想在测试时发送它的数据给应用,你可以使用在[JSON Compatible Encoder](encoder.md){.internal-link target=_blank}介绍的`jsonable_encoder` 。
diff --git a/docs_src/app_testing/app_b/test_main.py b/docs_src/app_testing/app_b/test_main.py
index 4e2b98e23..4e1c51ecc 100644
--- a/docs_src/app_testing/app_b/test_main.py
+++ b/docs_src/app_testing/app_b/test_main.py
@@ -21,7 +21,7 @@ def test_read_item_bad_token():
assert response.json() == {"detail": "Invalid X-Token header"}
-def test_read_inexistent_item():
+def test_read_nonexistent_item():
response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
assert response.status_code == 404
assert response.json() == {"detail": "Item not found"}
diff --git a/docs_src/app_testing/app_b_an/test_main.py b/docs_src/app_testing/app_b_an/test_main.py
index d186b8ecb..e2eda449d 100644
--- a/docs_src/app_testing/app_b_an/test_main.py
+++ b/docs_src/app_testing/app_b_an/test_main.py
@@ -21,7 +21,7 @@ def test_read_item_bad_token():
assert response.json() == {"detail": "Invalid X-Token header"}
-def test_read_inexistent_item():
+def test_read_nonexistent_item():
response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
assert response.status_code == 404
assert response.json() == {"detail": "Item not found"}
diff --git a/docs_src/app_testing/app_b_an_py310/test_main.py b/docs_src/app_testing/app_b_an_py310/test_main.py
index d186b8ecb..e2eda449d 100644
--- a/docs_src/app_testing/app_b_an_py310/test_main.py
+++ b/docs_src/app_testing/app_b_an_py310/test_main.py
@@ -21,7 +21,7 @@ def test_read_item_bad_token():
assert response.json() == {"detail": "Invalid X-Token header"}
-def test_read_inexistent_item():
+def test_read_nonexistent_item():
response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
assert response.status_code == 404
assert response.json() == {"detail": "Item not found"}
diff --git a/docs_src/app_testing/app_b_an_py39/test_main.py b/docs_src/app_testing/app_b_an_py39/test_main.py
index d186b8ecb..e2eda449d 100644
--- a/docs_src/app_testing/app_b_an_py39/test_main.py
+++ b/docs_src/app_testing/app_b_an_py39/test_main.py
@@ -21,7 +21,7 @@ def test_read_item_bad_token():
assert response.json() == {"detail": "Invalid X-Token header"}
-def test_read_inexistent_item():
+def test_read_nonexistent_item():
response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
assert response.status_code == 404
assert response.json() == {"detail": "Item not found"}
diff --git a/docs_src/app_testing/app_b_py310/test_main.py b/docs_src/app_testing/app_b_py310/test_main.py
index 4e2b98e23..4e1c51ecc 100644
--- a/docs_src/app_testing/app_b_py310/test_main.py
+++ b/docs_src/app_testing/app_b_py310/test_main.py
@@ -21,7 +21,7 @@ def test_read_item_bad_token():
assert response.json() == {"detail": "Invalid X-Token header"}
-def test_read_inexistent_item():
+def test_read_nonexistent_item():
response = client.get("/items/baz", headers={"X-Token": "coneofsilence"})
assert response.status_code == 404
assert response.json() == {"detail": "Item not found"}
diff --git a/docs_src/custom_docs_ui/tutorial001.py b/docs_src/custom_docs_ui/tutorial001.py
index 4384433e3..f7ceb0c2f 100644
--- a/docs_src/custom_docs_ui/tutorial001.py
+++ b/docs_src/custom_docs_ui/tutorial001.py
@@ -14,8 +14,8 @@ async def custom_swagger_ui_html():
openapi_url=app.openapi_url,
title=app.title + " - Swagger UI",
oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url,
- swagger_js_url="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-bundle.js",
- swagger_css_url="https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui.css",
+ swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js",
+ swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css",
)
diff --git a/docs_src/custom_response/tutorial006c.py b/docs_src/custom_response/tutorial006c.py
index db87a9389..87c720364 100644
--- a/docs_src/custom_response/tutorial006c.py
+++ b/docs_src/custom_response/tutorial006c.py
@@ -6,4 +6,4 @@ app = FastAPI()
@app.get("/pydantic", response_class=RedirectResponse, status_code=302)
async def redirect_pydantic():
- return "https://pydantic-docs.helpmanual.io/"
+ return "https://docs.pydantic.dev/"
diff --git a/docs_src/dependencies/tutorial005_an.py b/docs_src/dependencies/tutorial005_an.py
index 6785099da..1d78c17a2 100644
--- a/docs_src/dependencies/tutorial005_an.py
+++ b/docs_src/dependencies/tutorial005_an.py
@@ -21,6 +21,6 @@ def query_or_cookie_extractor(
@app.get("/items/")
async def read_query(
- query_or_default: Annotated[str, Depends(query_or_cookie_extractor)]
+ query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
diff --git a/docs_src/dependencies/tutorial005_an_py310.py b/docs_src/dependencies/tutorial005_an_py310.py
index 6c0aa0b36..5ccfc62bd 100644
--- a/docs_src/dependencies/tutorial005_an_py310.py
+++ b/docs_src/dependencies/tutorial005_an_py310.py
@@ -20,6 +20,6 @@ def query_or_cookie_extractor(
@app.get("/items/")
async def read_query(
- query_or_default: Annotated[str, Depends(query_or_cookie_extractor)]
+ query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
diff --git a/docs_src/dependencies/tutorial005_an_py39.py b/docs_src/dependencies/tutorial005_an_py39.py
index e8887e162..d5dd8dca9 100644
--- a/docs_src/dependencies/tutorial005_an_py39.py
+++ b/docs_src/dependencies/tutorial005_an_py39.py
@@ -20,6 +20,6 @@ def query_or_cookie_extractor(
@app.get("/items/")
async def read_query(
- query_or_default: Annotated[str, Depends(query_or_cookie_extractor)]
+ query_or_default: Annotated[str, Depends(query_or_cookie_extractor)],
):
return {"q_or_cookie": query_or_default}
diff --git a/docs_src/dependencies/tutorial008c.py b/docs_src/dependencies/tutorial008c.py
new file mode 100644
index 000000000..4b99a5a31
--- /dev/null
+++ b/docs_src/dependencies/tutorial008c.py
@@ -0,0 +1,27 @@
+from fastapi import Depends, FastAPI, HTTPException
+
+app = FastAPI()
+
+
+class InternalError(Exception):
+ pass
+
+
+def get_username():
+ try:
+ yield "Rick"
+ except InternalError:
+ print("Oops, we didn't raise again, Britney 😱")
+
+
+@app.get("/items/{item_id}")
+def get_item(item_id: str, username: str = Depends(get_username)):
+ if item_id == "portal-gun":
+ raise InternalError(
+ f"The portal gun is too dangerous to be owned by {username}"
+ )
+ if item_id != "plumbus":
+ raise HTTPException(
+ status_code=404, detail="Item not found, there's only a plumbus here"
+ )
+ return item_id
diff --git a/docs_src/dependencies/tutorial008c_an.py b/docs_src/dependencies/tutorial008c_an.py
new file mode 100644
index 000000000..94f59f9aa
--- /dev/null
+++ b/docs_src/dependencies/tutorial008c_an.py
@@ -0,0 +1,28 @@
+from fastapi import Depends, FastAPI, HTTPException
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+class InternalError(Exception):
+ pass
+
+
+def get_username():
+ try:
+ yield "Rick"
+ except InternalError:
+ print("Oops, we didn't raise again, Britney 😱")
+
+
+@app.get("/items/{item_id}")
+def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
+ if item_id == "portal-gun":
+ raise InternalError(
+ f"The portal gun is too dangerous to be owned by {username}"
+ )
+ if item_id != "plumbus":
+ raise HTTPException(
+ status_code=404, detail="Item not found, there's only a plumbus here"
+ )
+ return item_id
diff --git a/docs_src/dependencies/tutorial008c_an_py39.py b/docs_src/dependencies/tutorial008c_an_py39.py
new file mode 100644
index 000000000..da92efa9c
--- /dev/null
+++ b/docs_src/dependencies/tutorial008c_an_py39.py
@@ -0,0 +1,29 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI, HTTPException
+
+app = FastAPI()
+
+
+class InternalError(Exception):
+ pass
+
+
+def get_username():
+ try:
+ yield "Rick"
+ except InternalError:
+ print("Oops, we didn't raise again, Britney 😱")
+
+
+@app.get("/items/{item_id}")
+def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
+ if item_id == "portal-gun":
+ raise InternalError(
+ f"The portal gun is too dangerous to be owned by {username}"
+ )
+ if item_id != "plumbus":
+ raise HTTPException(
+ status_code=404, detail="Item not found, there's only a plumbus here"
+ )
+ return item_id
diff --git a/docs_src/dependencies/tutorial008d.py b/docs_src/dependencies/tutorial008d.py
new file mode 100644
index 000000000..93039343d
--- /dev/null
+++ b/docs_src/dependencies/tutorial008d.py
@@ -0,0 +1,28 @@
+from fastapi import Depends, FastAPI, HTTPException
+
+app = FastAPI()
+
+
+class InternalError(Exception):
+ pass
+
+
+def get_username():
+ try:
+ yield "Rick"
+ except InternalError:
+ print("We don't swallow the internal error here, we raise again 😎")
+ raise
+
+
+@app.get("/items/{item_id}")
+def get_item(item_id: str, username: str = Depends(get_username)):
+ if item_id == "portal-gun":
+ raise InternalError(
+ f"The portal gun is too dangerous to be owned by {username}"
+ )
+ if item_id != "plumbus":
+ raise HTTPException(
+ status_code=404, detail="Item not found, there's only a plumbus here"
+ )
+ return item_id
diff --git a/docs_src/dependencies/tutorial008d_an.py b/docs_src/dependencies/tutorial008d_an.py
new file mode 100644
index 000000000..c35424574
--- /dev/null
+++ b/docs_src/dependencies/tutorial008d_an.py
@@ -0,0 +1,29 @@
+from fastapi import Depends, FastAPI, HTTPException
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+class InternalError(Exception):
+ pass
+
+
+def get_username():
+ try:
+ yield "Rick"
+ except InternalError:
+ print("We don't swallow the internal error here, we raise again 😎")
+ raise
+
+
+@app.get("/items/{item_id}")
+def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
+ if item_id == "portal-gun":
+ raise InternalError(
+ f"The portal gun is too dangerous to be owned by {username}"
+ )
+ if item_id != "plumbus":
+ raise HTTPException(
+ status_code=404, detail="Item not found, there's only a plumbus here"
+ )
+ return item_id
diff --git a/docs_src/dependencies/tutorial008d_an_py39.py b/docs_src/dependencies/tutorial008d_an_py39.py
new file mode 100644
index 000000000..99bd5cb91
--- /dev/null
+++ b/docs_src/dependencies/tutorial008d_an_py39.py
@@ -0,0 +1,30 @@
+from typing import Annotated
+
+from fastapi import Depends, FastAPI, HTTPException
+
+app = FastAPI()
+
+
+class InternalError(Exception):
+ pass
+
+
+def get_username():
+ try:
+ yield "Rick"
+ except InternalError:
+ print("We don't swallow the internal error here, we raise again 😎")
+ raise
+
+
+@app.get("/items/{item_id}")
+def get_item(item_id: str, username: Annotated[str, Depends(get_username)]):
+ if item_id == "portal-gun":
+ raise InternalError(
+ f"The portal gun is too dangerous to be owned by {username}"
+ )
+ if item_id != "plumbus":
+ raise HTTPException(
+ status_code=404, detail="Item not found, there's only a plumbus here"
+ )
+ return item_id
diff --git a/docs_src/extra_data_types/tutorial001.py b/docs_src/extra_data_types/tutorial001.py
index 8ae8472a7..71de958ff 100644
--- a/docs_src/extra_data_types/tutorial001.py
+++ b/docs_src/extra_data_types/tutorial001.py
@@ -10,10 +10,10 @@ app = FastAPI()
@app.put("/items/{item_id}")
async def read_items(
item_id: UUID,
- start_datetime: Union[datetime, None] = Body(default=None),
- end_datetime: Union[datetime, None] = Body(default=None),
+ start_datetime: datetime = Body(),
+ end_datetime: datetime = Body(),
+ process_after: timedelta = Body(),
repeat_at: Union[time, None] = Body(default=None),
- process_after: Union[timedelta, None] = Body(default=None),
):
start_process = start_datetime + process_after
duration = end_datetime - start_process
@@ -21,8 +21,8 @@ async def read_items(
"item_id": item_id,
"start_datetime": start_datetime,
"end_datetime": end_datetime,
- "repeat_at": repeat_at,
"process_after": process_after,
+ "repeat_at": repeat_at,
"start_process": start_process,
"duration": duration,
}
diff --git a/docs_src/extra_data_types/tutorial001_an.py b/docs_src/extra_data_types/tutorial001_an.py
index a4c074241..257d0c7c8 100644
--- a/docs_src/extra_data_types/tutorial001_an.py
+++ b/docs_src/extra_data_types/tutorial001_an.py
@@ -11,10 +11,10 @@ app = FastAPI()
@app.put("/items/{item_id}")
async def read_items(
item_id: UUID,
- start_datetime: Annotated[Union[datetime, None], Body()] = None,
- end_datetime: Annotated[Union[datetime, None], Body()] = None,
+ start_datetime: Annotated[datetime, Body()],
+ end_datetime: Annotated[datetime, Body()],
+ process_after: Annotated[timedelta, Body()],
repeat_at: Annotated[Union[time, None], Body()] = None,
- process_after: Annotated[Union[timedelta, None], Body()] = None,
):
start_process = start_datetime + process_after
duration = end_datetime - start_process
@@ -22,8 +22,8 @@ async def read_items(
"item_id": item_id,
"start_datetime": start_datetime,
"end_datetime": end_datetime,
- "repeat_at": repeat_at,
"process_after": process_after,
+ "repeat_at": repeat_at,
"start_process": start_process,
"duration": duration,
}
diff --git a/docs_src/extra_data_types/tutorial001_an_py310.py b/docs_src/extra_data_types/tutorial001_an_py310.py
index 4f69c40d9..668bf1909 100644
--- a/docs_src/extra_data_types/tutorial001_an_py310.py
+++ b/docs_src/extra_data_types/tutorial001_an_py310.py
@@ -10,10 +10,10 @@ app = FastAPI()
@app.put("/items/{item_id}")
async def read_items(
item_id: UUID,
- start_datetime: Annotated[datetime | None, Body()] = None,
- end_datetime: Annotated[datetime | None, Body()] = None,
+ start_datetime: Annotated[datetime, Body()],
+ end_datetime: Annotated[datetime, Body()],
+ process_after: Annotated[timedelta, Body()],
repeat_at: Annotated[time | None, Body()] = None,
- process_after: Annotated[timedelta | None, Body()] = None,
):
start_process = start_datetime + process_after
duration = end_datetime - start_process
@@ -21,8 +21,8 @@ async def read_items(
"item_id": item_id,
"start_datetime": start_datetime,
"end_datetime": end_datetime,
- "repeat_at": repeat_at,
"process_after": process_after,
+ "repeat_at": repeat_at,
"start_process": start_process,
"duration": duration,
}
diff --git a/docs_src/extra_data_types/tutorial001_an_py39.py b/docs_src/extra_data_types/tutorial001_an_py39.py
index 630d36ae3..fa3551d66 100644
--- a/docs_src/extra_data_types/tutorial001_an_py39.py
+++ b/docs_src/extra_data_types/tutorial001_an_py39.py
@@ -10,10 +10,10 @@ app = FastAPI()
@app.put("/items/{item_id}")
async def read_items(
item_id: UUID,
- start_datetime: Annotated[Union[datetime, None], Body()] = None,
- end_datetime: Annotated[Union[datetime, None], Body()] = None,
+ start_datetime: Annotated[datetime, Body()],
+ end_datetime: Annotated[datetime, Body()],
+ process_after: Annotated[timedelta, Body()],
repeat_at: Annotated[Union[time, None], Body()] = None,
- process_after: Annotated[Union[timedelta, None], Body()] = None,
):
start_process = start_datetime + process_after
duration = end_datetime - start_process
@@ -21,8 +21,8 @@ async def read_items(
"item_id": item_id,
"start_datetime": start_datetime,
"end_datetime": end_datetime,
- "repeat_at": repeat_at,
"process_after": process_after,
+ "repeat_at": repeat_at,
"start_process": start_process,
"duration": duration,
}
diff --git a/docs_src/extra_data_types/tutorial001_py310.py b/docs_src/extra_data_types/tutorial001_py310.py
index d22f81888..a275a0577 100644
--- a/docs_src/extra_data_types/tutorial001_py310.py
+++ b/docs_src/extra_data_types/tutorial001_py310.py
@@ -9,10 +9,10 @@ app = FastAPI()
@app.put("/items/{item_id}")
async def read_items(
item_id: UUID,
- start_datetime: datetime | None = Body(default=None),
- end_datetime: datetime | None = Body(default=None),
+ start_datetime: datetime = Body(),
+ end_datetime: datetime = Body(),
+ process_after: timedelta = Body(),
repeat_at: time | None = Body(default=None),
- process_after: timedelta | None = Body(default=None),
):
start_process = start_datetime + process_after
duration = end_datetime - start_process
@@ -20,8 +20,8 @@ async def read_items(
"item_id": item_id,
"start_datetime": start_datetime,
"end_datetime": end_datetime,
- "repeat_at": repeat_at,
"process_after": process_after,
+ "repeat_at": repeat_at,
"start_process": start_process,
"duration": duration,
}
diff --git a/docs_src/generate_clients/tutorial004.js b/docs_src/generate_clients/tutorial004.js
index 18dc38267..fa222ba6c 100644
--- a/docs_src/generate_clients/tutorial004.js
+++ b/docs_src/generate_clients/tutorial004.js
@@ -1,29 +1,36 @@
-import * as fs from "fs";
+import * as fs from 'fs'
-const filePath = "./openapi.json";
+async function modifyOpenAPIFile(filePath) {
+ try {
+ const data = await fs.promises.readFile(filePath)
+ const openapiContent = JSON.parse(data)
-fs.readFile(filePath, (err, data) => {
- const openapiContent = JSON.parse(data);
- if (err) throw err;
-
- const paths = openapiContent.paths;
-
- Object.keys(paths).forEach((pathKey) => {
- const pathData = paths[pathKey];
- Object.keys(pathData).forEach((method) => {
- const operation = pathData[method];
- if (operation.tags && operation.tags.length > 0) {
- const tag = operation.tags[0];
- const operationId = operation.operationId;
- const toRemove = `${tag}-`;
- if (operationId.startsWith(toRemove)) {
- const newOperationId = operationId.substring(toRemove.length);
- operation.operationId = newOperationId;
+ const paths = openapiContent.paths
+ for (const pathKey of Object.keys(paths)) {
+ const pathData = paths[pathKey]
+ for (const method of Object.keys(pathData)) {
+ const operation = pathData[method]
+ if (operation.tags && operation.tags.length > 0) {
+ const tag = operation.tags[0]
+ const operationId = operation.operationId
+ const toRemove = `${tag}-`
+ if (operationId.startsWith(toRemove)) {
+ const newOperationId = operationId.substring(toRemove.length)
+ operation.operationId = newOperationId
+ }
}
}
- });
- });
- fs.writeFile(filePath, JSON.stringify(openapiContent, null, 2), (err) => {
- if (err) throw err;
- });
-});
+ }
+
+ await fs.promises.writeFile(
+ filePath,
+ JSON.stringify(openapiContent, null, 2),
+ )
+ console.log('File successfully modified')
+ } catch (err) {
+ console.error('Error:', err)
+ }
+}
+
+const filePath = './openapi.json'
+modifyOpenAPIFile(filePath)
diff --git a/docs_src/header_params/tutorial002.py b/docs_src/header_params/tutorial002.py
index 639ab1735..0a34f17cc 100644
--- a/docs_src/header_params/tutorial002.py
+++ b/docs_src/header_params/tutorial002.py
@@ -7,6 +7,6 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- strange_header: Union[str, None] = Header(default=None, convert_underscores=False)
+ strange_header: Union[str, None] = Header(default=None, convert_underscores=False),
):
return {"strange_header": strange_header}
diff --git a/docs_src/header_params/tutorial002_an_py310.py b/docs_src/header_params/tutorial002_an_py310.py
index b340647b6..8a102749f 100644
--- a/docs_src/header_params/tutorial002_an_py310.py
+++ b/docs_src/header_params/tutorial002_an_py310.py
@@ -7,6 +7,6 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- strange_header: Annotated[str | None, Header(convert_underscores=False)] = None
+ strange_header: Annotated[str | None, Header(convert_underscores=False)] = None,
):
return {"strange_header": strange_header}
diff --git a/docs_src/header_params/tutorial002_py310.py b/docs_src/header_params/tutorial002_py310.py
index b7979b542..10d6716c6 100644
--- a/docs_src/header_params/tutorial002_py310.py
+++ b/docs_src/header_params/tutorial002_py310.py
@@ -5,6 +5,6 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- strange_header: str | None = Header(default=None, convert_underscores=False)
+ strange_header: str | None = Header(default=None, convert_underscores=False),
):
return {"strange_header": strange_header}
diff --git a/docs_src/path_operation_advanced_configuration/tutorial007.py b/docs_src/path_operation_advanced_configuration/tutorial007.py
index 972ddbd2c..54e2e9399 100644
--- a/docs_src/path_operation_advanced_configuration/tutorial007.py
+++ b/docs_src/path_operation_advanced_configuration/tutorial007.py
@@ -30,5 +30,5 @@ async def create_item(request: Request):
try:
item = Item.model_validate(data)
except ValidationError as e:
- raise HTTPException(status_code=422, detail=e.errors())
+ raise HTTPException(status_code=422, detail=e.errors(include_url=False))
return item
diff --git a/docs_src/query_params_str_validations/tutorial003.py b/docs_src/query_params_str_validations/tutorial003.py
index 73d2e08c8..7d4917373 100644
--- a/docs_src/query_params_str_validations/tutorial003.py
+++ b/docs_src/query_params_str_validations/tutorial003.py
@@ -7,7 +7,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- q: Union[str, None] = Query(default=None, min_length=3, max_length=50)
+ q: Union[str, None] = Query(default=None, min_length=3, max_length=50),
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial003_an.py b/docs_src/query_params_str_validations/tutorial003_an.py
index a3665f6a8..0dd14086c 100644
--- a/docs_src/query_params_str_validations/tutorial003_an.py
+++ b/docs_src/query_params_str_validations/tutorial003_an.py
@@ -8,7 +8,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- q: Annotated[Union[str, None], Query(min_length=3, max_length=50)] = None
+ q: Annotated[Union[str, None], Query(min_length=3, max_length=50)] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial003_an_py310.py b/docs_src/query_params_str_validations/tutorial003_an_py310.py
index 836af04de..79a604b6c 100644
--- a/docs_src/query_params_str_validations/tutorial003_an_py310.py
+++ b/docs_src/query_params_str_validations/tutorial003_an_py310.py
@@ -7,7 +7,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- q: Annotated[str | None, Query(min_length=3, max_length=50)] = None
+ q: Annotated[str | None, Query(min_length=3, max_length=50)] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial003_an_py39.py b/docs_src/query_params_str_validations/tutorial003_an_py39.py
index 87a426839..3d6697793 100644
--- a/docs_src/query_params_str_validations/tutorial003_an_py39.py
+++ b/docs_src/query_params_str_validations/tutorial003_an_py39.py
@@ -7,7 +7,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- q: Annotated[Union[str, None], Query(min_length=3, max_length=50)] = None
+ q: Annotated[Union[str, None], Query(min_length=3, max_length=50)] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial007.py b/docs_src/query_params_str_validations/tutorial007.py
index cb836569e..27b649e14 100644
--- a/docs_src/query_params_str_validations/tutorial007.py
+++ b/docs_src/query_params_str_validations/tutorial007.py
@@ -7,7 +7,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- q: Union[str, None] = Query(default=None, title="Query string", min_length=3)
+ q: Union[str, None] = Query(default=None, title="Query string", min_length=3),
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial007_an.py b/docs_src/query_params_str_validations/tutorial007_an.py
index 3bc85cc0c..4b3c8de4b 100644
--- a/docs_src/query_params_str_validations/tutorial007_an.py
+++ b/docs_src/query_params_str_validations/tutorial007_an.py
@@ -8,7 +8,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- q: Annotated[Union[str, None], Query(title="Query string", min_length=3)] = None
+ q: Annotated[Union[str, None], Query(title="Query string", min_length=3)] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial007_an_py310.py b/docs_src/query_params_str_validations/tutorial007_an_py310.py
index 5933911fd..ef18e500d 100644
--- a/docs_src/query_params_str_validations/tutorial007_an_py310.py
+++ b/docs_src/query_params_str_validations/tutorial007_an_py310.py
@@ -7,7 +7,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- q: Annotated[str | None, Query(title="Query string", min_length=3)] = None
+ q: Annotated[str | None, Query(title="Query string", min_length=3)] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial007_an_py39.py b/docs_src/query_params_str_validations/tutorial007_an_py39.py
index dafa1c5c9..8d7a82c46 100644
--- a/docs_src/query_params_str_validations/tutorial007_an_py39.py
+++ b/docs_src/query_params_str_validations/tutorial007_an_py39.py
@@ -7,7 +7,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- q: Annotated[Union[str, None], Query(title="Query string", min_length=3)] = None
+ q: Annotated[Union[str, None], Query(title="Query string", min_length=3)] = None,
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial007_py310.py b/docs_src/query_params_str_validations/tutorial007_py310.py
index e3e1ef2e0..c283576d5 100644
--- a/docs_src/query_params_str_validations/tutorial007_py310.py
+++ b/docs_src/query_params_str_validations/tutorial007_py310.py
@@ -5,7 +5,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- q: str | None = Query(default=None, title="Query string", min_length=3)
+ q: str | None = Query(default=None, title="Query string", min_length=3),
):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
diff --git a/docs_src/query_params_str_validations/tutorial014.py b/docs_src/query_params_str_validations/tutorial014.py
index 50e0a6c2b..779db1c80 100644
--- a/docs_src/query_params_str_validations/tutorial014.py
+++ b/docs_src/query_params_str_validations/tutorial014.py
@@ -7,7 +7,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- hidden_query: Union[str, None] = Query(default=None, include_in_schema=False)
+ hidden_query: Union[str, None] = Query(default=None, include_in_schema=False),
):
if hidden_query:
return {"hidden_query": hidden_query}
diff --git a/docs_src/query_params_str_validations/tutorial014_an.py b/docs_src/query_params_str_validations/tutorial014_an.py
index a9a9c4427..2eaa58540 100644
--- a/docs_src/query_params_str_validations/tutorial014_an.py
+++ b/docs_src/query_params_str_validations/tutorial014_an.py
@@ -8,7 +8,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- hidden_query: Annotated[Union[str, None], Query(include_in_schema=False)] = None
+ hidden_query: Annotated[Union[str, None], Query(include_in_schema=False)] = None,
):
if hidden_query:
return {"hidden_query": hidden_query}
diff --git a/docs_src/query_params_str_validations/tutorial014_an_py310.py b/docs_src/query_params_str_validations/tutorial014_an_py310.py
index 5fba54150..e728dbdb5 100644
--- a/docs_src/query_params_str_validations/tutorial014_an_py310.py
+++ b/docs_src/query_params_str_validations/tutorial014_an_py310.py
@@ -7,7 +7,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- hidden_query: Annotated[str | None, Query(include_in_schema=False)] = None
+ hidden_query: Annotated[str | None, Query(include_in_schema=False)] = None,
):
if hidden_query:
return {"hidden_query": hidden_query}
diff --git a/docs_src/query_params_str_validations/tutorial014_an_py39.py b/docs_src/query_params_str_validations/tutorial014_an_py39.py
index b07985210..aaf7703a5 100644
--- a/docs_src/query_params_str_validations/tutorial014_an_py39.py
+++ b/docs_src/query_params_str_validations/tutorial014_an_py39.py
@@ -7,7 +7,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- hidden_query: Annotated[Union[str, None], Query(include_in_schema=False)] = None
+ hidden_query: Annotated[Union[str, None], Query(include_in_schema=False)] = None,
):
if hidden_query:
return {"hidden_query": hidden_query}
diff --git a/docs_src/query_params_str_validations/tutorial014_py310.py b/docs_src/query_params_str_validations/tutorial014_py310.py
index 1b617efdd..97bb3386e 100644
--- a/docs_src/query_params_str_validations/tutorial014_py310.py
+++ b/docs_src/query_params_str_validations/tutorial014_py310.py
@@ -5,7 +5,7 @@ app = FastAPI()
@app.get("/items/")
async def read_items(
- hidden_query: str | None = Query(default=None, include_in_schema=False)
+ hidden_query: str | None = Query(default=None, include_in_schema=False),
):
if hidden_query:
return {"hidden_query": hidden_query}
diff --git a/docs_src/security/tutorial003_an.py b/docs_src/security/tutorial003_an.py
index 261cb4857..8fb40dd4a 100644
--- a/docs_src/security/tutorial003_an.py
+++ b/docs_src/security/tutorial003_an.py
@@ -68,7 +68,7 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
async def get_current_active_user(
- current_user: Annotated[User, Depends(get_current_user)]
+ current_user: Annotated[User, Depends(get_current_user)],
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
@@ -90,6 +90,6 @@ async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
@app.get("/users/me")
async def read_users_me(
- current_user: Annotated[User, Depends(get_current_active_user)]
+ current_user: Annotated[User, Depends(get_current_active_user)],
):
return current_user
diff --git a/docs_src/security/tutorial003_an_py310.py b/docs_src/security/tutorial003_an_py310.py
index a03f4f8bf..ced4a2fbc 100644
--- a/docs_src/security/tutorial003_an_py310.py
+++ b/docs_src/security/tutorial003_an_py310.py
@@ -67,7 +67,7 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
async def get_current_active_user(
- current_user: Annotated[User, Depends(get_current_user)]
+ current_user: Annotated[User, Depends(get_current_user)],
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
@@ -89,6 +89,6 @@ async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
@app.get("/users/me")
async def read_users_me(
- current_user: Annotated[User, Depends(get_current_active_user)]
+ current_user: Annotated[User, Depends(get_current_active_user)],
):
return current_user
diff --git a/docs_src/security/tutorial003_an_py39.py b/docs_src/security/tutorial003_an_py39.py
index 308dbe798..068a3933e 100644
--- a/docs_src/security/tutorial003_an_py39.py
+++ b/docs_src/security/tutorial003_an_py39.py
@@ -67,7 +67,7 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
async def get_current_active_user(
- current_user: Annotated[User, Depends(get_current_user)]
+ current_user: Annotated[User, Depends(get_current_user)],
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
@@ -89,6 +89,6 @@ async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
@app.get("/users/me")
async def read_users_me(
- current_user: Annotated[User, Depends(get_current_active_user)]
+ current_user: Annotated[User, Depends(get_current_active_user)],
):
return current_user
diff --git a/docs_src/security/tutorial004.py b/docs_src/security/tutorial004.py
index 044eec700..91d161b8a 100644
--- a/docs_src/security/tutorial004.py
+++ b/docs_src/security/tutorial004.py
@@ -1,9 +1,10 @@
from datetime import datetime, timedelta, timezone
from typing import Union
+import jwt
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
-from jose import JWTError, jwt
+from jwt.exceptions import InvalidTokenError
from passlib.context import CryptContext
from pydantic import BaseModel
@@ -98,7 +99,7 @@ async def get_current_user(token: str = Depends(oauth2_scheme)):
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
- except JWTError:
+ except InvalidTokenError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
@@ -114,7 +115,7 @@ async def get_current_active_user(current_user: User = Depends(get_current_user)
@app.post("/token")
async def login_for_access_token(
- form_data: OAuth2PasswordRequestForm = Depends()
+ form_data: OAuth2PasswordRequestForm = Depends(),
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
diff --git a/docs_src/security/tutorial004_an.py b/docs_src/security/tutorial004_an.py
index c78e8496c..df50754af 100644
--- a/docs_src/security/tutorial004_an.py
+++ b/docs_src/security/tutorial004_an.py
@@ -1,9 +1,10 @@
from datetime import datetime, timedelta, timezone
from typing import Union
+import jwt
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
-from jose import JWTError, jwt
+from jwt.exceptions import InvalidTokenError
from passlib.context import CryptContext
from pydantic import BaseModel
from typing_extensions import Annotated
@@ -99,7 +100,7 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
- except JWTError:
+ except InvalidTokenError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
@@ -108,7 +109,7 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
async def get_current_active_user(
- current_user: Annotated[User, Depends(get_current_user)]
+ current_user: Annotated[User, Depends(get_current_user)],
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
@@ -117,7 +118,7 @@ async def get_current_active_user(
@app.post("/token")
async def login_for_access_token(
- form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
@@ -135,13 +136,13 @@ async def login_for_access_token(
@app.get("/users/me/", response_model=User)
async def read_users_me(
- current_user: Annotated[User, Depends(get_current_active_user)]
+ current_user: Annotated[User, Depends(get_current_active_user)],
):
return current_user
@app.get("/users/me/items/")
async def read_own_items(
- current_user: Annotated[User, Depends(get_current_active_user)]
+ current_user: Annotated[User, Depends(get_current_active_user)],
):
return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial004_an_py310.py b/docs_src/security/tutorial004_an_py310.py
index 36dbc677e..eff54ef01 100644
--- a/docs_src/security/tutorial004_an_py310.py
+++ b/docs_src/security/tutorial004_an_py310.py
@@ -1,9 +1,10 @@
from datetime import datetime, timedelta, timezone
from typing import Annotated
+import jwt
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
-from jose import JWTError, jwt
+from jwt.exceptions import InvalidTokenError
from passlib.context import CryptContext
from pydantic import BaseModel
@@ -98,7 +99,7 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
- except JWTError:
+ except InvalidTokenError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
@@ -107,7 +108,7 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
async def get_current_active_user(
- current_user: Annotated[User, Depends(get_current_user)]
+ current_user: Annotated[User, Depends(get_current_user)],
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
@@ -116,7 +117,7 @@ async def get_current_active_user(
@app.post("/token")
async def login_for_access_token(
- form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
@@ -134,13 +135,13 @@ async def login_for_access_token(
@app.get("/users/me/", response_model=User)
async def read_users_me(
- current_user: Annotated[User, Depends(get_current_active_user)]
+ current_user: Annotated[User, Depends(get_current_active_user)],
):
return current_user
@app.get("/users/me/items/")
async def read_own_items(
- current_user: Annotated[User, Depends(get_current_active_user)]
+ current_user: Annotated[User, Depends(get_current_active_user)],
):
return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial004_an_py39.py b/docs_src/security/tutorial004_an_py39.py
index 23fc04a72..0455b500c 100644
--- a/docs_src/security/tutorial004_an_py39.py
+++ b/docs_src/security/tutorial004_an_py39.py
@@ -1,9 +1,10 @@
from datetime import datetime, timedelta, timezone
from typing import Annotated, Union
+import jwt
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
-from jose import JWTError, jwt
+from jwt.exceptions import InvalidTokenError
from passlib.context import CryptContext
from pydantic import BaseModel
@@ -98,7 +99,7 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
- except JWTError:
+ except InvalidTokenError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
@@ -107,7 +108,7 @@ async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]):
async def get_current_active_user(
- current_user: Annotated[User, Depends(get_current_user)]
+ current_user: Annotated[User, Depends(get_current_user)],
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
@@ -116,7 +117,7 @@ async def get_current_active_user(
@app.post("/token")
async def login_for_access_token(
- form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
@@ -134,13 +135,13 @@ async def login_for_access_token(
@app.get("/users/me/", response_model=User)
async def read_users_me(
- current_user: Annotated[User, Depends(get_current_active_user)]
+ current_user: Annotated[User, Depends(get_current_active_user)],
):
return current_user
@app.get("/users/me/items/")
async def read_own_items(
- current_user: Annotated[User, Depends(get_current_active_user)]
+ current_user: Annotated[User, Depends(get_current_active_user)],
):
return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial004_py310.py b/docs_src/security/tutorial004_py310.py
index 8363d45ab..78bee22a3 100644
--- a/docs_src/security/tutorial004_py310.py
+++ b/docs_src/security/tutorial004_py310.py
@@ -1,8 +1,9 @@
from datetime import datetime, timedelta, timezone
+import jwt
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
-from jose import JWTError, jwt
+from jwt.exceptions import InvalidTokenError
from passlib.context import CryptContext
from pydantic import BaseModel
@@ -97,7 +98,7 @@ async def get_current_user(token: str = Depends(oauth2_scheme)):
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
- except JWTError:
+ except InvalidTokenError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
@@ -113,7 +114,7 @@ async def get_current_active_user(current_user: User = Depends(get_current_user)
@app.post("/token")
async def login_for_access_token(
- form_data: OAuth2PasswordRequestForm = Depends()
+ form_data: OAuth2PasswordRequestForm = Depends(),
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
diff --git a/docs_src/security/tutorial005.py b/docs_src/security/tutorial005.py
index b16bf440a..ccad07969 100644
--- a/docs_src/security/tutorial005.py
+++ b/docs_src/security/tutorial005.py
@@ -1,13 +1,14 @@
from datetime import datetime, timedelta, timezone
from typing import List, Union
+import jwt
from fastapi import Depends, FastAPI, HTTPException, Security, status
from fastapi.security import (
OAuth2PasswordBearer,
OAuth2PasswordRequestForm,
SecurityScopes,
)
-from jose import JWTError, jwt
+from jwt.exceptions import InvalidTokenError
from passlib.context import CryptContext
from pydantic import BaseModel, ValidationError
@@ -120,7 +121,7 @@ async def get_current_user(
raise credentials_exception
token_scopes = payload.get("scopes", [])
token_data = TokenData(scopes=token_scopes, username=username)
- except (JWTError, ValidationError):
+ except (InvalidTokenError, ValidationError):
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
@@ -136,7 +137,7 @@ async def get_current_user(
async def get_current_active_user(
- current_user: User = Security(get_current_user, scopes=["me"])
+ current_user: User = Security(get_current_user, scopes=["me"]),
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
@@ -145,7 +146,7 @@ async def get_current_active_user(
@app.post("/token")
async def login_for_access_token(
- form_data: OAuth2PasswordRequestForm = Depends()
+ form_data: OAuth2PasswordRequestForm = Depends(),
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
@@ -165,7 +166,7 @@ async def read_users_me(current_user: User = Depends(get_current_active_user)):
@app.get("/users/me/items/")
async def read_own_items(
- current_user: User = Security(get_current_active_user, scopes=["items"])
+ current_user: User = Security(get_current_active_user, scopes=["items"]),
):
return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial005_an.py b/docs_src/security/tutorial005_an.py
index 95e406b32..5b67cb145 100644
--- a/docs_src/security/tutorial005_an.py
+++ b/docs_src/security/tutorial005_an.py
@@ -1,13 +1,14 @@
from datetime import datetime, timedelta, timezone
from typing import List, Union
+import jwt
from fastapi import Depends, FastAPI, HTTPException, Security, status
from fastapi.security import (
OAuth2PasswordBearer,
OAuth2PasswordRequestForm,
SecurityScopes,
)
-from jose import JWTError, jwt
+from jwt.exceptions import InvalidTokenError
from passlib.context import CryptContext
from pydantic import BaseModel, ValidationError
from typing_extensions import Annotated
@@ -121,7 +122,7 @@ async def get_current_user(
raise credentials_exception
token_scopes = payload.get("scopes", [])
token_data = TokenData(scopes=token_scopes, username=username)
- except (JWTError, ValidationError):
+ except (InvalidTokenError, ValidationError):
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
@@ -137,7 +138,7 @@ async def get_current_user(
async def get_current_active_user(
- current_user: Annotated[User, Security(get_current_user, scopes=["me"])]
+ current_user: Annotated[User, Security(get_current_user, scopes=["me"])],
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
@@ -146,7 +147,7 @@ async def get_current_active_user(
@app.post("/token")
async def login_for_access_token(
- form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
@@ -161,14 +162,14 @@ async def login_for_access_token(
@app.get("/users/me/", response_model=User)
async def read_users_me(
- current_user: Annotated[User, Depends(get_current_active_user)]
+ current_user: Annotated[User, Depends(get_current_active_user)],
):
return current_user
@app.get("/users/me/items/")
async def read_own_items(
- current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])]
+ current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])],
):
return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial005_an_py310.py b/docs_src/security/tutorial005_an_py310.py
index c6116a5ed..297193e35 100644
--- a/docs_src/security/tutorial005_an_py310.py
+++ b/docs_src/security/tutorial005_an_py310.py
@@ -1,13 +1,14 @@
from datetime import datetime, timedelta, timezone
from typing import Annotated
+import jwt
from fastapi import Depends, FastAPI, HTTPException, Security, status
from fastapi.security import (
OAuth2PasswordBearer,
OAuth2PasswordRequestForm,
SecurityScopes,
)
-from jose import JWTError, jwt
+from jwt.exceptions import InvalidTokenError
from passlib.context import CryptContext
from pydantic import BaseModel, ValidationError
@@ -120,7 +121,7 @@ async def get_current_user(
raise credentials_exception
token_scopes = payload.get("scopes", [])
token_data = TokenData(scopes=token_scopes, username=username)
- except (JWTError, ValidationError):
+ except (InvalidTokenError, ValidationError):
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
@@ -136,7 +137,7 @@ async def get_current_user(
async def get_current_active_user(
- current_user: Annotated[User, Security(get_current_user, scopes=["me"])]
+ current_user: Annotated[User, Security(get_current_user, scopes=["me"])],
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
@@ -145,7 +146,7 @@ async def get_current_active_user(
@app.post("/token")
async def login_for_access_token(
- form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
@@ -160,14 +161,14 @@ async def login_for_access_token(
@app.get("/users/me/", response_model=User)
async def read_users_me(
- current_user: Annotated[User, Depends(get_current_active_user)]
+ current_user: Annotated[User, Depends(get_current_active_user)],
):
return current_user
@app.get("/users/me/items/")
async def read_own_items(
- current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])]
+ current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])],
):
return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial005_an_py39.py b/docs_src/security/tutorial005_an_py39.py
index af51c08b5..1acf47bdc 100644
--- a/docs_src/security/tutorial005_an_py39.py
+++ b/docs_src/security/tutorial005_an_py39.py
@@ -1,13 +1,14 @@
from datetime import datetime, timedelta, timezone
from typing import Annotated, List, Union
+import jwt
from fastapi import Depends, FastAPI, HTTPException, Security, status
from fastapi.security import (
OAuth2PasswordBearer,
OAuth2PasswordRequestForm,
SecurityScopes,
)
-from jose import JWTError, jwt
+from jwt.exceptions import InvalidTokenError
from passlib.context import CryptContext
from pydantic import BaseModel, ValidationError
@@ -120,7 +121,7 @@ async def get_current_user(
raise credentials_exception
token_scopes = payload.get("scopes", [])
token_data = TokenData(scopes=token_scopes, username=username)
- except (JWTError, ValidationError):
+ except (InvalidTokenError, ValidationError):
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
@@ -136,7 +137,7 @@ async def get_current_user(
async def get_current_active_user(
- current_user: Annotated[User, Security(get_current_user, scopes=["me"])]
+ current_user: Annotated[User, Security(get_current_user, scopes=["me"])],
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
@@ -145,7 +146,7 @@ async def get_current_active_user(
@app.post("/token")
async def login_for_access_token(
- form_data: Annotated[OAuth2PasswordRequestForm, Depends()]
+ form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
@@ -160,14 +161,14 @@ async def login_for_access_token(
@app.get("/users/me/", response_model=User)
async def read_users_me(
- current_user: Annotated[User, Depends(get_current_active_user)]
+ current_user: Annotated[User, Depends(get_current_active_user)],
):
return current_user
@app.get("/users/me/items/")
async def read_own_items(
- current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])]
+ current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])],
):
return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial005_py310.py b/docs_src/security/tutorial005_py310.py
index 37a22c709..b244ef08e 100644
--- a/docs_src/security/tutorial005_py310.py
+++ b/docs_src/security/tutorial005_py310.py
@@ -1,12 +1,13 @@
from datetime import datetime, timedelta, timezone
+import jwt
from fastapi import Depends, FastAPI, HTTPException, Security, status
from fastapi.security import (
OAuth2PasswordBearer,
OAuth2PasswordRequestForm,
SecurityScopes,
)
-from jose import JWTError, jwt
+from jwt.exceptions import InvalidTokenError
from passlib.context import CryptContext
from pydantic import BaseModel, ValidationError
@@ -119,7 +120,7 @@ async def get_current_user(
raise credentials_exception
token_scopes = payload.get("scopes", [])
token_data = TokenData(scopes=token_scopes, username=username)
- except (JWTError, ValidationError):
+ except (InvalidTokenError, ValidationError):
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
@@ -135,7 +136,7 @@ async def get_current_user(
async def get_current_active_user(
- current_user: User = Security(get_current_user, scopes=["me"])
+ current_user: User = Security(get_current_user, scopes=["me"]),
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
@@ -144,7 +145,7 @@ async def get_current_active_user(
@app.post("/token")
async def login_for_access_token(
- form_data: OAuth2PasswordRequestForm = Depends()
+ form_data: OAuth2PasswordRequestForm = Depends(),
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
@@ -164,7 +165,7 @@ async def read_users_me(current_user: User = Depends(get_current_active_user)):
@app.get("/users/me/items/")
async def read_own_items(
- current_user: User = Security(get_current_active_user, scopes=["items"])
+ current_user: User = Security(get_current_active_user, scopes=["items"]),
):
return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial005_py39.py b/docs_src/security/tutorial005_py39.py
index c27580763..8f0e93376 100644
--- a/docs_src/security/tutorial005_py39.py
+++ b/docs_src/security/tutorial005_py39.py
@@ -1,13 +1,14 @@
from datetime import datetime, timedelta, timezone
from typing import Union
+import jwt
from fastapi import Depends, FastAPI, HTTPException, Security, status
from fastapi.security import (
OAuth2PasswordBearer,
OAuth2PasswordRequestForm,
SecurityScopes,
)
-from jose import JWTError, jwt
+from jwt.exceptions import InvalidTokenError
from passlib.context import CryptContext
from pydantic import BaseModel, ValidationError
@@ -120,7 +121,7 @@ async def get_current_user(
raise credentials_exception
token_scopes = payload.get("scopes", [])
token_data = TokenData(scopes=token_scopes, username=username)
- except (JWTError, ValidationError):
+ except (InvalidTokenError, ValidationError):
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
@@ -136,7 +137,7 @@ async def get_current_user(
async def get_current_active_user(
- current_user: User = Security(get_current_user, scopes=["me"])
+ current_user: User = Security(get_current_user, scopes=["me"]),
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
@@ -145,7 +146,7 @@ async def get_current_active_user(
@app.post("/token")
async def login_for_access_token(
- form_data: OAuth2PasswordRequestForm = Depends()
+ form_data: OAuth2PasswordRequestForm = Depends(),
) -> Token:
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
@@ -165,7 +166,7 @@ async def read_users_me(current_user: User = Depends(get_current_active_user)):
@app.get("/users/me/items/")
async def read_own_items(
- current_user: User = Security(get_current_active_user, scopes=["items"])
+ current_user: User = Security(get_current_active_user, scopes=["items"]),
):
return [{"item_id": "Foo", "owner": current_user.username}]
diff --git a/docs_src/security/tutorial007_an.py b/docs_src/security/tutorial007_an.py
index 9e9c3cd70..0d211dfde 100644
--- a/docs_src/security/tutorial007_an.py
+++ b/docs_src/security/tutorial007_an.py
@@ -10,7 +10,7 @@ security = HTTPBasic()
def get_current_username(
- credentials: Annotated[HTTPBasicCredentials, Depends(security)]
+ credentials: Annotated[HTTPBasicCredentials, Depends(security)],
):
current_username_bytes = credentials.username.encode("utf8")
correct_username_bytes = b"stanleyjobson"
diff --git a/docs_src/security/tutorial007_an_py39.py b/docs_src/security/tutorial007_an_py39.py
index 3d9ea2726..87ef98657 100644
--- a/docs_src/security/tutorial007_an_py39.py
+++ b/docs_src/security/tutorial007_an_py39.py
@@ -10,7 +10,7 @@ security = HTTPBasic()
def get_current_username(
- credentials: Annotated[HTTPBasicCredentials, Depends(security)]
+ credentials: Annotated[HTTPBasicCredentials, Depends(security)],
):
current_username_bytes = credentials.username.encode("utf8")
correct_username_bytes = b"stanleyjobson"
diff --git a/fastapi/__init__.py b/fastapi/__init__.py
index fedd8b419..04305ad8b 100644
--- a/fastapi/__init__.py
+++ b/fastapi/__init__.py
@@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
-__version__ = "0.109.1"
+__version__ = "0.111.0"
from starlette import status as status
diff --git a/fastapi/_compat.py b/fastapi/_compat.py
index 35d4a8723..06b847b4f 100644
--- a/fastapi/_compat.py
+++ b/fastapi/_compat.py
@@ -20,10 +20,12 @@ from typing import (
from fastapi.exceptions import RequestErrorModel
from fastapi.types import IncEx, ModelNameMap, UnionType
from pydantic import BaseModel, create_model
-from pydantic.version import VERSION as PYDANTIC_VERSION
+from pydantic.version import VERSION as P_VERSION
from starlette.datastructures import UploadFile
from typing_extensions import Annotated, Literal, get_args, get_origin
+# Reassign variable to make it reexported for mypy
+PYDANTIC_VERSION = P_VERSION
PYDANTIC_V2 = PYDANTIC_VERSION.startswith("2.")
@@ -127,7 +129,7 @@ if PYDANTIC_V2:
)
except ValidationError as exc:
return None, _regenerate_error_with_loc(
- errors=exc.errors(), loc_prefix=loc
+ errors=exc.errors(include_url=False), loc_prefix=loc
)
def serialize(
@@ -266,7 +268,7 @@ if PYDANTIC_V2:
def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]:
error = ValidationError.from_exception_data(
"Field required", [{"type": "missing", "loc": loc, "input": {}}]
- ).errors()[0]
+ ).errors(include_url=False)[0]
error["input"] = None
return error # type: ignore[return-value]
diff --git a/fastapi/applications.py b/fastapi/applications.py
index 597c60a56..4f5e6f1d9 100644
--- a/fastapi/applications.py
+++ b/fastapi/applications.py
@@ -40,7 +40,7 @@ from starlette.requests import Request
from starlette.responses import HTMLResponse, JSONResponse, Response
from starlette.routing import BaseRoute
from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send
-from typing_extensions import Annotated, Doc, deprecated # type: ignore [attr-defined]
+from typing_extensions import Annotated, Doc, deprecated
AppType = TypeVar("AppType", bound="FastAPI")
@@ -297,7 +297,7 @@ class FastAPI(Starlette):
browser tabs open). Or if you want to leave fixed the possible URLs.
If the servers `list` is not provided, or is an empty `list`, the
- default value would be a a `dict` with a `url` value of `/`.
+ default value would be a `dict` with a `url` value of `/`.
Each item in the `list` is a `dict` containing:
@@ -902,7 +902,7 @@ class FastAPI(Starlette):
A state object for the application. This is the same object for the
entire application, it doesn't change from request to request.
- You normally woudln't use this in FastAPI, for most of the cases you
+ You normally wouldn't use this in FastAPI, for most of the cases you
would instead use FastAPI dependencies.
This is simply inherited from Starlette.
@@ -1019,7 +1019,7 @@ class FastAPI(Starlette):
oauth2_redirect_url = root_path + oauth2_redirect_url
return get_swagger_ui_html(
openapi_url=openapi_url,
- title=self.title + " - Swagger UI",
+ title=f"{self.title} - Swagger UI",
oauth2_redirect_url=oauth2_redirect_url,
init_oauth=self.swagger_ui_init_oauth,
swagger_ui_parameters=self.swagger_ui_parameters,
@@ -1043,7 +1043,7 @@ class FastAPI(Starlette):
root_path = req.scope.get("root_path", "").rstrip("/")
openapi_url = root_path + self.openapi_url
return get_redoc_html(
- openapi_url=openapi_url, title=self.title + " - ReDoc"
+ openapi_url=openapi_url, title=f"{self.title} - ReDoc"
)
self.add_route(self.redoc_url, redoc_html, include_in_schema=False)
diff --git a/fastapi/background.py b/fastapi/background.py
index 35ab1b227..203578a41 100644
--- a/fastapi/background.py
+++ b/fastapi/background.py
@@ -1,7 +1,7 @@
from typing import Any, Callable
from starlette.background import BackgroundTasks as StarletteBackgroundTasks
-from typing_extensions import Annotated, Doc, ParamSpec # type: ignore [attr-defined]
+from typing_extensions import Annotated, Doc, ParamSpec
P = ParamSpec("P")
diff --git a/fastapi/datastructures.py b/fastapi/datastructures.py
index ce03e3ce4..cf8406b0f 100644
--- a/fastapi/datastructures.py
+++ b/fastapi/datastructures.py
@@ -24,7 +24,7 @@ from starlette.datastructures import Headers as Headers # noqa: F401
from starlette.datastructures import QueryParams as QueryParams # noqa: F401
from starlette.datastructures import State as State # noqa: F401
from starlette.datastructures import UploadFile as StarletteUploadFile
-from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
+from typing_extensions import Annotated, Doc
class UploadFile(StarletteUploadFile):
diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py
index 63ccfadb7..bbf61ad85 100644
--- a/fastapi/dependencies/utils.py
+++ b/fastapi/dependencies/utils.py
@@ -1,6 +1,6 @@
import inspect
from contextlib import AsyncExitStack, contextmanager
-from copy import deepcopy
+from copy import copy, deepcopy
from typing import (
Any,
Callable,
@@ -385,6 +385,8 @@ def analyze_param(
field_info.annotation = type_annotation
if depends is not None and depends.dependency is None:
+ # Copy `depends` before mutating it
+ depends = copy(depends)
depends.dependency = type_annotation
if lenient_issubclass(
@@ -744,7 +746,7 @@ async def request_body_to_args(
results: List[Union[bytes, str]] = []
async def process_fn(
- fn: Callable[[], Coroutine[Any, Any, Any]]
+ fn: Callable[[], Coroutine[Any, Any, Any]],
) -> None:
result = await fn()
results.append(result) # noqa: B023
diff --git a/fastapi/encoders.py b/fastapi/encoders.py
index e50171393..451ea0760 100644
--- a/fastapi/encoders.py
+++ b/fastapi/encoders.py
@@ -22,9 +22,9 @@ from pydantic import BaseModel
from pydantic.color import Color
from pydantic.networks import AnyUrl, NameEmail
from pydantic.types import SecretBytes, SecretStr
-from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
+from typing_extensions import Annotated, Doc
-from ._compat import PYDANTIC_V2, Url, _model_dump
+from ._compat import PYDANTIC_V2, UndefinedType, Url, _model_dump
# Taken from Pydantic v1 as is
@@ -86,7 +86,7 @@ ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
def generate_encoders_by_class_tuples(
- type_encoder_map: Dict[Any, Callable[[Any], Any]]
+ type_encoder_map: Dict[Any, Callable[[Any], Any]],
) -> Dict[Callable[[Any], Any], Tuple[Any, ...]]:
encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict(
tuple
@@ -259,6 +259,8 @@ def jsonable_encoder(
return str(obj)
if isinstance(obj, (str, int, float, type(None))):
return obj
+ if isinstance(obj, UndefinedType):
+ return None
if isinstance(obj, dict):
encoded_dict = {}
allowed_keys = set(obj.keys())
diff --git a/fastapi/exceptions.py b/fastapi/exceptions.py
index 5cc97dcd2..5a7721f29 100644
--- a/fastapi/exceptions.py
+++ b/fastapi/exceptions.py
@@ -3,7 +3,7 @@ from typing import Any, Dict, Optional, Sequence, Type, Union
from pydantic import BaseModel, create_model
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.exceptions import WebSocketException as StarletteWebSocketException
-from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
+from typing_extensions import Annotated, Doc
class HTTPException(StarletteHTTPException):
diff --git a/fastapi/openapi/docs.py b/fastapi/openapi/docs.py
index 69473d19c..c2ec358d2 100644
--- a/fastapi/openapi/docs.py
+++ b/fastapi/openapi/docs.py
@@ -3,7 +3,7 @@ from typing import Any, Dict, Optional
from fastapi.encoders import jsonable_encoder
from starlette.responses import HTMLResponse
-from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
+from typing_extensions import Annotated, Doc
swagger_ui_default_parameters: Annotated[
Dict[str, Any],
@@ -53,7 +53,7 @@ def get_swagger_ui_html(
It is normally set to a CDN URL.
"""
),
- ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui-bundle.js",
+ ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js",
swagger_css_url: Annotated[
str,
Doc(
@@ -63,7 +63,7 @@ def get_swagger_ui_html(
It is normally set to a CDN URL.
"""
),
- ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.9.0/swagger-ui.css",
+ ] = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css",
swagger_favicon_url: Annotated[
str,
Doc(
diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py
index 5f3bdbb20..ed07b40f5 100644
--- a/fastapi/openapi/models.py
+++ b/fastapi/openapi/models.py
@@ -55,11 +55,7 @@ except ImportError: # pragma: no cover
return with_info_plain_validator_function(cls._validate)
-class Contact(BaseModel):
- name: Optional[str] = None
- url: Optional[AnyUrl] = None
- email: Optional[EmailStr] = None
-
+class BaseModelWithConfig(BaseModel):
if PYDANTIC_V2:
model_config = {"extra": "allow"}
@@ -69,21 +65,19 @@ class Contact(BaseModel):
extra = "allow"
-class License(BaseModel):
- name: str
- identifier: Optional[str] = None
+class Contact(BaseModelWithConfig):
+ name: Optional[str] = None
url: Optional[AnyUrl] = None
+ email: Optional[EmailStr] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
- class Config:
- extra = "allow"
+class License(BaseModelWithConfig):
+ name: str
+ identifier: Optional[str] = None
+ url: Optional[AnyUrl] = None
-class Info(BaseModel):
+class Info(BaseModelWithConfig):
title: str
summary: Optional[str] = None
description: Optional[str] = None
@@ -92,42 +86,18 @@ class Info(BaseModel):
license: Optional[License] = None
version: str
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
- class Config:
- extra = "allow"
-
-
-class ServerVariable(BaseModel):
+class ServerVariable(BaseModelWithConfig):
enum: Annotated[Optional[List[str]], Field(min_length=1)] = None
default: str
description: Optional[str] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
- class Config:
- extra = "allow"
-
-
-class Server(BaseModel):
+class Server(BaseModelWithConfig):
url: Union[AnyUrl, str]
description: Optional[str] = None
variables: Optional[Dict[str, ServerVariable]] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
class Reference(BaseModel):
ref: str = Field(alias="$ref")
@@ -138,36 +108,20 @@ class Discriminator(BaseModel):
mapping: Optional[Dict[str, str]] = None
-class XML(BaseModel):
+class XML(BaseModelWithConfig):
name: Optional[str] = None
namespace: Optional[str] = None
prefix: Optional[str] = None
attribute: Optional[bool] = None
wrapped: Optional[bool] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
- class Config:
- extra = "allow"
-
-
-class ExternalDocumentation(BaseModel):
+class ExternalDocumentation(BaseModelWithConfig):
description: Optional[str] = None
url: AnyUrl
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
-class Schema(BaseModel):
+class Schema(BaseModelWithConfig):
# Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu
# Core Vocabulary
schema_: Optional[str] = Field(default=None, alias="$schema")
@@ -253,14 +207,6 @@ class Schema(BaseModel):
),
] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
# Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents
# A JSON Schema MUST be an object or a boolean.
@@ -289,38 +235,22 @@ class ParameterInType(Enum):
cookie = "cookie"
-class Encoding(BaseModel):
+class Encoding(BaseModelWithConfig):
contentType: Optional[str] = None
headers: Optional[Dict[str, Union["Header", Reference]]] = None
style: Optional[str] = None
explode: Optional[bool] = None
allowReserved: Optional[bool] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
-class MediaType(BaseModel):
+class MediaType(BaseModelWithConfig):
schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema")
example: Optional[Any] = None
examples: Optional[Dict[str, Union[Example, Reference]]] = None
encoding: Optional[Dict[str, Encoding]] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
-class ParameterBase(BaseModel):
+class ParameterBase(BaseModelWithConfig):
description: Optional[str] = None
required: Optional[bool] = None
deprecated: Optional[bool] = None
@@ -334,14 +264,6 @@ class ParameterBase(BaseModel):
# Serialization rules for more complex scenarios
content: Optional[Dict[str, MediaType]] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
class Parameter(ParameterBase):
name: str
@@ -352,21 +274,13 @@ class Header(ParameterBase):
pass
-class RequestBody(BaseModel):
+class RequestBody(BaseModelWithConfig):
description: Optional[str] = None
content: Dict[str, MediaType]
required: Optional[bool] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
- class Config:
- extra = "allow"
-
-
-class Link(BaseModel):
+class Link(BaseModelWithConfig):
operationRef: Optional[str] = None
operationId: Optional[str] = None
parameters: Optional[Dict[str, Union[Any, str]]] = None
@@ -374,31 +288,15 @@ class Link(BaseModel):
description: Optional[str] = None
server: Optional[Server] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
-class Response(BaseModel):
+class Response(BaseModelWithConfig):
description: str
headers: Optional[Dict[str, Union[Header, Reference]]] = None
content: Optional[Dict[str, MediaType]] = None
links: Optional[Dict[str, Union[Link, Reference]]] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
-class Operation(BaseModel):
+class Operation(BaseModelWithConfig):
tags: Optional[List[str]] = None
summary: Optional[str] = None
description: Optional[str] = None
@@ -413,16 +311,8 @@ class Operation(BaseModel):
security: Optional[List[Dict[str, List[str]]]] = None
servers: Optional[List[Server]] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
- class Config:
- extra = "allow"
-
-
-class PathItem(BaseModel):
+class PathItem(BaseModelWithConfig):
ref: Optional[str] = Field(default=None, alias="$ref")
summary: Optional[str] = None
description: Optional[str] = None
@@ -437,14 +327,6 @@ class PathItem(BaseModel):
servers: Optional[List[Server]] = None
parameters: Optional[List[Union[Parameter, Reference]]] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
class SecuritySchemeType(Enum):
apiKey = "apiKey"
@@ -453,18 +335,10 @@ class SecuritySchemeType(Enum):
openIdConnect = "openIdConnect"
-class SecurityBase(BaseModel):
+class SecurityBase(BaseModelWithConfig):
type_: SecuritySchemeType = Field(alias="type")
description: Optional[str] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
class APIKeyIn(Enum):
query = "query"
@@ -488,18 +362,10 @@ class HTTPBearer(HTTPBase):
bearerFormat: Optional[str] = None
-class OAuthFlow(BaseModel):
+class OAuthFlow(BaseModelWithConfig):
refreshUrl: Optional[str] = None
scopes: Dict[str, str] = {}
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
class OAuthFlowImplicit(OAuthFlow):
authorizationUrl: str
@@ -518,20 +384,12 @@ class OAuthFlowAuthorizationCode(OAuthFlow):
tokenUrl: str
-class OAuthFlows(BaseModel):
+class OAuthFlows(BaseModelWithConfig):
implicit: Optional[OAuthFlowImplicit] = None
password: Optional[OAuthFlowPassword] = None
clientCredentials: Optional[OAuthFlowClientCredentials] = None
authorizationCode: Optional[OAuthFlowAuthorizationCode] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
class OAuth2(SecurityBase):
type_: SecuritySchemeType = Field(default=SecuritySchemeType.oauth2, alias="type")
@@ -548,7 +406,7 @@ class OpenIdConnect(SecurityBase):
SecurityScheme = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer]
-class Components(BaseModel):
+class Components(BaseModelWithConfig):
schemas: Optional[Dict[str, Union[Schema, Reference]]] = None
responses: Optional[Dict[str, Union[Response, Reference]]] = None
parameters: Optional[Dict[str, Union[Parameter, Reference]]] = None
@@ -561,30 +419,14 @@ class Components(BaseModel):
callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference, Any]]] = None
pathItems: Optional[Dict[str, Union[PathItem, Reference]]] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
-class Tag(BaseModel):
+class Tag(BaseModelWithConfig):
name: str
description: Optional[str] = None
externalDocs: Optional[ExternalDocumentation] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
-class OpenAPI(BaseModel):
+class OpenAPI(BaseModelWithConfig):
openapi: str
info: Info
jsonSchemaDialect: Optional[str] = None
@@ -597,14 +439,6 @@ class OpenAPI(BaseModel):
tags: Optional[List[Tag]] = None
externalDocs: Optional[ExternalDocumentation] = None
- if PYDANTIC_V2:
- model_config = {"extra": "allow"}
-
- else:
-
- class Config:
- extra = "allow"
-
_model_rebuild(Schema)
_model_rebuild(Operation)
diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py
index 5bfb5acef..79ad9f83f 100644
--- a/fastapi/openapi/utils.py
+++ b/fastapi/openapi/utils.py
@@ -123,7 +123,7 @@ def get_openapi_operation_parameters(
elif field_info.example != Undefined:
parameter["example"] = jsonable_encoder(field_info.example)
if field_info.deprecated:
- parameter["deprecated"] = field_info.deprecated
+ parameter["deprecated"] = True
parameters.append(parameter)
return parameters
diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py
index 3f6dbc959..3b25d774a 100644
--- a/fastapi/param_functions.py
+++ b/fastapi/param_functions.py
@@ -3,7 +3,7 @@ from typing import Any, Callable, Dict, List, Optional, Sequence, Union
from fastapi import params
from fastapi._compat import Undefined
from fastapi.openapi.models import Example
-from typing_extensions import Annotated, Doc, deprecated # type: ignore [attr-defined]
+from typing_extensions import Annotated, Doc, deprecated
_Unset: Any = Undefined
@@ -240,7 +240,7 @@ def Path( # noqa: N802
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ Union[deprecated, str, bool, None],
Doc(
"""
Mark this parameter field as deprecated.
@@ -565,7 +565,7 @@ def Query( # noqa: N802
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ Union[deprecated, str, bool, None],
Doc(
"""
Mark this parameter field as deprecated.
@@ -880,7 +880,7 @@ def Header( # noqa: N802
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ Union[deprecated, str, bool, None],
Doc(
"""
Mark this parameter field as deprecated.
@@ -1185,7 +1185,7 @@ def Cookie( # noqa: N802
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ Union[deprecated, str, bool, None],
Doc(
"""
Mark this parameter field as deprecated.
@@ -1512,7 +1512,7 @@ def Body( # noqa: N802
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ Union[deprecated, str, bool, None],
Doc(
"""
Mark this parameter field as deprecated.
@@ -1827,7 +1827,7 @@ def Form( # noqa: N802
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ Union[deprecated, str, bool, None],
Doc(
"""
Mark this parameter field as deprecated.
@@ -2141,7 +2141,7 @@ def File( # noqa: N802
),
] = None,
deprecated: Annotated[
- Optional[bool],
+ Union[deprecated, str, bool, None],
Doc(
"""
Mark this parameter field as deprecated.
diff --git a/fastapi/params.py b/fastapi/params.py
index b40944dba..860146531 100644
--- a/fastapi/params.py
+++ b/fastapi/params.py
@@ -6,7 +6,7 @@ from fastapi.openapi.models import Example
from pydantic.fields import FieldInfo
from typing_extensions import Annotated, deprecated
-from ._compat import PYDANTIC_V2, Undefined
+from ._compat import PYDANTIC_V2, PYDANTIC_VERSION, Undefined
_Unset: Any = Undefined
@@ -63,12 +63,11 @@ class Param(FieldInfo):
),
] = _Unset,
openapi_examples: Optional[Dict[str, Example]] = None,
- deprecated: Optional[bool] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
**extra: Any,
):
- self.deprecated = deprecated
if example is not _Unset:
warnings.warn(
"`example` has been deprecated, please use `examples` instead",
@@ -106,6 +105,10 @@ class Param(FieldInfo):
stacklevel=4,
)
current_json_schema_extra = json_schema_extra or extra
+ if PYDANTIC_VERSION < "2.7.0":
+ self.deprecated = deprecated
+ else:
+ kwargs["deprecated"] = deprecated
if PYDANTIC_V2:
kwargs.update(
{
@@ -174,7 +177,7 @@ class Path(Param):
),
] = _Unset,
openapi_examples: Optional[Dict[str, Example]] = None,
- deprecated: Optional[bool] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
**extra: Any,
@@ -260,7 +263,7 @@ class Query(Param):
),
] = _Unset,
openapi_examples: Optional[Dict[str, Example]] = None,
- deprecated: Optional[bool] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
**extra: Any,
@@ -345,7 +348,7 @@ class Header(Param):
),
] = _Unset,
openapi_examples: Optional[Dict[str, Example]] = None,
- deprecated: Optional[bool] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
**extra: Any,
@@ -430,7 +433,7 @@ class Cookie(Param):
),
] = _Unset,
openapi_examples: Optional[Dict[str, Example]] = None,
- deprecated: Optional[bool] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
**extra: Any,
@@ -514,14 +517,13 @@ class Body(FieldInfo):
),
] = _Unset,
openapi_examples: Optional[Dict[str, Example]] = None,
- deprecated: Optional[bool] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
**extra: Any,
):
self.embed = embed
self.media_type = media_type
- self.deprecated = deprecated
if example is not _Unset:
warnings.warn(
"`example` has been deprecated, please use `examples` instead",
@@ -559,6 +561,10 @@ class Body(FieldInfo):
stacklevel=4,
)
current_json_schema_extra = json_schema_extra or extra
+ if PYDANTIC_VERSION < "2.7.0":
+ self.deprecated = deprecated
+ else:
+ kwargs["deprecated"] = deprecated
if PYDANTIC_V2:
kwargs.update(
{
@@ -627,7 +633,7 @@ class Form(Body):
),
] = _Unset,
openapi_examples: Optional[Dict[str, Example]] = None,
- deprecated: Optional[bool] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
**extra: Any,
@@ -712,7 +718,7 @@ class File(Form):
),
] = _Unset,
openapi_examples: Optional[Dict[str, Example]] = None,
- deprecated: Optional[bool] = None,
+ deprecated: Union[deprecated, str, bool, None] = None,
include_in_schema: bool = True,
json_schema_extra: Union[Dict[str, Any], None] = None,
**extra: Any,
diff --git a/fastapi/routing.py b/fastapi/routing.py
index 5edf3c06e..f18a658cb 100644
--- a/fastapi/routing.py
+++ b/fastapi/routing.py
@@ -71,7 +71,7 @@ from starlette.routing import (
from starlette.routing import Mount as Mount # noqa
from starlette.types import ASGIApp, Lifespan, Scope
from starlette.websockets import WebSocket
-from typing_extensions import Annotated, Doc, deprecated # type: ignore [attr-defined]
+from typing_extensions import Annotated, Doc, deprecated
def _prepare_response_content(
@@ -218,19 +218,14 @@ def get_request_handler(
actual_response_class = response_class
async def app(request: Request) -> Response:
- exception_to_reraise: Optional[Exception] = None
response: Union[Response, None] = None
- async with AsyncExitStack() as async_exit_stack:
- # TODO: remove this scope later, after a few releases
- # This scope fastapi_astack is no longer used by FastAPI, kept for
- # compatibility, just in case
- request.scope["fastapi_astack"] = async_exit_stack
+ async with AsyncExitStack() as file_stack:
try:
body: Any = None
if body_field:
if is_body_form:
body = await request.form()
- async_exit_stack.push_async_callback(body.close)
+ file_stack.push_async_callback(body.close)
else:
body_bytes = await request.body()
if body_bytes:
@@ -262,18 +257,17 @@ def get_request_handler(
],
body=e.doc,
)
- exception_to_reraise = validation_error
raise validation_error from e
- except HTTPException as e:
- exception_to_reraise = e
+ except HTTPException:
+ # If a middleware raises an HTTPException, it should be raised again
raise
except Exception as e:
http_error = HTTPException(
status_code=400, detail="There was an error parsing the body"
)
- exception_to_reraise = http_error
raise http_error from e
- try:
+ errors: List[Any] = []
+ async with AsyncExitStack() as async_exit_stack:
solved_result = await solve_dependencies(
request=request,
dependant=dependant,
@@ -282,59 +276,53 @@ def get_request_handler(
async_exit_stack=async_exit_stack,
)
values, errors, background_tasks, sub_response, _ = solved_result
- except Exception as e:
- exception_to_reraise = e
- raise e
+ if not errors:
+ raw_response = await run_endpoint_function(
+ dependant=dependant, values=values, is_coroutine=is_coroutine
+ )
+ if isinstance(raw_response, Response):
+ if raw_response.background is None:
+ raw_response.background = background_tasks
+ response = raw_response
+ else:
+ response_args: Dict[str, Any] = {"background": background_tasks}
+ # If status_code was set, use it, otherwise use the default from the
+ # response class, in the case of redirect it's 307
+ current_status_code = (
+ status_code if status_code else sub_response.status_code
+ )
+ if current_status_code is not None:
+ response_args["status_code"] = current_status_code
+ if sub_response.status_code:
+ response_args["status_code"] = sub_response.status_code
+ content = await serialize_response(
+ field=response_field,
+ response_content=raw_response,
+ include=response_model_include,
+ exclude=response_model_exclude,
+ by_alias=response_model_by_alias,
+ exclude_unset=response_model_exclude_unset,
+ exclude_defaults=response_model_exclude_defaults,
+ exclude_none=response_model_exclude_none,
+ is_coroutine=is_coroutine,
+ )
+ response = actual_response_class(content, **response_args)
+ if not is_body_allowed_for_status_code(response.status_code):
+ response.body = b""
+ response.headers.raw.extend(sub_response.headers.raw)
if errors:
validation_error = RequestValidationError(
_normalize_errors(errors), body=body
)
- exception_to_reraise = validation_error
raise validation_error
- else:
- try:
- raw_response = await run_endpoint_function(
- dependant=dependant, values=values, is_coroutine=is_coroutine
- )
- except Exception as e:
- exception_to_reraise = e
- raise e
- if isinstance(raw_response, Response):
- if raw_response.background is None:
- raw_response.background = background_tasks
- response = raw_response
- else:
- response_args: Dict[str, Any] = {"background": background_tasks}
- # If status_code was set, use it, otherwise use the default from the
- # response class, in the case of redirect it's 307
- current_status_code = (
- status_code if status_code else sub_response.status_code
- )
- if current_status_code is not None:
- response_args["status_code"] = current_status_code
- if sub_response.status_code:
- response_args["status_code"] = sub_response.status_code
- content = await serialize_response(
- field=response_field,
- response_content=raw_response,
- include=response_model_include,
- exclude=response_model_exclude,
- by_alias=response_model_by_alias,
- exclude_unset=response_model_exclude_unset,
- exclude_defaults=response_model_exclude_defaults,
- exclude_none=response_model_exclude_none,
- is_coroutine=is_coroutine,
- )
- response = actual_response_class(content, **response_args)
- if not is_body_allowed_for_status_code(response.status_code):
- response.body = b""
- response.headers.raw.extend(sub_response.headers.raw)
- # This exception was possibly handled by the dependency but it should
- # still bubble up so that the ServerErrorMiddleware can return a 500
- # or the ExceptionMiddleware can catch and handle any other exceptions
- if exception_to_reraise:
- raise exception_to_reraise
- assert response is not None, "An error occurred while generating the request"
+ if response is None:
+ raise FastAPIError(
+ "No response object was returned. There's a high chance that the "
+ "application code is raising an exception and a dependency with yield "
+ "has a block with a bare except, or a block with except Exception, "
+ "and is not raising the exception again. Read more about it in the "
+ "docs: https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-except"
+ )
return response
return app
diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py
index b1a6b4f94..d68bdb037 100644
--- a/fastapi/security/api_key.py
+++ b/fastapi/security/api_key.py
@@ -5,7 +5,7 @@ from fastapi.security.base import SecurityBase
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.status import HTTP_403_FORBIDDEN
-from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
+from typing_extensions import Annotated, Doc
class APIKeyBase(SecurityBase):
@@ -76,7 +76,7 @@ class APIKeyQuery(APIKeyBase):
Doc(
"""
By default, if the query parameter is not provided, `APIKeyQuery` will
- automatically cancel the request and sebd the client an error.
+ automatically cancel the request and send the client an error.
If `auto_error` is set to `False`, when the query parameter is not
available, instead of erroring out, the dependency result will be
diff --git a/fastapi/security/http.py b/fastapi/security/http.py
index 738455de3..a142b135d 100644
--- a/fastapi/security/http.py
+++ b/fastapi/security/http.py
@@ -10,12 +10,12 @@ from fastapi.security.utils import get_authorization_scheme_param
from pydantic import BaseModel
from starlette.requests import Request
from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
-from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
+from typing_extensions import Annotated, Doc
class HTTPBasicCredentials(BaseModel):
"""
- The HTTP Basic credendials given as the result of using `HTTPBasic` in a
+ The HTTP Basic credentials given as the result of using `HTTPBasic` in a
dependency.
Read more about it in the
diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py
index be3e18cd8..9720cace0 100644
--- a/fastapi/security/oauth2.py
+++ b/fastapi/security/oauth2.py
@@ -10,7 +10,7 @@ from starlette.requests import Request
from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
# TODO: import from typing when deprecating Python 3.9
-from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
+from typing_extensions import Annotated, Doc
class OAuth2PasswordRequestForm:
@@ -54,7 +54,7 @@ class OAuth2PasswordRequestForm:
Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.
You could have custom internal logic to separate it by colon caracters (`:`) or
similar, and get the two parts `items` and `read`. Many applications do that to
- group and organize permisions, you could do it as well in your application, just
+ group and organize permissions, you could do it as well in your application, just
know that that it is application specific, it's not part of the specification.
"""
@@ -196,7 +196,7 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.
You could have custom internal logic to separate it by colon caracters (`:`) or
similar, and get the two parts `items` and `read`. Many applications do that to
- group and organize permisions, you could do it as well in your application, just
+ group and organize permissions, you could do it as well in your application, just
know that that it is application specific, it's not part of the specification.
@@ -441,7 +441,7 @@ class OAuth2PasswordBearer(OAuth2):
bool,
Doc(
"""
- By default, if no HTTP Auhtorization header is provided, required for
+ By default, if no HTTP Authorization header is provided, required for
OAuth2 authentication, it will automatically cancel the request and
send the client an error.
@@ -543,7 +543,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
bool,
Doc(
"""
- By default, if no HTTP Auhtorization header is provided, required for
+ By default, if no HTTP Authorization header is provided, required for
OAuth2 authentication, it will automatically cancel the request and
send the client an error.
diff --git a/fastapi/security/open_id_connect_url.py b/fastapi/security/open_id_connect_url.py
index c612b475d..c8cceb911 100644
--- a/fastapi/security/open_id_connect_url.py
+++ b/fastapi/security/open_id_connect_url.py
@@ -5,7 +5,7 @@ from fastapi.security.base import SecurityBase
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.status import HTTP_403_FORBIDDEN
-from typing_extensions import Annotated, Doc # type: ignore [attr-defined]
+from typing_extensions import Annotated, Doc
class OpenIdConnect(SecurityBase):
@@ -49,7 +49,7 @@ class OpenIdConnect(SecurityBase):
bool,
Doc(
"""
- By default, if no HTTP Auhtorization header is provided, required for
+ By default, if no HTTP Authorization header is provided, required for
OpenID Connect authentication, it will automatically cancel the request
and send the client an error.
diff --git a/fastapi/utils.py b/fastapi/utils.py
index 53b2fa0c3..dfda4e678 100644
--- a/fastapi/utils.py
+++ b/fastapi/utils.py
@@ -221,9 +221,3 @@ def get_value_or_default(
if not isinstance(item, DefaultPlaceholder):
return item
return first_item
-
-
-def match_pydantic_error_url(error_type: str) -> Any:
- from dirty_equals import IsStr
-
- return IsStr(regex=rf"^https://errors\.pydantic\.dev/.*/v/{error_type}")
diff --git a/pdm_build.py b/pdm_build.py
new file mode 100644
index 000000000..45922d471
--- /dev/null
+++ b/pdm_build.py
@@ -0,0 +1,39 @@
+import os
+from typing import Any, Dict, List
+
+from pdm.backend.hooks import Context
+
+TIANGOLO_BUILD_PACKAGE = os.getenv("TIANGOLO_BUILD_PACKAGE", "fastapi")
+
+
+def pdm_build_initialize(context: Context) -> None:
+ metadata = context.config.metadata
+ # Get custom config for the current package, from the env var
+ config: Dict[str, Any] = context.config.data["tool"]["tiangolo"][
+ "_internal-slim-build"
+ ]["packages"][TIANGOLO_BUILD_PACKAGE]
+ project_config: Dict[str, Any] = config["project"]
+ # Get main optional dependencies, extras
+ optional_dependencies: Dict[str, List[str]] = metadata.get(
+ "optional-dependencies", {}
+ )
+ # Get custom optional dependencies name to always include in this (non-slim) package
+ include_optional_dependencies: List[str] = config.get(
+ "include-optional-dependencies", []
+ )
+ # Override main [project] configs with custom configs for this package
+ for key, value in project_config.items():
+ metadata[key] = value
+ # Get custom build config for the current package
+ build_config: Dict[str, Any] = (
+ config.get("tool", {}).get("pdm", {}).get("build", {})
+ )
+ # Override PDM build config with custom build config for this package
+ for key, value in build_config.items():
+ context.config.build_config[key] = value
+ # Get main dependencies
+ dependencies: List[str] = metadata.get("dependencies", [])
+ # Add optional dependencies to the default dependencies for this (non-slim) package
+ for include_optional in include_optional_dependencies:
+ optional_dependencies_group = optional_dependencies.get(include_optional, [])
+ dependencies.extend(optional_dependencies_group)
diff --git a/pyproject.toml b/pyproject.toml
index 31d9c59b3..a79845646 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,13 +1,13 @@
[build-system]
-requires = ["hatchling >= 1.13.0"]
-build-backend = "hatchling.build"
+requires = ["pdm-backend"]
+build-backend = "pdm.backend"
[project]
name = "fastapi"
+dynamic = ["version"]
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
readme = "README.md"
requires-python = ">=3.8"
-license = "MIT"
authors = [
{ name = "Sebastián Ramírez", email = "tiangolo@gmail.com" },
]
@@ -41,11 +41,10 @@ classifiers = [
"Topic :: Internet :: WWW/HTTP",
]
dependencies = [
- "starlette>=0.35.0,<0.36.0",
+ "starlette>=0.37.2,<0.38.0",
"pydantic>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0",
"typing-extensions>=4.8.0",
]
-dynamic = ["version"]
[project.urls]
Homepage = "https://github.com/tiangolo/fastapi"
@@ -53,22 +52,101 @@ Documentation = "https://fastapi.tiangolo.com/"
Repository = "https://github.com/tiangolo/fastapi"
[project.optional-dependencies]
+
+standard = [
+ "fastapi-cli >=0.0.2",
+ # For the test client
+ "httpx >=0.23.0",
+ # For templates
+ "jinja2 >=2.11.2",
+ # For forms and file uploads
+ "python-multipart >=0.0.7",
+ # For UJSONResponse
+ "ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0",
+ # For ORJSONResponse
+ "orjson >=3.2.1",
+ # To validate email fields
+ "email_validator >=2.0.0",
+ # Uvicorn with uvloop
+ "uvicorn[standard] >=0.12.0",
+ # TODO: this should be part of some pydantic optional extra dependencies
+ # # Settings management
+ # "pydantic-settings >=2.0.0",
+ # # Extra Pydantic data types
+ # "pydantic-extra-types >=2.0.0",
+]
+
all = [
+ "fastapi-cli >=0.0.2",
+ # # For the test client
"httpx >=0.23.0",
+ # For templates
"jinja2 >=2.11.2",
+ # For forms and file uploads
"python-multipart >=0.0.7",
+ # For Starlette's SessionMiddleware, not commonly used with FastAPI
"itsdangerous >=1.1.0",
+ # For Starlette's schema generation, would not be used with FastAPI
"pyyaml >=5.3.1",
+ # For UJSONResponse
"ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0",
+ # For ORJSONResponse
"orjson >=3.2.1",
+ # To validate email fields
"email_validator >=2.0.0",
+ # Uvicorn with uvloop
"uvicorn[standard] >=0.12.0",
+ # Settings management
"pydantic-settings >=2.0.0",
+ # Extra Pydantic data types
"pydantic-extra-types >=2.0.0",
]
-[tool.hatch.version]
-path = "fastapi/__init__.py"
+[tool.pdm]
+version = { source = "file", path = "fastapi/__init__.py" }
+distribution = true
+
+[tool.pdm.build]
+source-includes = [
+ "tests/",
+ "docs_src/",
+ "requirements*.txt",
+ "scripts/",
+ # For a test
+ "docs/en/docs/img/favicon.png",
+ ]
+
+[tool.tiangolo._internal-slim-build.packages.fastapi-slim.project]
+name = "fastapi-slim"
+
+[tool.tiangolo._internal-slim-build.packages.fastapi]
+include-optional-dependencies = ["standard"]
+
+[tool.tiangolo._internal-slim-build.packages.fastapi.project.optional-dependencies]
+all = [
+ # # For the test client
+ "httpx >=0.23.0",
+ # For templates
+ "jinja2 >=2.11.2",
+ # For forms and file uploads
+ "python-multipart >=0.0.7",
+ # For Starlette's SessionMiddleware, not commonly used with FastAPI
+ "itsdangerous >=1.1.0",
+ # For Starlette's schema generation, would not be used with FastAPI
+ "pyyaml >=5.3.1",
+ # For UJSONResponse
+ "ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0",
+ # For ORJSONResponse
+ "orjson >=3.2.1",
+ # To validate email fields
+ "email_validator >=2.0.0",
+ # Uvicorn with uvloop
+ "uvicorn[standard] >=0.12.0",
+ # Settings management
+ "pydantic-settings >=2.0.0",
+ # Extra Pydantic data types
+ "pydantic-extra-types >=2.0.0",
+]
[tool.mypy]
strict = true
@@ -121,9 +199,6 @@ filterwarnings = [
# - https://github.com/mpdavis/python-jose/issues/332
# - https://github.com/mpdavis/python-jose/issues/334
'ignore:datetime\.datetime\.utcnow\(\) is deprecated and scheduled for removal in a future version\..*:DeprecationWarning:jose',
- # TODO: remove after upgrading Starlette to a version including https://github.com/encode/starlette/pull/2406
- # Probably Starlette 0.36.0
- "ignore: The 'method' parameter is not used, and it will be removed.:DeprecationWarning:starlette",
]
[tool.coverage.run]
@@ -139,7 +214,7 @@ omit = [
"docs_src/response_model/tutorial003_04_py310.py",
]
-[tool.ruff]
+[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
@@ -152,10 +227,11 @@ select = [
ignore = [
"E501", # line too long, handled by black
"B008", # do not perform function calls in argument defaults
+ "C901", # too complex
"W191", # indentation contains tabs
]
-[tool.ruff.per-file-ignores]
+[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]
"docs_src/dependencies/tutorial007.py" = ["F821"]
"docs_src/dependencies/tutorial008.py" = ["F821"]
@@ -188,9 +264,9 @@ ignore = [
"docs_src/dependencies/tutorial008b_an_py39.py" = ["B904"]
-[tool.ruff.isort]
+[tool.ruff.lint.isort]
known-third-party = ["fastapi", "pydantic", "starlette"]
-[tool.ruff.pyupgrade]
+[tool.ruff.lint.pyupgrade]
# Preserve types, even if a file imports `from __future__ import annotations`.
keep-runtime-typing = true
diff --git a/requirements-docs.txt b/requirements-docs.txt
index 28408a9f1..c672f0ef7 100644
--- a/requirements-docs.txt
+++ b/requirements-docs.txt
@@ -1,19 +1,18 @@
-e .
-r requirements-docs-tests.txt
-mkdocs-material==9.4.7
+mkdocs-material==9.5.18
mdx-include >=1.4.1,<2.0.0
-mkdocs-markdownextradata-plugin >=0.1.7,<0.3.0
mkdocs-redirects>=1.2.1,<1.3.0
-typer-cli >=0.0.13,<0.0.14
-typer[all] >=0.6.1,<0.8.0
+typer >=0.12.0
pyyaml >=5.3.1,<7.0.0
# For Material for MkDocs, Chinese search
jieba==0.42.1
# For image processing by Material for MkDocs
-pillow==10.1.0
+pillow==10.3.0
# For image processing by Material for MkDocs
cairosvg==2.7.0
-mkdocstrings[python]==0.23.0
+mkdocstrings[python]==0.24.3
griffe-typingdoc==0.2.2
# For griffe, it formats with black
-black==23.3.0
+black==24.3.0
+mkdocs-macros-plugin==1.0.5
diff --git a/requirements-tests.txt b/requirements-tests.txt
index a5586c5ce..bfe70f2f5 100644
--- a/requirements-tests.txt
+++ b/requirements-tests.txt
@@ -1,22 +1,17 @@
--e .
+-e .[all]
-r requirements-docs-tests.txt
-pydantic-settings >=2.0.0
pytest >=7.1.3,<8.0.0
coverage[toml] >= 6.5.0,< 8.0
-mypy ==1.4.1
-ruff ==0.1.2
-email_validator >=1.1.1,<3.0.0
+mypy ==1.8.0
+ruff ==0.2.0
dirty-equals ==0.6.0
# TODO: once removing databases from tutorial, upgrade SQLAlchemy
# probably when including SQLModel
sqlalchemy >=1.3.18,<1.4.43
databases[sqlite] >=0.3.2,<0.7.0
-orjson >=3.2.1,<4.0.0
-ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0
-python-multipart >=0.0.7,<0.1.0
flask >=1.1.2,<3.0.0
anyio[trio] >=3.2.1,<4.0.0
-python-jose[cryptography] >=3.3.0,<4.0.0
+PyJWT==2.8.0
pyyaml >=5.3.1,<7.0.0
passlib[bcrypt] >=1.7.2,<2.0.0
diff --git a/requirements.txt b/requirements.txt
index ef25ec483..8e1fef341 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,6 @@
-e .[all]
-r requirements-tests.txt
-r requirements-docs.txt
-uvicorn[standard] >=0.12.0,<0.23.0
pre-commit >=2.17.0,<4.0.0
# For generating screenshots
playwright
diff --git a/scripts/build-docs.sh b/scripts/build-docs.sh
deleted file mode 100755
index 7aa0a9a47..000000000
--- a/scripts/build-docs.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-set -x
-
-# Check README.md is up to date
-python ./scripts/docs.py verify-docs
-python ./scripts/docs.py build-all
diff --git a/scripts/clean.sh b/scripts/clean.sh
deleted file mode 100755
index d5a4b790a..000000000
--- a/scripts/clean.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh -e
-
-if [ -d 'dist' ] ; then
- rm -r dist
-fi
-if [ -d 'site' ] ; then
- rm -r site
-fi
diff --git a/scripts/docs-live.sh b/scripts/docs-live.sh
deleted file mode 100755
index 30637a528..000000000
--- a/scripts/docs-live.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-mkdocs serve --dev-addr 0.0.0.0:8008
diff --git a/scripts/format.sh b/scripts/format.sh
index 11f25f1ce..45742f79a 100755
--- a/scripts/format.sh
+++ b/scripts/format.sh
@@ -1,5 +1,5 @@
#!/bin/sh -e
set -x
-ruff fastapi tests docs_src scripts --fix
+ruff check fastapi tests docs_src scripts --fix
ruff format fastapi tests docs_src scripts
diff --git a/scripts/lint.sh b/scripts/lint.sh
index c0e24db9f..18cf52a84 100755
--- a/scripts/lint.sh
+++ b/scripts/lint.sh
@@ -4,5 +4,5 @@ set -e
set -x
mypy fastapi
-ruff fastapi tests docs_src scripts
+ruff check fastapi tests docs_src scripts
ruff format fastapi tests --check
diff --git a/scripts/netlify-docs.sh b/scripts/netlify-docs.sh
deleted file mode 100755
index 8f9065e23..000000000
--- a/scripts/netlify-docs.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env bash
-set -x
-set -e
-# Install pip
-cd /tmp
-curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
-python3.6 get-pip.py --user
-cd -
-# Install Flit to be able to install all
-python3.6 -m pip install --user flit
-# Install with Flit
-python3.6 -m flit install --user --extras doc
-# Finally, run mkdocs
-python3.6 -m mkdocs build
diff --git a/scripts/publish.sh b/scripts/publish.sh
deleted file mode 100755
index 122728a60..000000000
--- a/scripts/publish.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-flit publish
diff --git a/tests/main.py b/tests/main.py
index 15760c039..6927eab61 100644
--- a/tests/main.py
+++ b/tests/main.py
@@ -1,5 +1,5 @@
import http
-from typing import FrozenSet, Optional
+from typing import FrozenSet, List, Optional
from fastapi import FastAPI, Path, Query
@@ -192,3 +192,13 @@ def get_enum_status_code():
@app.get("/query/frozenset")
def get_query_type_frozenset(query: FrozenSet[int] = Query(...)):
return ",".join(map(str, sorted(query)))
+
+
+@app.get("/query/list")
+def get_query_list(device_ids: List[int] = Query()) -> List[int]:
+ return device_ids
+
+
+@app.get("/query/list-default")
+def get_query_list_default(device_ids: List[int] = Query(default=[])) -> List[int]:
+ return device_ids
diff --git a/tests/test_annotated.py b/tests/test_annotated.py
index 2222be978..473d33e52 100644
--- a/tests/test_annotated.py
+++ b/tests/test_annotated.py
@@ -2,7 +2,6 @@ import pytest
from dirty_equals import IsDict
from fastapi import APIRouter, FastAPI, Query
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from typing_extensions import Annotated
app = FastAPI()
@@ -38,7 +37,6 @@ foo_is_missing = {
"msg": "Field required",
"type": "missing",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
)
# TODO: remove when deprecating Pydantic v1
@@ -60,7 +58,6 @@ foo_is_short = {
"msg": "String should have at least 1 character",
"type": "string_too_short",
"input": "",
- "url": match_pydantic_error_url("string_too_short"),
}
)
# TODO: remove when deprecating Pydantic v1
diff --git a/tests/test_application.py b/tests/test_application.py
index ea7a80128..5c62f5f6e 100644
--- a/tests/test_application.py
+++ b/tests/test_application.py
@@ -1163,6 +1163,91 @@ def test_openapi_schema():
},
}
},
+ "/query/list": {
+ "get": {
+ "summary": "Get Query List",
+ "operationId": "get_query_list_query_list_get",
+ "parameters": [
+ {
+ "name": "device_ids",
+ "in": "query",
+ "required": True,
+ "schema": {
+ "type": "array",
+ "items": {"type": "integer"},
+ "title": "Device Ids",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {"type": "integer"},
+ "title": "Response Get Query List Query List Get",
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ "/query/list-default": {
+ "get": {
+ "summary": "Get Query List Default",
+ "operationId": "get_query_list_default_query_list_default_get",
+ "parameters": [
+ {
+ "name": "device_ids",
+ "in": "query",
+ "required": False,
+ "schema": {
+ "type": "array",
+ "items": {"type": "integer"},
+ "default": [],
+ "title": "Device Ids",
+ },
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {"type": "integer"},
+ "title": "Response Get Query List Default Query List Default Get",
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
},
"components": {
"schemas": {
diff --git a/tests/test_dependency_contextmanager.py b/tests/test_dependency_contextmanager.py
index b07f9aa5b..008dab7bc 100644
--- a/tests/test_dependency_contextmanager.py
+++ b/tests/test_dependency_contextmanager.py
@@ -55,6 +55,7 @@ async def asyncgen_state_try(state: Dict[str, str] = Depends(get_state)):
yield state["/async_raise"]
except AsyncDependencyError:
errors.append("/async_raise")
+ raise
finally:
state["/async_raise"] = "asyncgen raise finalized"
@@ -65,6 +66,7 @@ def generator_state_try(state: Dict[str, str] = Depends(get_state)):
yield state["/sync_raise"]
except SyncDependencyError:
errors.append("/sync_raise")
+ raise
finally:
state["/sync_raise"] = "generator raise finalized"
diff --git a/tests/test_dependency_duplicates.py b/tests/test_dependency_duplicates.py
index 0882cc41d..8e8d07c2d 100644
--- a/tests/test_dependency_duplicates.py
+++ b/tests/test_dependency_duplicates.py
@@ -3,7 +3,6 @@ from typing import List
from dirty_equals import IsDict
from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from pydantic import BaseModel
app = FastAPI()
@@ -57,7 +56,6 @@ def test_no_duplicates_invalid():
"loc": ["body", "item2"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
diff --git a/tests/test_dependency_normal_exceptions.py b/tests/test_dependency_normal_exceptions.py
index 23c366d5d..326f8fd88 100644
--- a/tests/test_dependency_normal_exceptions.py
+++ b/tests/test_dependency_normal_exceptions.py
@@ -20,6 +20,7 @@ async def get_database():
fake_database.update(temp_database)
except HTTPException:
state["except"] = True
+ raise
finally:
state["finally"] = True
diff --git a/tests/test_dependency_overrides.py b/tests/test_dependency_overrides.py
index 21cff998d..154937fa0 100644
--- a/tests/test_dependency_overrides.py
+++ b/tests/test_dependency_overrides.py
@@ -4,7 +4,6 @@ import pytest
from dirty_equals import IsDict
from fastapi import APIRouter, Depends, FastAPI
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
app = FastAPI()
@@ -63,7 +62,6 @@ def test_main_depends():
"loc": ["query", "q"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -110,7 +108,6 @@ def test_decorator_depends():
"loc": ["query", "q"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -151,7 +148,6 @@ def test_router_depends():
"loc": ["query", "q"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -198,7 +194,6 @@ def test_router_decorator_depends():
"loc": ["query", "q"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -285,7 +280,6 @@ def test_override_with_sub_main_depends():
"loc": ["query", "k"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -316,7 +310,6 @@ def test_override_with_sub__main_depends_q_foo():
"loc": ["query", "k"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -355,7 +348,6 @@ def test_override_with_sub_decorator_depends():
"loc": ["query", "k"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -386,7 +378,6 @@ def test_override_with_sub_decorator_depends_q_foo():
"loc": ["query", "k"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -425,7 +416,6 @@ def test_override_with_sub_router_depends():
"loc": ["query", "k"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -456,7 +446,6 @@ def test_override_with_sub_router_depends_q_foo():
"loc": ["query", "k"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -495,7 +484,6 @@ def test_override_with_sub_router_decorator_depends():
"loc": ["query", "k"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -526,7 +514,6 @@ def test_override_with_sub_router_decorator_depends_q_foo():
"loc": ["query", "k"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
diff --git a/tests/test_filter_pydantic_sub_model_pv2.py b/tests/test_filter_pydantic_sub_model_pv2.py
index 9097d2ce5..2e2c26ddc 100644
--- a/tests/test_filter_pydantic_sub_model_pv2.py
+++ b/tests/test_filter_pydantic_sub_model_pv2.py
@@ -5,7 +5,6 @@ from dirty_equals import HasRepr, IsDict, IsOneOf
from fastapi import Depends, FastAPI
from fastapi.exceptions import ResponseValidationError
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from .utils import needs_pydanticv2
@@ -67,7 +66,6 @@ def test_validator_is_cloned(client: TestClient):
"msg": "Value error, name must end in A",
"input": "modelX",
"ctx": {"error": HasRepr("ValueError('name must end in A')")},
- "url": match_pydantic_error_url("value_error"),
}
)
| IsDict(
diff --git a/tests/test_generic_parameterless_depends.py b/tests/test_generic_parameterless_depends.py
new file mode 100644
index 000000000..fe13ff89b
--- /dev/null
+++ b/tests/test_generic_parameterless_depends.py
@@ -0,0 +1,77 @@
+from typing import TypeVar
+
+from fastapi import Depends, FastAPI
+from fastapi.testclient import TestClient
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+T = TypeVar("T")
+
+Dep = Annotated[T, Depends()]
+
+
+class A:
+ pass
+
+
+class B:
+ pass
+
+
+@app.get("/a")
+async def a(dep: Dep[A]):
+ return {"cls": dep.__class__.__name__}
+
+
+@app.get("/b")
+async def b(dep: Dep[B]):
+ return {"cls": dep.__class__.__name__}
+
+
+client = TestClient(app)
+
+
+def test_generic_parameterless_depends():
+ response = client.get("/a")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"cls": "A"}
+
+ response = client.get("/b")
+ assert response.status_code == 200, response.text
+ assert response.json() == {"cls": "B"}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "openapi": "3.1.0",
+ "paths": {
+ "/a": {
+ "get": {
+ "operationId": "a_a_get",
+ "responses": {
+ "200": {
+ "content": {"application/json": {"schema": {}}},
+ "description": "Successful " "Response",
+ }
+ },
+ "summary": "A",
+ }
+ },
+ "/b": {
+ "get": {
+ "operationId": "b_b_get",
+ "responses": {
+ "200": {
+ "content": {"application/json": {"schema": {}}},
+ "description": "Successful " "Response",
+ }
+ },
+ "summary": "B",
+ }
+ },
+ },
+ }
diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py
index 7c8338ff3..1906d6bf1 100644
--- a/tests/test_jsonable_encoder.py
+++ b/tests/test_jsonable_encoder.py
@@ -7,7 +7,7 @@ from pathlib import PurePath, PurePosixPath, PureWindowsPath
from typing import Optional
import pytest
-from fastapi._compat import PYDANTIC_V2
+from fastapi._compat import PYDANTIC_V2, Undefined
from fastapi.encoders import jsonable_encoder
from pydantic import BaseModel, Field, ValidationError
@@ -310,3 +310,9 @@ def test_encode_deque_encodes_child_models():
dq = deque([Model(test="test")])
assert jsonable_encoder(dq)[0]["test"] == "test"
+
+
+@needs_pydanticv2
+def test_encode_pydantic_undefined():
+ data = {"value": Undefined}
+ assert jsonable_encoder(data) == {"value": None}
diff --git a/tests/test_multi_body_errors.py b/tests/test_multi_body_errors.py
index a51ca7253..0102f0f1a 100644
--- a/tests/test_multi_body_errors.py
+++ b/tests/test_multi_body_errors.py
@@ -4,7 +4,6 @@ from typing import List
from dirty_equals import IsDict, IsOneOf
from fastapi import FastAPI
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from pydantic import BaseModel, condecimal
app = FastAPI()
@@ -52,7 +51,6 @@ def test_jsonable_encoder_requiring_error():
"msg": "Input should be greater than 0",
"input": -1.0,
"ctx": {"gt": 0},
- "url": match_pydantic_error_url("greater_than"),
}
]
}
@@ -82,28 +80,24 @@ def test_put_incorrect_body_multiple():
"loc": ["body", 0, "name"],
"msg": "Field required",
"input": {"age": "five"},
- "url": match_pydantic_error_url("missing"),
},
{
"type": "decimal_parsing",
"loc": ["body", 0, "age"],
"msg": "Input should be a valid decimal",
"input": "five",
- "url": match_pydantic_error_url("decimal_parsing"),
},
{
"type": "missing",
"loc": ["body", 1, "name"],
"msg": "Field required",
"input": {"age": "six"},
- "url": match_pydantic_error_url("missing"),
},
{
"type": "decimal_parsing",
"loc": ["body", 1, "age"],
"msg": "Input should be a valid decimal",
"input": "six",
- "url": match_pydantic_error_url("decimal_parsing"),
},
]
}
diff --git a/tests/test_multi_query_errors.py b/tests/test_multi_query_errors.py
index 470a35808..8162d986c 100644
--- a/tests/test_multi_query_errors.py
+++ b/tests/test_multi_query_errors.py
@@ -3,7 +3,6 @@ from typing import List
from dirty_equals import IsDict
from fastapi import FastAPI, Query
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
app = FastAPI()
@@ -33,14 +32,12 @@ def test_multi_query_incorrect():
"loc": ["query", "q", 0],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "five",
- "url": match_pydantic_error_url("int_parsing"),
},
{
"type": "int_parsing",
"loc": ["query", "q", 1],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "six",
- "url": match_pydantic_error_url("int_parsing"),
},
]
}
diff --git a/tests/test_param_include_in_schema.py b/tests/test_param_include_in_schema.py
index 26201e9e2..f461947c9 100644
--- a/tests/test_param_include_in_schema.py
+++ b/tests/test_param_include_in_schema.py
@@ -9,14 +9,14 @@ app = FastAPI()
@app.get("/hidden_cookie")
async def hidden_cookie(
- hidden_cookie: Optional[str] = Cookie(default=None, include_in_schema=False)
+ hidden_cookie: Optional[str] = Cookie(default=None, include_in_schema=False),
):
return {"hidden_cookie": hidden_cookie}
@app.get("/hidden_header")
async def hidden_header(
- hidden_header: Optional[str] = Header(default=None, include_in_schema=False)
+ hidden_header: Optional[str] = Header(default=None, include_in_schema=False),
):
return {"hidden_header": hidden_header}
@@ -28,7 +28,7 @@ async def hidden_path(hidden_path: str = Path(include_in_schema=False)):
@app.get("/hidden_query")
async def hidden_query(
- hidden_query: Optional[str] = Query(default=None, include_in_schema=False)
+ hidden_query: Optional[str] = Query(default=None, include_in_schema=False),
):
return {"hidden_query": hidden_query}
diff --git a/tests/test_path.py b/tests/test_path.py
index 848b245e2..09c1f13fb 100644
--- a/tests/test_path.py
+++ b/tests/test_path.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from .main import app
@@ -54,7 +53,6 @@ def test_path_int_foobar():
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foobar",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -83,7 +81,6 @@ def test_path_int_True():
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "True",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -118,7 +115,6 @@ def test_path_int_42_5():
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "42.5",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -147,7 +143,6 @@ def test_path_float_foobar():
"loc": ["path", "item_id"],
"msg": "Input should be a valid number, unable to parse string as a number",
"input": "foobar",
- "url": match_pydantic_error_url("float_parsing"),
}
]
}
@@ -176,7 +171,6 @@ def test_path_float_True():
"loc": ["path", "item_id"],
"msg": "Input should be a valid number, unable to parse string as a number",
"input": "True",
- "url": match_pydantic_error_url("float_parsing"),
}
]
}
@@ -217,7 +211,6 @@ def test_path_bool_foobar():
"loc": ["path", "item_id"],
"msg": "Input should be a valid boolean, unable to interpret input",
"input": "foobar",
- "url": match_pydantic_error_url("bool_parsing"),
}
]
}
@@ -252,7 +245,6 @@ def test_path_bool_42():
"loc": ["path", "item_id"],
"msg": "Input should be a valid boolean, unable to interpret input",
"input": "42",
- "url": match_pydantic_error_url("bool_parsing"),
}
]
}
@@ -281,7 +273,6 @@ def test_path_bool_42_5():
"loc": ["path", "item_id"],
"msg": "Input should be a valid boolean, unable to interpret input",
"input": "42.5",
- "url": match_pydantic_error_url("bool_parsing"),
}
]
}
@@ -353,7 +344,6 @@ def test_path_param_minlength_fo():
"msg": "String should have at least 3 characters",
"input": "fo",
"ctx": {"min_length": 3},
- "url": match_pydantic_error_url("string_too_short"),
}
]
}
@@ -390,7 +380,6 @@ def test_path_param_maxlength_foobar():
"msg": "String should have at most 3 characters",
"input": "foobar",
"ctx": {"max_length": 3},
- "url": match_pydantic_error_url("string_too_long"),
}
]
}
@@ -427,7 +416,6 @@ def test_path_param_min_maxlength_foobar():
"msg": "String should have at most 3 characters",
"input": "foobar",
"ctx": {"max_length": 3},
- "url": match_pydantic_error_url("string_too_long"),
}
]
}
@@ -458,7 +446,6 @@ def test_path_param_min_maxlength_f():
"msg": "String should have at least 2 characters",
"input": "f",
"ctx": {"min_length": 2},
- "url": match_pydantic_error_url("string_too_short"),
}
]
}
@@ -494,7 +481,6 @@ def test_path_param_gt_2():
"msg": "Input should be greater than 3",
"input": "2",
"ctx": {"gt": 3.0},
- "url": match_pydantic_error_url("greater_than"),
}
]
}
@@ -531,7 +517,6 @@ def test_path_param_gt0_0():
"msg": "Input should be greater than 0",
"input": "0",
"ctx": {"gt": 0.0},
- "url": match_pydantic_error_url("greater_than"),
}
]
}
@@ -574,7 +559,6 @@ def test_path_param_ge_2():
"msg": "Input should be greater than or equal to 3",
"input": "2",
"ctx": {"ge": 3.0},
- "url": match_pydantic_error_url("greater_than_equal"),
}
]
}
@@ -605,7 +589,6 @@ def test_path_param_lt_42():
"msg": "Input should be less than 3",
"input": "42",
"ctx": {"lt": 3.0},
- "url": match_pydantic_error_url("less_than"),
}
]
}
@@ -648,7 +631,6 @@ def test_path_param_lt0_0():
"msg": "Input should be less than 0",
"input": "0",
"ctx": {"lt": 0.0},
- "url": match_pydantic_error_url("less_than"),
}
]
}
@@ -679,7 +661,6 @@ def test_path_param_le_42():
"msg": "Input should be less than or equal to 3",
"input": "42",
"ctx": {"le": 3.0},
- "url": match_pydantic_error_url("less_than_equal"),
}
]
}
@@ -728,7 +709,6 @@ def test_path_param_lt_gt_4():
"msg": "Input should be less than 3",
"input": "4",
"ctx": {"lt": 3.0},
- "url": match_pydantic_error_url("less_than"),
}
]
}
@@ -759,7 +739,6 @@ def test_path_param_lt_gt_0():
"msg": "Input should be greater than 1",
"input": "0",
"ctx": {"gt": 1.0},
- "url": match_pydantic_error_url("greater_than"),
}
]
}
@@ -807,7 +786,6 @@ def test_path_param_le_ge_4():
"msg": "Input should be less than or equal to 3",
"input": "4",
"ctx": {"le": 3.0},
- "url": match_pydantic_error_url("less_than_equal"),
}
]
}
@@ -844,7 +822,6 @@ def test_path_param_lt_int_42():
"msg": "Input should be less than 3",
"input": "42",
"ctx": {"lt": 3},
- "url": match_pydantic_error_url("less_than"),
}
]
}
@@ -874,7 +851,6 @@ def test_path_param_lt_int_2_7():
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "2.7",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -910,7 +886,6 @@ def test_path_param_gt_int_2():
"msg": "Input should be greater than 3",
"input": "2",
"ctx": {"gt": 3},
- "url": match_pydantic_error_url("greater_than"),
}
]
}
@@ -940,7 +915,6 @@ def test_path_param_gt_int_2_7():
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "2.7",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -970,7 +944,6 @@ def test_path_param_le_int_42():
"msg": "Input should be less than or equal to 3",
"input": "42",
"ctx": {"le": 3},
- "url": match_pydantic_error_url("less_than_equal"),
}
]
}
@@ -1012,7 +985,6 @@ def test_path_param_le_int_2_7():
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "2.7",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -1054,7 +1026,6 @@ def test_path_param_ge_int_2():
"msg": "Input should be greater than or equal to 3",
"input": "2",
"ctx": {"ge": 3},
- "url": match_pydantic_error_url("greater_than_equal"),
}
]
}
@@ -1084,7 +1055,6 @@ def test_path_param_ge_int_2_7():
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "2.7",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -1120,7 +1090,6 @@ def test_path_param_lt_gt_int_4():
"msg": "Input should be less than 3",
"input": "4",
"ctx": {"lt": 3},
- "url": match_pydantic_error_url("less_than"),
}
]
}
@@ -1151,7 +1120,6 @@ def test_path_param_lt_gt_int_0():
"msg": "Input should be greater than 1",
"input": "0",
"ctx": {"gt": 1},
- "url": match_pydantic_error_url("greater_than"),
}
]
}
@@ -1181,7 +1149,6 @@ def test_path_param_lt_gt_int_2_7():
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "2.7",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -1229,7 +1196,6 @@ def test_path_param_le_ge_int_4():
"msg": "Input should be less than or equal to 3",
"input": "4",
"ctx": {"le": 3},
- "url": match_pydantic_error_url("less_than_equal"),
}
]
}
@@ -1259,7 +1225,6 @@ def test_path_param_le_ge_int_2_7():
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "2.7",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
diff --git a/tests/test_query.py b/tests/test_query.py
index 5bb9995d6..57f551d2a 100644
--- a/tests/test_query.py
+++ b/tests/test_query.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from .main import app
@@ -18,7 +17,6 @@ def test_query():
"loc": ["query", "query"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -53,7 +51,6 @@ def test_query_not_declared_baz():
"loc": ["query", "query"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -100,7 +97,6 @@ def test_query_int():
"loc": ["query", "query"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -135,7 +131,6 @@ def test_query_int_query_42_5():
"loc": ["query", "query"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "42.5",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -164,7 +159,6 @@ def test_query_int_query_baz():
"loc": ["query", "query"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "baz",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -193,7 +187,6 @@ def test_query_int_not_declared_baz():
"loc": ["query", "query"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -234,7 +227,6 @@ def test_query_int_optional_query_foo():
"loc": ["query", "query"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -275,7 +267,6 @@ def test_query_int_default_query_foo():
"loc": ["query", "query"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -316,7 +307,6 @@ def test_query_param_required():
"loc": ["query", "query"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -351,7 +341,6 @@ def test_query_param_required_int():
"loc": ["query", "query"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -386,7 +375,6 @@ def test_query_param_required_int_query_foo():
"loc": ["query", "query"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
@@ -408,3 +396,26 @@ def test_query_frozenset_query_1_query_1_query_2():
response = client.get("/query/frozenset/?query=1&query=1&query=2")
assert response.status_code == 200
assert response.json() == "1,2"
+
+
+def test_query_list():
+ response = client.get("/query/list/?device_ids=1&device_ids=2")
+ assert response.status_code == 200
+ assert response.json() == [1, 2]
+
+
+def test_query_list_empty():
+ response = client.get("/query/list/")
+ assert response.status_code == 422
+
+
+def test_query_list_default():
+ response = client.get("/query/list-default/?device_ids=1&device_ids=2")
+ assert response.status_code == 200
+ assert response.json() == [1, 2]
+
+
+def test_query_list_default_empty():
+ response = client.get("/query/list-default/")
+ assert response.status_code == 200
+ assert response.json() == []
diff --git a/tests/test_regex_deprecated_body.py b/tests/test_regex_deprecated_body.py
index ca1ab514c..74654ff3c 100644
--- a/tests/test_regex_deprecated_body.py
+++ b/tests/test_regex_deprecated_body.py
@@ -2,7 +2,6 @@ import pytest
from dirty_equals import IsDict
from fastapi import FastAPI, Form
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from typing_extensions import Annotated
from .utils import needs_py310
@@ -14,7 +13,7 @@ def get_client():
@app.post("/items/")
async def read_items(
- q: Annotated[str | None, Form(regex="^fixedquery$")] = None
+ q: Annotated[str | None, Form(regex="^fixedquery$")] = None,
):
if q:
return f"Hello {q}"
@@ -55,7 +54,6 @@ def test_query_nonregexquery():
"msg": "String should match pattern '^fixedquery$'",
"input": "nonregexquery",
"ctx": {"pattern": "^fixedquery$"},
- "url": match_pydantic_error_url("string_pattern_mismatch"),
}
]
}
diff --git a/tests/test_regex_deprecated_params.py b/tests/test_regex_deprecated_params.py
index 79a653353..2ce64c686 100644
--- a/tests/test_regex_deprecated_params.py
+++ b/tests/test_regex_deprecated_params.py
@@ -2,7 +2,6 @@ import pytest
from dirty_equals import IsDict
from fastapi import FastAPI, Query
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from typing_extensions import Annotated
from .utils import needs_py310
@@ -14,7 +13,7 @@ def get_client():
@app.get("/items/")
async def read_items(
- q: Annotated[str | None, Query(regex="^fixedquery$")] = None
+ q: Annotated[str | None, Query(regex="^fixedquery$")] = None,
):
if q:
return f"Hello {q}"
@@ -55,7 +54,6 @@ def test_query_params_str_validations_item_query_nonregexquery():
"msg": "String should match pattern '^fixedquery$'",
"input": "nonregexquery",
"ctx": {"pattern": "^fixedquery$"},
- "url": match_pydantic_error_url("string_pattern_mismatch"),
}
]
}
diff --git a/tests/test_security_oauth2.py b/tests/test_security_oauth2.py
index e98f80ebf..7d914d034 100644
--- a/tests/test_security_oauth2.py
+++ b/tests/test_security_oauth2.py
@@ -2,7 +2,6 @@ from dirty_equals import IsDict
from fastapi import Depends, FastAPI, Security
from fastapi.security import OAuth2, OAuth2PasswordRequestFormStrict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from pydantic import BaseModel
app = FastAPI()
@@ -71,21 +70,18 @@ def test_strict_login_no_data():
"loc": ["body", "grant_type"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "username"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "password"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -124,7 +120,6 @@ def test_strict_login_no_grant_type():
"loc": ["body", "grant_type"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -157,7 +152,6 @@ def test_strict_login_incorrect_grant_type():
"msg": "String should match pattern 'password'",
"input": "incorrect",
"ctx": {"pattern": "password"},
- "url": match_pydantic_error_url("string_pattern_mismatch"),
}
]
}
diff --git a/tests/test_security_oauth2_optional.py b/tests/test_security_oauth2_optional.py
index d06c01bba..0da3b911e 100644
--- a/tests/test_security_oauth2_optional.py
+++ b/tests/test_security_oauth2_optional.py
@@ -4,7 +4,6 @@ from dirty_equals import IsDict
from fastapi import Depends, FastAPI, Security
from fastapi.security import OAuth2, OAuth2PasswordRequestFormStrict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from pydantic import BaseModel
app = FastAPI()
@@ -75,21 +74,18 @@ def test_strict_login_no_data():
"loc": ["body", "grant_type"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "username"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "password"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -128,7 +124,6 @@ def test_strict_login_no_grant_type():
"loc": ["body", "grant_type"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -161,7 +156,6 @@ def test_strict_login_incorrect_grant_type():
"msg": "String should match pattern 'password'",
"input": "incorrect",
"ctx": {"pattern": "password"},
- "url": match_pydantic_error_url("string_pattern_mismatch"),
}
]
}
diff --git a/tests/test_security_oauth2_optional_description.py b/tests/test_security_oauth2_optional_description.py
index 9287e4366..85a9f9b39 100644
--- a/tests/test_security_oauth2_optional_description.py
+++ b/tests/test_security_oauth2_optional_description.py
@@ -4,7 +4,6 @@ from dirty_equals import IsDict
from fastapi import Depends, FastAPI, Security
from fastapi.security import OAuth2, OAuth2PasswordRequestFormStrict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from pydantic import BaseModel
app = FastAPI()
@@ -76,21 +75,18 @@ def test_strict_login_None():
"loc": ["body", "grant_type"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "username"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "password"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -129,7 +125,6 @@ def test_strict_login_no_grant_type():
"loc": ["body", "grant_type"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -162,7 +157,6 @@ def test_strict_login_incorrect_grant_type():
"msg": "String should match pattern 'password'",
"input": "incorrect",
"ctx": {"pattern": "password"},
- "url": match_pydantic_error_url("string_pattern_mismatch"),
}
]
}
diff --git a/tests/test_tutorial/test_bigger_applications/test_main.py b/tests/test_tutorial/test_bigger_applications/test_main.py
index 526e265a6..35fdfa4a6 100644
--- a/tests/test_tutorial/test_bigger_applications/test_main.py
+++ b/tests/test_tutorial/test_bigger_applications/test_main.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -29,7 +28,6 @@ def test_users_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -64,7 +62,6 @@ def test_users_foo_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -99,7 +96,6 @@ def test_users_me_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -145,7 +141,6 @@ def test_items_with_no_token_jessica(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -192,7 +187,6 @@ def test_items_plumbus_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -233,7 +227,6 @@ def test_items_with_missing_x_token_header(client: TestClient):
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -262,7 +255,6 @@ def test_items_plumbus_with_missing_x_token_header(client: TestClient):
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -297,7 +289,6 @@ def test_root_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -326,14 +317,12 @@ def test_put_no_header(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_bigger_applications/test_main_an.py b/tests/test_tutorial/test_bigger_applications/test_main_an.py
index c0b77d4a7..4e2e3e74d 100644
--- a/tests/test_tutorial/test_bigger_applications/test_main_an.py
+++ b/tests/test_tutorial/test_bigger_applications/test_main_an.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -29,7 +28,6 @@ def test_users_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -64,7 +62,6 @@ def test_users_foo_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -99,7 +96,6 @@ def test_users_me_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -145,7 +141,6 @@ def test_items_with_no_token_jessica(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -192,7 +187,6 @@ def test_items_plumbus_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -233,7 +227,6 @@ def test_items_with_missing_x_token_header(client: TestClient):
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -262,7 +255,6 @@ def test_items_plumbus_with_missing_x_token_header(client: TestClient):
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -297,7 +289,6 @@ def test_root_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -326,14 +317,12 @@ def test_put_no_header(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_bigger_applications/test_main_an_py39.py b/tests/test_tutorial/test_bigger_applications/test_main_an_py39.py
index 948331b5d..8c9e976df 100644
--- a/tests/test_tutorial/test_bigger_applications/test_main_an_py39.py
+++ b/tests/test_tutorial/test_bigger_applications/test_main_an_py39.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -33,7 +32,6 @@ def test_users_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -70,7 +68,6 @@ def test_users_foo_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -107,7 +104,6 @@ def test_users_me_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -156,7 +152,6 @@ def test_items_with_no_token_jessica(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -206,7 +201,6 @@ def test_items_plumbus_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -250,7 +244,6 @@ def test_items_with_missing_x_token_header(client: TestClient):
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -280,7 +273,6 @@ def test_items_plumbus_with_missing_x_token_header(client: TestClient):
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -317,7 +309,6 @@ def test_root_with_no_token(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -347,14 +338,12 @@ def test_put_no_header(client: TestClient):
"loc": ["query", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py
index 2476b773f..0d55d73eb 100644
--- a/tests/test_tutorial/test_body/test_tutorial001.py
+++ b/tests/test_tutorial/test_body/test_tutorial001.py
@@ -3,7 +3,6 @@ from unittest.mock import patch
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture
@@ -74,7 +73,6 @@ def test_post_with_only_name(client: TestClient):
"loc": ["body", "price"],
"msg": "Field required",
"input": {"name": "Foo"},
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -103,7 +101,6 @@ def test_post_with_only_name_price(client: TestClient):
"loc": ["body", "price"],
"msg": "Input should be a valid number, unable to parse string as a number",
"input": "twenty",
- "url": match_pydantic_error_url("float_parsing"),
}
]
}
@@ -132,14 +129,12 @@ def test_post_with_no_data(client: TestClient):
"loc": ["body", "name"],
"msg": "Field required",
"input": {},
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "price"],
"msg": "Field required",
"input": {},
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -173,7 +168,6 @@ def test_post_with_none(client: TestClient):
"loc": ["body"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -244,7 +238,6 @@ def test_post_form_for_json(client: TestClient):
"loc": ["body"],
"msg": "Input should be a valid dictionary or object to extract fields from",
"input": "name=Foo&price=50.5",
- "url": match_pydantic_error_url("model_attributes_type"),
}
]
}
@@ -308,9 +301,6 @@ def test_wrong_headers(client: TestClient):
"loc": ["body"],
"msg": "Input should be a valid dictionary or object to extract fields from",
"input": '{"name": "Foo", "price": 50.5}',
- "url": match_pydantic_error_url(
- "model_attributes_type"
- ), # "https://errors.pydantic.dev/0.38.0/v/dict_attributes_type",
}
]
}
@@ -339,7 +329,6 @@ def test_wrong_headers(client: TestClient):
"loc": ["body"],
"msg": "Input should be a valid dictionary or object to extract fields from",
"input": '{"name": "Foo", "price": 50.5}',
- "url": match_pydantic_error_url("model_attributes_type"),
}
]
}
@@ -367,7 +356,6 @@ def test_wrong_headers(client: TestClient):
"loc": ["body"],
"msg": "Input should be a valid dictionary or object to extract fields from",
"input": '{"name": "Foo", "price": 50.5}',
- "url": match_pydantic_error_url("model_attributes_type"),
}
]
}
diff --git a/tests/test_tutorial/test_body/test_tutorial001_py310.py b/tests/test_tutorial/test_body/test_tutorial001_py310.py
index b64d86005..4b9c12806 100644
--- a/tests/test_tutorial/test_body/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_body/test_tutorial001_py310.py
@@ -3,7 +3,6 @@ from unittest.mock import patch
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py310
@@ -81,7 +80,6 @@ def test_post_with_only_name(client: TestClient):
"loc": ["body", "price"],
"msg": "Field required",
"input": {"name": "Foo"},
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -111,7 +109,6 @@ def test_post_with_only_name_price(client: TestClient):
"loc": ["body", "price"],
"msg": "Input should be a valid number, unable to parse string as a number",
"input": "twenty",
- "url": match_pydantic_error_url("float_parsing"),
}
]
}
@@ -141,14 +138,12 @@ def test_post_with_no_data(client: TestClient):
"loc": ["body", "name"],
"msg": "Field required",
"input": {},
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "price"],
"msg": "Field required",
"input": {},
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -183,7 +178,6 @@ def test_post_with_none(client: TestClient):
"loc": ["body"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -256,7 +250,6 @@ def test_post_form_for_json(client: TestClient):
"loc": ["body"],
"msg": "Input should be a valid dictionary or object to extract fields from",
"input": "name=Foo&price=50.5",
- "url": match_pydantic_error_url("model_attributes_type"),
}
]
}
@@ -324,7 +317,6 @@ def test_wrong_headers(client: TestClient):
"loc": ["body"],
"msg": "Input should be a valid dictionary or object to extract fields from",
"input": '{"name": "Foo", "price": 50.5}',
- "url": match_pydantic_error_url("model_attributes_type"),
}
]
}
@@ -353,7 +345,6 @@ def test_wrong_headers(client: TestClient):
"loc": ["body"],
"msg": "Input should be a valid dictionary or object to extract fields from",
"input": '{"name": "Foo", "price": 50.5}',
- "url": match_pydantic_error_url("model_attributes_type"),
}
]
}
@@ -381,7 +372,6 @@ def test_wrong_headers(client: TestClient):
"loc": ["body"],
"msg": "Input should be a valid dictionary or object to extract fields from",
"input": '{"name": "Foo", "price": 50.5}',
- "url": match_pydantic_error_url("model_attributes_type"),
}
]
}
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001.py b/tests/test_tutorial/test_body_fields/test_tutorial001.py
index 1ff2d9576..fd6139eb9 100644
--- a/tests/test_tutorial/test_body_fields/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -57,7 +56,6 @@ def test_invalid_price(client: TestClient):
"msg": "Input should be greater than 0",
"input": -3.0,
"ctx": {"gt": 0.0},
- "url": match_pydantic_error_url("greater_than"),
}
]
}
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_an.py b/tests/test_tutorial/test_body_fields/test_tutorial001_an.py
index 907d6842a..72c18c1f7 100644
--- a/tests/test_tutorial/test_body_fields/test_tutorial001_an.py
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001_an.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -57,7 +56,6 @@ def test_invalid_price(client: TestClient):
"msg": "Input should be greater than 0",
"input": -3.0,
"ctx": {"gt": 0.0},
- "url": match_pydantic_error_url("greater_than"),
}
]
}
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_an_py310.py b/tests/test_tutorial/test_body_fields/test_tutorial001_an_py310.py
index 431d2d181..1bc62868f 100644
--- a/tests/test_tutorial/test_body_fields/test_tutorial001_an_py310.py
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001_an_py310.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py310
@@ -62,7 +61,6 @@ def test_invalid_price(client: TestClient):
"msg": "Input should be greater than 0",
"input": -3.0,
"ctx": {"gt": 0.0},
- "url": match_pydantic_error_url("greater_than"),
}
]
}
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_an_py39.py b/tests/test_tutorial/test_body_fields/test_tutorial001_an_py39.py
index 8cef6c154..3c5557a1b 100644
--- a/tests/test_tutorial/test_body_fields/test_tutorial001_an_py39.py
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001_an_py39.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -62,7 +61,6 @@ def test_invalid_price(client: TestClient):
"msg": "Input should be greater than 0",
"input": -3.0,
"ctx": {"gt": 0.0},
- "url": match_pydantic_error_url("greater_than"),
}
]
}
diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py b/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py
index b48cd9ec2..8c1386aa6 100644
--- a/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py310
@@ -62,7 +61,6 @@ def test_invalid_price(client: TestClient):
"msg": "Input should be greater than 0",
"input": -3.0,
"ctx": {"gt": 0.0},
- "url": match_pydantic_error_url("greater_than"),
}
]
}
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
index e5dc13b26..6275ebe95 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -50,7 +49,6 @@ def test_post_id_foo(client: TestClient):
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an.py
index 51e8e3a4e..5cd3e2c4a 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -50,7 +49,6 @@ def test_post_id_foo(client: TestClient):
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py310.py
index 8ac1f7261..0173ab21b 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py310.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py310.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py310
@@ -56,7 +55,6 @@ def test_post_id_foo(client: TestClient):
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py39.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py39.py
index 7ada42c52..cda19918a 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py39.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py39.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -56,7 +55,6 @@ def test_post_id_foo(client: TestClient):
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py
index 0a832eaf6..663291933 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py310
@@ -56,7 +55,6 @@ def test_post_id_foo(client: TestClient):
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
index 2046579a9..c26f8b89b 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -46,21 +45,18 @@ def test_post_body_no_data(client: TestClient):
"loc": ["body", "item"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "user"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "importance"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -99,21 +95,18 @@ def test_post_body_empty_list(client: TestClient):
"loc": ["body", "item"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "user"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "importance"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an.py
index 1282483e0..62c7e2fad 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -46,21 +45,18 @@ def test_post_body_no_data(client: TestClient):
"loc": ["body", "item"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "user"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "importance"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -99,21 +95,18 @@ def test_post_body_empty_list(client: TestClient):
"loc": ["body", "item"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "user"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "importance"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py310.py
index 577c079d0..f46430fb5 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py310.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py310.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py310
@@ -50,21 +49,18 @@ def test_post_body_no_data(client: TestClient):
"loc": ["body", "item"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "user"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "importance"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -104,21 +100,18 @@ def test_post_body_empty_list(client: TestClient):
"loc": ["body", "item"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "user"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "importance"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py39.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py39.py
index 0ec04151c..29071cddc 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py39.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py39.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -50,21 +49,18 @@ def test_post_body_no_data(client: TestClient):
"loc": ["body", "item"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "user"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "importance"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -104,21 +100,18 @@ def test_post_body_empty_list(client: TestClient):
"loc": ["body", "item"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "user"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "importance"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py
index 9caf5fe6c..133afe9b5 100644
--- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py
+++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py310
@@ -50,21 +49,18 @@ def test_post_body_no_data(client: TestClient):
"loc": ["body", "item"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "user"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "importance"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -104,21 +100,18 @@ def test_post_body_empty_list(client: TestClient):
"loc": ["body", "item"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "user"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "importance"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py
index f4a76be44..762073aea 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -31,7 +30,6 @@ def test_post_invalid_body(client: TestClient):
"loc": ["body", "foo", "[key]"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py
index 8ab9bcac8..24623cecc 100644
--- a/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py
+++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -35,7 +34,6 @@ def test_post_invalid_body(client: TestClient):
"loc": ["body", "foo", "[key]"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
diff --git a/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py
index 34a18b12c..aff070d74 100644
--- a/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py
+++ b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py
@@ -20,10 +20,8 @@ def client():
def test_swagger_ui_html(client: TestClient):
response = client.get("/docs")
assert response.status_code == 200, response.text
- assert (
- "https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui-bundle.js" in response.text
- )
- assert "https://unpkg.com/swagger-ui-dist@5.9.0/swagger-ui.css" in response.text
+ assert "https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js" in response.text
+ assert "https://unpkg.com/swagger-ui-dist@5/swagger-ui.css" in response.text
def test_swagger_ui_oauth2_redirect_html(client: TestClient):
diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py
index ad142ec88..6f7355aaa 100644
--- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py
+++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.custom_request_and_route.tutorial002 import app
@@ -23,7 +22,6 @@ def test_exception_handler_body_access():
"loc": ["body"],
"msg": "Input should be a valid list",
"input": {"numbers": [1, 2, 3]},
- "url": match_pydantic_error_url("list_type"),
}
],
"body": '{"numbers": [1, 2, 3]}',
diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006c.py b/tests/test_tutorial/test_custom_response/test_tutorial006c.py
index 51aa1833d..2675f2a93 100644
--- a/tests/test_tutorial/test_custom_response/test_tutorial006c.py
+++ b/tests/test_tutorial/test_custom_response/test_tutorial006c.py
@@ -8,7 +8,7 @@ client = TestClient(app)
def test_redirect_status_code():
response = client.get("/pydantic", follow_redirects=False)
assert response.status_code == 302
- assert response.headers["location"] == "https://pydantic-docs.helpmanual.io/"
+ assert response.headers["location"] == "https://docs.pydantic.dev/"
def test_openapi_schema():
diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial001.py b/tests/test_tutorial/test_dataclasses/test_tutorial001.py
index 9f1200f37..762654d29 100644
--- a/tests/test_tutorial/test_dataclasses/test_tutorial001.py
+++ b/tests/test_tutorial/test_dataclasses/test_tutorial001.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.dataclasses.tutorial001 import app
@@ -29,7 +28,6 @@ def test_post_invalid_item():
"loc": ["body", "price"],
"msg": "Input should be a valid number, unable to parse string as a number",
"input": "invalid price",
- "url": match_pydantic_error_url("float_parsing"),
}
]
}
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006.py b/tests/test_tutorial/test_dependencies/test_tutorial006.py
index 704e389a5..5f14d9a3b 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial006.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial006.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.dependencies.tutorial006 import app
@@ -18,14 +17,12 @@ def test_get_no_headers():
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["header", "x-key"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006_an.py b/tests/test_tutorial/test_dependencies/test_tutorial006_an.py
index 5034fceba..a307ff808 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial006_an.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial006_an.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.dependencies.tutorial006_an import app
@@ -18,14 +17,12 @@ def test_get_no_headers():
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["header", "x-key"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial006_an_py39.py
index 3fc22dd3c..b41b1537e 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial006_an_py39.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial006_an_py39.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -26,14 +25,12 @@ def test_get_no_headers(client: TestClient):
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["header", "x-key"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008b_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial008b_an_py39.py
index 7f51fc52a..7d24809a8 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial008b_an_py39.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial008b_an_py39.py
@@ -1,23 +1,33 @@
+import pytest
from fastapi.testclient import TestClient
-from docs_src.dependencies.tutorial008b_an import app
+from ...utils import needs_py39
-client = TestClient(app)
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial008b_an_py39 import app
-def test_get_no_item():
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+def test_get_no_item(client: TestClient):
response = client.get("/items/foo")
assert response.status_code == 404, response.text
assert response.json() == {"detail": "Item not found"}
-def test_owner_error():
+@needs_py39
+def test_owner_error(client: TestClient):
response = client.get("/items/plumbus")
assert response.status_code == 400, response.text
assert response.json() == {"detail": "Owner error: Rick"}
-def test_get_item():
+@needs_py39
+def test_get_item(client: TestClient):
response = client.get("/items/portal-gun")
assert response.status_code == 200, response.text
assert response.json() == {"description": "Gun to create portals", "owner": "Rick"}
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008c.py b/tests/test_tutorial/test_dependencies/test_tutorial008c.py
new file mode 100644
index 000000000..27be8895a
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial008c.py
@@ -0,0 +1,38 @@
+import pytest
+from fastapi.exceptions import FastAPIError
+from fastapi.testclient import TestClient
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial008c import app
+
+ client = TestClient(app)
+ return client
+
+
+def test_get_no_item(client: TestClient):
+ response = client.get("/items/foo")
+ assert response.status_code == 404, response.text
+ assert response.json() == {"detail": "Item not found, there's only a plumbus here"}
+
+
+def test_get(client: TestClient):
+ response = client.get("/items/plumbus")
+ assert response.status_code == 200, response.text
+ assert response.json() == "plumbus"
+
+
+def test_fastapi_error(client: TestClient):
+ with pytest.raises(FastAPIError) as exc_info:
+ client.get("/items/portal-gun")
+ assert "No response object was returned" in exc_info.value.args[0]
+
+
+def test_internal_server_error():
+ from docs_src.dependencies.tutorial008c import app
+
+ client = TestClient(app, raise_server_exceptions=False)
+ response = client.get("/items/portal-gun")
+ assert response.status_code == 500, response.text
+ assert response.text == "Internal Server Error"
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008c_an.py b/tests/test_tutorial/test_dependencies/test_tutorial008c_an.py
new file mode 100644
index 000000000..10fa1ab50
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial008c_an.py
@@ -0,0 +1,38 @@
+import pytest
+from fastapi.exceptions import FastAPIError
+from fastapi.testclient import TestClient
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial008c_an import app
+
+ client = TestClient(app)
+ return client
+
+
+def test_get_no_item(client: TestClient):
+ response = client.get("/items/foo")
+ assert response.status_code == 404, response.text
+ assert response.json() == {"detail": "Item not found, there's only a plumbus here"}
+
+
+def test_get(client: TestClient):
+ response = client.get("/items/plumbus")
+ assert response.status_code == 200, response.text
+ assert response.json() == "plumbus"
+
+
+def test_fastapi_error(client: TestClient):
+ with pytest.raises(FastAPIError) as exc_info:
+ client.get("/items/portal-gun")
+ assert "No response object was returned" in exc_info.value.args[0]
+
+
+def test_internal_server_error():
+ from docs_src.dependencies.tutorial008c_an import app
+
+ client = TestClient(app, raise_server_exceptions=False)
+ response = client.get("/items/portal-gun")
+ assert response.status_code == 500, response.text
+ assert response.text == "Internal Server Error"
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008c_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial008c_an_py39.py
new file mode 100644
index 000000000..6c3acff50
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial008c_an_py39.py
@@ -0,0 +1,44 @@
+import pytest
+from fastapi.exceptions import FastAPIError
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial008c_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+def test_get_no_item(client: TestClient):
+ response = client.get("/items/foo")
+ assert response.status_code == 404, response.text
+ assert response.json() == {"detail": "Item not found, there's only a plumbus here"}
+
+
+@needs_py39
+def test_get(client: TestClient):
+ response = client.get("/items/plumbus")
+ assert response.status_code == 200, response.text
+ assert response.json() == "plumbus"
+
+
+@needs_py39
+def test_fastapi_error(client: TestClient):
+ with pytest.raises(FastAPIError) as exc_info:
+ client.get("/items/portal-gun")
+ assert "No response object was returned" in exc_info.value.args[0]
+
+
+@needs_py39
+def test_internal_server_error():
+ from docs_src.dependencies.tutorial008c_an_py39 import app
+
+ client = TestClient(app, raise_server_exceptions=False)
+ response = client.get("/items/portal-gun")
+ assert response.status_code == 500, response.text
+ assert response.text == "Internal Server Error"
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008d.py b/tests/test_tutorial/test_dependencies/test_tutorial008d.py
new file mode 100644
index 000000000..043496112
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial008d.py
@@ -0,0 +1,41 @@
+import pytest
+from fastapi.testclient import TestClient
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial008d import app
+
+ client = TestClient(app)
+ return client
+
+
+def test_get_no_item(client: TestClient):
+ response = client.get("/items/foo")
+ assert response.status_code == 404, response.text
+ assert response.json() == {"detail": "Item not found, there's only a plumbus here"}
+
+
+def test_get(client: TestClient):
+ response = client.get("/items/plumbus")
+ assert response.status_code == 200, response.text
+ assert response.json() == "plumbus"
+
+
+def test_internal_error(client: TestClient):
+ from docs_src.dependencies.tutorial008d import InternalError
+
+ with pytest.raises(InternalError) as exc_info:
+ client.get("/items/portal-gun")
+ assert (
+ exc_info.value.args[0] == "The portal gun is too dangerous to be owned by Rick"
+ )
+
+
+def test_internal_server_error():
+ from docs_src.dependencies.tutorial008d import app
+
+ client = TestClient(app, raise_server_exceptions=False)
+ response = client.get("/items/portal-gun")
+ assert response.status_code == 500, response.text
+ assert response.text == "Internal Server Error"
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008d_an.py b/tests/test_tutorial/test_dependencies/test_tutorial008d_an.py
new file mode 100644
index 000000000..f29d8cdbe
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial008d_an.py
@@ -0,0 +1,41 @@
+import pytest
+from fastapi.testclient import TestClient
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial008d_an import app
+
+ client = TestClient(app)
+ return client
+
+
+def test_get_no_item(client: TestClient):
+ response = client.get("/items/foo")
+ assert response.status_code == 404, response.text
+ assert response.json() == {"detail": "Item not found, there's only a plumbus here"}
+
+
+def test_get(client: TestClient):
+ response = client.get("/items/plumbus")
+ assert response.status_code == 200, response.text
+ assert response.json() == "plumbus"
+
+
+def test_internal_error(client: TestClient):
+ from docs_src.dependencies.tutorial008d_an import InternalError
+
+ with pytest.raises(InternalError) as exc_info:
+ client.get("/items/portal-gun")
+ assert (
+ exc_info.value.args[0] == "The portal gun is too dangerous to be owned by Rick"
+ )
+
+
+def test_internal_server_error():
+ from docs_src.dependencies.tutorial008d_an import app
+
+ client = TestClient(app, raise_server_exceptions=False)
+ response = client.get("/items/portal-gun")
+ assert response.status_code == 500, response.text
+ assert response.text == "Internal Server Error"
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008d_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial008d_an_py39.py
new file mode 100644
index 000000000..0a585f4ad
--- /dev/null
+++ b/tests/test_tutorial/test_dependencies/test_tutorial008d_an_py39.py
@@ -0,0 +1,47 @@
+import pytest
+from fastapi.testclient import TestClient
+
+from ...utils import needs_py39
+
+
+@pytest.fixture(name="client")
+def get_client():
+ from docs_src.dependencies.tutorial008d_an_py39 import app
+
+ client = TestClient(app)
+ return client
+
+
+@needs_py39
+def test_get_no_item(client: TestClient):
+ response = client.get("/items/foo")
+ assert response.status_code == 404, response.text
+ assert response.json() == {"detail": "Item not found, there's only a plumbus here"}
+
+
+@needs_py39
+def test_get(client: TestClient):
+ response = client.get("/items/plumbus")
+ assert response.status_code == 200, response.text
+ assert response.json() == "plumbus"
+
+
+@needs_py39
+def test_internal_error(client: TestClient):
+ from docs_src.dependencies.tutorial008d_an_py39 import InternalError
+
+ with pytest.raises(InternalError) as exc_info:
+ client.get("/items/portal-gun")
+ assert (
+ exc_info.value.args[0] == "The portal gun is too dangerous to be owned by Rick"
+ )
+
+
+@needs_py39
+def test_internal_server_error():
+ from docs_src.dependencies.tutorial008d_an_py39 import app
+
+ client = TestClient(app, raise_server_exceptions=False)
+ response = client.get("/items/portal-gun")
+ assert response.status_code == 500, response.text
+ assert response.text == "Internal Server Error"
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012.py b/tests/test_tutorial/test_dependencies/test_tutorial012.py
index 753e62e43..6b53c83bb 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial012.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial012.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.dependencies.tutorial012 import app
@@ -18,14 +17,12 @@ def test_get_no_headers_items():
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["header", "x-key"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -59,14 +56,12 @@ def test_get_no_headers_users():
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["header", "x-key"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012_an.py b/tests/test_tutorial/test_dependencies/test_tutorial012_an.py
index 4157d4612..75adb69fc 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial012_an.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial012_an.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.dependencies.tutorial012_an import app
@@ -18,14 +17,12 @@ def test_get_no_headers_items():
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["header", "x-key"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -59,14 +56,12 @@ def test_get_no_headers_users():
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["header", "x-key"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial012_an_py39.py
index 9e46758cb..e0a3d1ec2 100644
--- a/tests/test_tutorial/test_dependencies/test_tutorial012_an_py39.py
+++ b/tests/test_tutorial/test_dependencies/test_tutorial012_an_py39.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -26,14 +25,12 @@ def test_get_no_headers_items(client: TestClient):
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["header", "x-key"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -68,14 +65,12 @@ def test_get_no_headers_users(client: TestClient):
"loc": ["header", "x-token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["header", "x-key"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
index 7710446ce..5558671b9 100644
--- a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py
@@ -67,6 +67,7 @@ def test_openapi_schema():
}
],
"requestBody": {
+ "required": True,
"content": {
"application/json": {
"schema": IsDict(
@@ -86,7 +87,7 @@ def test_openapi_schema():
}
)
}
- }
+ },
},
}
}
@@ -97,40 +98,16 @@ def test_openapi_schema():
"title": "Body_read_items_items__item_id__put",
"type": "object",
"properties": {
- "start_datetime": IsDict(
- {
- "title": "Start Datetime",
- "anyOf": [
- {"type": "string", "format": "date-time"},
- {"type": "null"},
- ],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {
- "title": "Start Datetime",
- "type": "string",
- "format": "date-time",
- }
- ),
- "end_datetime": IsDict(
- {
- "title": "End Datetime",
- "anyOf": [
- {"type": "string", "format": "date-time"},
- {"type": "null"},
- ],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {
- "title": "End Datetime",
- "type": "string",
- "format": "date-time",
- }
- ),
+ "start_datetime": {
+ "title": "Start Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "end_datetime": {
+ "title": "End Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
"repeat_at": IsDict(
{
"title": "Repeat At",
@@ -151,10 +128,8 @@ def test_openapi_schema():
"process_after": IsDict(
{
"title": "Process After",
- "anyOf": [
- {"type": "string", "format": "duration"},
- {"type": "null"},
- ],
+ "type": "string",
+ "format": "duration",
}
)
| IsDict(
@@ -166,6 +141,7 @@ def test_openapi_schema():
}
),
},
+ "required": ["start_datetime", "end_datetime", "process_after"],
},
"ValidationError": {
"title": "ValidationError",
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an.py
index 9951b3b51..e309f8bd6 100644
--- a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an.py
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an.py
@@ -67,6 +67,7 @@ def test_openapi_schema():
}
],
"requestBody": {
+ "required": True,
"content": {
"application/json": {
"schema": IsDict(
@@ -86,7 +87,7 @@ def test_openapi_schema():
}
)
}
- }
+ },
},
}
}
@@ -97,40 +98,16 @@ def test_openapi_schema():
"title": "Body_read_items_items__item_id__put",
"type": "object",
"properties": {
- "start_datetime": IsDict(
- {
- "title": "Start Datetime",
- "anyOf": [
- {"type": "string", "format": "date-time"},
- {"type": "null"},
- ],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {
- "title": "Start Datetime",
- "type": "string",
- "format": "date-time",
- }
- ),
- "end_datetime": IsDict(
- {
- "title": "End Datetime",
- "anyOf": [
- {"type": "string", "format": "date-time"},
- {"type": "null"},
- ],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {
- "title": "End Datetime",
- "type": "string",
- "format": "date-time",
- }
- ),
+ "start_datetime": {
+ "title": "Start Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "end_datetime": {
+ "title": "End Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
"repeat_at": IsDict(
{
"title": "Repeat At",
@@ -151,10 +128,8 @@ def test_openapi_schema():
"process_after": IsDict(
{
"title": "Process After",
- "anyOf": [
- {"type": "string", "format": "duration"},
- {"type": "null"},
- ],
+ "type": "string",
+ "format": "duration",
}
)
| IsDict(
@@ -166,6 +141,7 @@ def test_openapi_schema():
}
),
},
+ "required": ["start_datetime", "end_datetime", "process_after"],
},
"ValidationError": {
"title": "ValidationError",
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py310.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py310.py
index 7c482b8cb..ca110dc00 100644
--- a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py310.py
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py310.py
@@ -76,6 +76,7 @@ def test_openapi_schema(client: TestClient):
}
],
"requestBody": {
+ "required": True,
"content": {
"application/json": {
"schema": IsDict(
@@ -95,7 +96,7 @@ def test_openapi_schema(client: TestClient):
}
)
}
- }
+ },
},
}
}
@@ -106,40 +107,16 @@ def test_openapi_schema(client: TestClient):
"title": "Body_read_items_items__item_id__put",
"type": "object",
"properties": {
- "start_datetime": IsDict(
- {
- "title": "Start Datetime",
- "anyOf": [
- {"type": "string", "format": "date-time"},
- {"type": "null"},
- ],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {
- "title": "Start Datetime",
- "type": "string",
- "format": "date-time",
- }
- ),
- "end_datetime": IsDict(
- {
- "title": "End Datetime",
- "anyOf": [
- {"type": "string", "format": "date-time"},
- {"type": "null"},
- ],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {
- "title": "End Datetime",
- "type": "string",
- "format": "date-time",
- }
- ),
+ "start_datetime": {
+ "title": "Start Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "end_datetime": {
+ "title": "End Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
"repeat_at": IsDict(
{
"title": "Repeat At",
@@ -160,10 +137,8 @@ def test_openapi_schema(client: TestClient):
"process_after": IsDict(
{
"title": "Process After",
- "anyOf": [
- {"type": "string", "format": "duration"},
- {"type": "null"},
- ],
+ "type": "string",
+ "format": "duration",
}
)
| IsDict(
@@ -175,6 +150,7 @@ def test_openapi_schema(client: TestClient):
}
),
},
+ "required": ["start_datetime", "end_datetime", "process_after"],
},
"ValidationError": {
"title": "ValidationError",
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py39.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py39.py
index 87473867b..3386fb1fd 100644
--- a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py39.py
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py39.py
@@ -76,6 +76,7 @@ def test_openapi_schema(client: TestClient):
}
],
"requestBody": {
+ "required": True,
"content": {
"application/json": {
"schema": IsDict(
@@ -95,7 +96,7 @@ def test_openapi_schema(client: TestClient):
}
)
}
- }
+ },
},
}
}
@@ -106,40 +107,16 @@ def test_openapi_schema(client: TestClient):
"title": "Body_read_items_items__item_id__put",
"type": "object",
"properties": {
- "start_datetime": IsDict(
- {
- "title": "Start Datetime",
- "anyOf": [
- {"type": "string", "format": "date-time"},
- {"type": "null"},
- ],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {
- "title": "Start Datetime",
- "type": "string",
- "format": "date-time",
- }
- ),
- "end_datetime": IsDict(
- {
- "title": "End Datetime",
- "anyOf": [
- {"type": "string", "format": "date-time"},
- {"type": "null"},
- ],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {
- "title": "End Datetime",
- "type": "string",
- "format": "date-time",
- }
- ),
+ "start_datetime": {
+ "title": "Start Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "end_datetime": {
+ "title": "End Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
"repeat_at": IsDict(
{
"title": "Repeat At",
@@ -160,10 +137,8 @@ def test_openapi_schema(client: TestClient):
"process_after": IsDict(
{
"title": "Process After",
- "anyOf": [
- {"type": "string", "format": "duration"},
- {"type": "null"},
- ],
+ "type": "string",
+ "format": "duration",
}
)
| IsDict(
@@ -175,6 +150,7 @@ def test_openapi_schema(client: TestClient):
}
),
},
+ "required": ["start_datetime", "end_datetime", "process_after"],
},
"ValidationError": {
"title": "ValidationError",
diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py
index 0b71d9177..50c9aefdf 100644
--- a/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py
+++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py
@@ -76,6 +76,7 @@ def test_openapi_schema(client: TestClient):
}
],
"requestBody": {
+ "required": True,
"content": {
"application/json": {
"schema": IsDict(
@@ -95,7 +96,7 @@ def test_openapi_schema(client: TestClient):
}
)
}
- }
+ },
},
}
}
@@ -106,40 +107,16 @@ def test_openapi_schema(client: TestClient):
"title": "Body_read_items_items__item_id__put",
"type": "object",
"properties": {
- "start_datetime": IsDict(
- {
- "title": "Start Datetime",
- "anyOf": [
- {"type": "string", "format": "date-time"},
- {"type": "null"},
- ],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {
- "title": "Start Datetime",
- "type": "string",
- "format": "date-time",
- }
- ),
- "end_datetime": IsDict(
- {
- "title": "End Datetime",
- "anyOf": [
- {"type": "string", "format": "date-time"},
- {"type": "null"},
- ],
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {
- "title": "End Datetime",
- "type": "string",
- "format": "date-time",
- }
- ),
+ "start_datetime": {
+ "title": "Start Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
+ "end_datetime": {
+ "title": "End Datetime",
+ "type": "string",
+ "format": "date-time",
+ },
"repeat_at": IsDict(
{
"title": "Repeat At",
@@ -160,10 +137,8 @@ def test_openapi_schema(client: TestClient):
"process_after": IsDict(
{
"title": "Process After",
- "anyOf": [
- {"type": "string", "format": "duration"},
- {"type": "null"},
- ],
+ "type": "string",
+ "format": "duration",
}
)
| IsDict(
@@ -175,6 +150,7 @@ def test_openapi_schema(client: TestClient):
}
),
},
+ "required": ["start_datetime", "end_datetime", "process_after"],
},
"ValidationError": {
"title": "ValidationError",
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial005.py b/tests/test_tutorial/test_handling_errors/test_tutorial005.py
index 494c317ca..581b2e4c7 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial005.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial005.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.handling_errors.tutorial005 import app
@@ -18,7 +17,6 @@ def test_post_validation_error():
"loc": ["body", "size"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "XL",
- "url": match_pydantic_error_url("int_parsing"),
}
],
"body": {"title": "towel", "size": "XL"},
diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial006.py b/tests/test_tutorial/test_handling_errors/test_tutorial006.py
index cc2b496a8..7d2f553aa 100644
--- a/tests/test_tutorial/test_handling_errors/test_tutorial006.py
+++ b/tests/test_tutorial/test_handling_errors/test_tutorial006.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.handling_errors.tutorial006 import app
@@ -18,7 +17,6 @@ def test_get_validation_error():
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
- "url": match_pydantic_error_url("int_parsing"),
}
]
}
diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py
index 2d2802269..8240b60a6 100644
--- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py
+++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py
@@ -1,6 +1,5 @@
import pytest
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_pydanticv2
@@ -64,7 +63,6 @@ def test_post_invalid(client: TestClient):
"loc": ["tags", 3],
"msg": "Input should be a valid string",
"input": {"sneaky": "object"},
- "url": match_pydantic_error_url("string_type"),
}
]
}
diff --git a/tests/test_tutorial/test_query_params/test_tutorial005.py b/tests/test_tutorial/test_query_params/test_tutorial005.py
index 921586357..05ae85b45 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial005.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial005.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.query_params.tutorial005 import app
@@ -24,7 +23,6 @@ def test_foo_no_needy():
"loc": ["query", "needy"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
diff --git a/tests/test_tutorial/test_query_params/test_tutorial006.py b/tests/test_tutorial/test_query_params/test_tutorial006.py
index e07803d6c..dbd63da16 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial006.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial006.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -34,21 +33,18 @@ def test_foo_no_needy(client: TestClient):
"loc": ["query", "needy"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "int_parsing",
"loc": ["query", "skip"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "a",
- "url": match_pydantic_error_url("int_parsing"),
},
{
"type": "int_parsing",
"loc": ["query", "limit"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "b",
- "url": match_pydantic_error_url("int_parsing"),
},
]
}
diff --git a/tests/test_tutorial/test_query_params/test_tutorial006_py310.py b/tests/test_tutorial/test_query_params/test_tutorial006_py310.py
index 6c4c0b4dc..5055e3805 100644
--- a/tests/test_tutorial/test_query_params/test_tutorial006_py310.py
+++ b/tests/test_tutorial/test_query_params/test_tutorial006_py310.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py310
@@ -38,21 +37,18 @@ def test_foo_no_needy(client: TestClient):
"loc": ["query", "needy"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "int_parsing",
"loc": ["query", "skip"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "a",
- "url": match_pydantic_error_url("int_parsing"),
},
{
"type": "int_parsing",
"loc": ["query", "limit"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "b",
- "url": match_pydantic_error_url("int_parsing"),
},
]
}
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py
index 287c2e8f8..945cee3d2 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -45,7 +44,6 @@ def test_query_params_str_validations_item_query_nonregexquery(client: TestClien
"msg": "String should match pattern '^fixedquery$'",
"input": "nonregexquery",
"ctx": {"pattern": "^fixedquery$"},
- "url": match_pydantic_error_url("string_pattern_mismatch"),
}
]
}
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py
index 5b0515070..23951a9aa 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -45,7 +44,6 @@ def test_query_params_str_validations_item_query_nonregexquery(client: TestClien
"msg": "String should match pattern '^fixedquery$'",
"input": "nonregexquery",
"ctx": {"pattern": "^fixedquery$"},
- "url": match_pydantic_error_url("string_pattern_mismatch"),
}
]
}
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py310.py
index d22b1ce20..2968af563 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py310.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py310.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py310
@@ -51,7 +50,6 @@ def test_query_params_str_validations_item_query_nonregexquery(client: TestClien
"msg": "String should match pattern '^fixedquery$'",
"input": "nonregexquery",
"ctx": {"pattern": "^fixedquery$"},
- "url": match_pydantic_error_url("string_pattern_mismatch"),
}
]
}
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py39.py
index 3e7d5d3ad..534ba8759 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py39.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py39.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -51,7 +50,6 @@ def test_query_params_str_validations_item_query_nonregexquery(client: TestClien
"msg": "String should match pattern '^fixedquery$'",
"input": "nonregexquery",
"ctx": {"pattern": "^fixedquery$"},
- "url": match_pydantic_error_url("string_pattern_mismatch"),
}
]
}
diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_py310.py
index 1c3a09d39..886bceca2 100644
--- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_py310.py
+++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_py310.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py310
@@ -51,7 +50,6 @@ def test_query_params_str_validations_item_query_nonregexquery(client: TestClien
"msg": "String should match pattern '^fixedquery$'",
"input": "nonregexquery",
"ctx": {"pattern": "^fixedquery$"},
- "url": match_pydantic_error_url("string_pattern_mismatch"),
}
]
}
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001.py b/tests/test_tutorial/test_request_files/test_tutorial001.py
index 91cc2b636..f5817593b 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.request_files.tutorial001 import app
@@ -29,7 +28,6 @@ def test_post_form_no_body():
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -58,7 +56,6 @@ def test_post_body_json():
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_an.py b/tests/test_tutorial/test_request_files/test_tutorial001_an.py
index 3021eb3c3..1c78e3679 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001_an.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_an.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.request_files.tutorial001_an import app
@@ -18,7 +17,6 @@ def test_post_form_no_body():
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -47,7 +45,6 @@ def test_post_body_json():
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_an_py39.py b/tests/test_tutorial/test_request_files/test_tutorial001_an_py39.py
index 04f3a4693..843fcec28 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial001_an_py39.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial001_an_py39.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -26,7 +25,6 @@ def test_post_form_no_body(client: TestClient):
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -56,7 +54,6 @@ def test_post_body_json(client: TestClient):
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
diff --git a/tests/test_tutorial/test_request_files/test_tutorial002.py b/tests/test_tutorial/test_request_files/test_tutorial002.py
index ed9680b62..db1552e5c 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial002.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial002.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.request_files.tutorial002 import app
@@ -18,7 +17,6 @@ def test_post_form_no_body():
"loc": ["body", "files"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -47,7 +45,6 @@ def test_post_body_json():
"loc": ["body", "files"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
diff --git a/tests/test_tutorial/test_request_files/test_tutorial002_an.py b/tests/test_tutorial/test_request_files/test_tutorial002_an.py
index ea8c1216c..b16da1669 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial002_an.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial002_an.py
@@ -1,6 +1,5 @@
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from docs_src.request_files.tutorial002_an import app
@@ -18,7 +17,6 @@ def test_post_form_no_body():
"loc": ["body", "files"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -47,7 +45,6 @@ def test_post_body_json():
"loc": ["body", "files"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
diff --git a/tests/test_tutorial/test_request_files/test_tutorial002_an_py39.py b/tests/test_tutorial/test_request_files/test_tutorial002_an_py39.py
index 6d5877836..e092a516d 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial002_an_py39.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial002_an_py39.py
@@ -2,7 +2,6 @@ import pytest
from dirty_equals import IsDict
from fastapi import FastAPI
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -32,7 +31,6 @@ def test_post_form_no_body(client: TestClient):
"loc": ["body", "files"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -62,7 +60,6 @@ def test_post_body_json(client: TestClient):
"loc": ["body", "files"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
diff --git a/tests/test_tutorial/test_request_files/test_tutorial002_py39.py b/tests/test_tutorial/test_request_files/test_tutorial002_py39.py
index 2d0445421..341a9ac8e 100644
--- a/tests/test_tutorial/test_request_files/test_tutorial002_py39.py
+++ b/tests/test_tutorial/test_request_files/test_tutorial002_py39.py
@@ -2,7 +2,6 @@ import pytest
from dirty_equals import IsDict
from fastapi import FastAPI
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -43,7 +42,6 @@ def test_post_form_no_body(client: TestClient):
"loc": ["body", "files"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -73,7 +71,6 @@ def test_post_body_json(client: TestClient):
"loc": ["body", "files"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001.py b/tests/test_tutorial/test_request_forms/test_tutorial001.py
index 805daeb10..cbef9d30f 100644
--- a/tests/test_tutorial/test_request_forms/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_forms/test_tutorial001.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -29,7 +28,6 @@ def test_post_body_form_no_password(client: TestClient):
"loc": ["body", "password"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -58,7 +56,6 @@ def test_post_body_form_no_username(client: TestClient):
"loc": ["body", "username"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -87,14 +84,12 @@ def test_post_body_form_no_data(client: TestClient):
"loc": ["body", "username"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "password"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -128,14 +123,12 @@ def test_post_body_json(client: TestClient):
"loc": ["body", "username"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "password"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001_an.py b/tests/test_tutorial/test_request_forms/test_tutorial001_an.py
index c43a0b695..88b8452bc 100644
--- a/tests/test_tutorial/test_request_forms/test_tutorial001_an.py
+++ b/tests/test_tutorial/test_request_forms/test_tutorial001_an.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="client")
@@ -29,7 +28,6 @@ def test_post_body_form_no_password(client: TestClient):
"loc": ["body", "password"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -58,7 +56,6 @@ def test_post_body_form_no_username(client: TestClient):
"loc": ["body", "username"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -87,14 +84,12 @@ def test_post_body_form_no_data(client: TestClient):
"loc": ["body", "username"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "password"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -128,14 +123,12 @@ def test_post_body_json(client: TestClient):
"loc": ["body", "username"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "password"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001_an_py39.py b/tests/test_tutorial/test_request_forms/test_tutorial001_an_py39.py
index 078b812aa..3229897c9 100644
--- a/tests/test_tutorial/test_request_forms/test_tutorial001_an_py39.py
+++ b/tests/test_tutorial/test_request_forms/test_tutorial001_an_py39.py
@@ -1,7 +1,6 @@
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -33,7 +32,6 @@ def test_post_body_form_no_password(client: TestClient):
"loc": ["body", "password"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -63,7 +61,6 @@ def test_post_body_form_no_username(client: TestClient):
"loc": ["body", "username"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
}
]
}
@@ -93,14 +90,12 @@ def test_post_body_form_no_data(client: TestClient):
"loc": ["body", "username"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "password"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -135,14 +130,12 @@ def test_post_body_json(client: TestClient):
"loc": ["body", "username"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "password"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
index cac58639f..1e1ad2a87 100644
--- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
+++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
@@ -2,7 +2,6 @@ import pytest
from dirty_equals import IsDict
from fastapi import FastAPI
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="app")
@@ -29,21 +28,18 @@ def test_post_form_no_body(client: TestClient):
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "fileb"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -82,14 +78,12 @@ def test_post_form_no_file(client: TestClient):
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "fileb"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -123,21 +117,18 @@ def test_post_body_json(client: TestClient):
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "fileb"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -181,14 +172,12 @@ def test_post_file_no_token(tmp_path, app: FastAPI):
"loc": ["body", "fileb"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an.py
index 009568048..5daf4dbf4 100644
--- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an.py
+++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an.py
@@ -2,7 +2,6 @@ import pytest
from dirty_equals import IsDict
from fastapi import FastAPI
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
@pytest.fixture(name="app")
@@ -29,21 +28,18 @@ def test_post_form_no_body(client: TestClient):
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "fileb"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -82,14 +78,12 @@ def test_post_form_no_file(client: TestClient):
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "fileb"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -123,21 +117,18 @@ def test_post_body_json(client: TestClient):
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "fileb"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -181,14 +172,12 @@ def test_post_file_no_token(tmp_path, app: FastAPI):
"loc": ["body", "fileb"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an_py39.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an_py39.py
index 3d007e90b..3f1204efa 100644
--- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an_py39.py
+++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an_py39.py
@@ -2,7 +2,6 @@ import pytest
from dirty_equals import IsDict
from fastapi import FastAPI
from fastapi.testclient import TestClient
-from fastapi.utils import match_pydantic_error_url
from ...utils import needs_py39
@@ -32,21 +31,18 @@ def test_post_form_no_body(client: TestClient):
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "fileb"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -86,14 +82,12 @@ def test_post_form_no_file(client: TestClient):
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "fileb"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -128,21 +122,18 @@ def test_post_body_json(client: TestClient):
"loc": ["body", "file"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "fileb"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
@@ -187,14 +178,12 @@ def test_post_file_no_token(tmp_path, app: FastAPI):
"loc": ["body", "fileb"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
{
"type": "missing",
"loc": ["body", "token"],
"msg": "Field required",
"input": None,
- "url": match_pydantic_error_url("missing"),
},
]
}
diff --git a/tests/test_tutorial/test_security/test_tutorial005.py b/tests/test_tutorial/test_security/test_tutorial005.py
index c669c306d..2e580dbb3 100644
--- a/tests/test_tutorial/test_security/test_tutorial005.py
+++ b/tests/test_tutorial/test_security/test_tutorial005.py
@@ -128,7 +128,7 @@ def test_token_no_scope():
assert response.headers["WWW-Authenticate"] == 'Bearer scope="me"'
-def test_token_inexistent_user():
+def test_token_nonexistent_user():
response = client.get(
"/users/me",
headers={
diff --git a/tests/test_tutorial/test_security/test_tutorial005_an.py b/tests/test_tutorial/test_security/test_tutorial005_an.py
index aaab04f78..04c7d60bc 100644
--- a/tests/test_tutorial/test_security/test_tutorial005_an.py
+++ b/tests/test_tutorial/test_security/test_tutorial005_an.py
@@ -128,7 +128,7 @@ def test_token_no_scope():
assert response.headers["WWW-Authenticate"] == 'Bearer scope="me"'
-def test_token_inexistent_user():
+def test_token_nonexistent_user():
response = client.get(
"/users/me",
headers={
diff --git a/tests/test_tutorial/test_security/test_tutorial005_an_py310.py b/tests/test_tutorial/test_security/test_tutorial005_an_py310.py
index 243d0773c..9c7f83ed2 100644
--- a/tests/test_tutorial/test_security/test_tutorial005_an_py310.py
+++ b/tests/test_tutorial/test_security/test_tutorial005_an_py310.py
@@ -151,7 +151,7 @@ def test_token_no_scope(client: TestClient):
@needs_py310
-def test_token_inexistent_user(client: TestClient):
+def test_token_nonexistent_user(client: TestClient):
response = client.get(
"/users/me",
headers={
diff --git a/tests/test_tutorial/test_security/test_tutorial005_an_py39.py b/tests/test_tutorial/test_security/test_tutorial005_an_py39.py
index 17a3f9aa2..04cc1b014 100644
--- a/tests/test_tutorial/test_security/test_tutorial005_an_py39.py
+++ b/tests/test_tutorial/test_security/test_tutorial005_an_py39.py
@@ -151,7 +151,7 @@ def test_token_no_scope(client: TestClient):
@needs_py39
-def test_token_inexistent_user(client: TestClient):
+def test_token_nonexistent_user(client: TestClient):
response = client.get(
"/users/me",
headers={
diff --git a/tests/test_tutorial/test_security/test_tutorial005_py310.py b/tests/test_tutorial/test_security/test_tutorial005_py310.py
index 06455cd63..98c60c1c2 100644
--- a/tests/test_tutorial/test_security/test_tutorial005_py310.py
+++ b/tests/test_tutorial/test_security/test_tutorial005_py310.py
@@ -151,7 +151,7 @@ def test_token_no_scope(client: TestClient):
@needs_py310
-def test_token_inexistent_user(client: TestClient):
+def test_token_nonexistent_user(client: TestClient):
response = client.get(
"/users/me",
headers={
diff --git a/tests/test_tutorial/test_security/test_tutorial005_py39.py b/tests/test_tutorial/test_security/test_tutorial005_py39.py
index 9455bfb4e..cd2157d54 100644
--- a/tests/test_tutorial/test_security/test_tutorial005_py39.py
+++ b/tests/test_tutorial/test_security/test_tutorial005_py39.py
@@ -151,7 +151,7 @@ def test_token_no_scope(client: TestClient):
@needs_py39
-def test_token_inexistent_user(client: TestClient):
+def test_token_nonexistent_user(client: TestClient):
response = client.get(
"/users/me",
headers={
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases.py b/tests/test_tutorial/test_sql_databases/test_sql_databases.py
index 03e747433..e3e2b36a8 100644
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases.py
@@ -54,7 +54,7 @@ def test_get_user(client):
# TODO: pv2 add version with Pydantic v2
@needs_pydanticv1
-def test_inexistent_user(client):
+def test_nonexistent_user(client):
response = client.get("/users/999")
assert response.status_code == 404, response.text
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py
index a503ef2a6..73b97e09d 100644
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py
@@ -50,7 +50,7 @@ def test_get_user(client):
# TODO: pv2 add version with Pydantic v2
@needs_pydanticv1
-def test_inexistent_user(client):
+def test_nonexistent_user(client):
response = client.get("/users/999")
assert response.status_code == 404, response.text
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py
index d54cc6552..a078f012a 100644
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py
@@ -58,7 +58,7 @@ def test_get_user(client):
@needs_py310
# TODO: pv2 add version with Pydantic v2
@needs_pydanticv1
-def test_inexistent_user(client):
+def test_nonexistent_user(client):
response = client.get("/users/999")
assert response.status_code == 404, response.text
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py
index 4e43995e6..a5da07ac6 100644
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py
@@ -58,7 +58,7 @@ def test_get_user(client):
@needs_py39
# TODO: pv2 add version with Pydantic v2
@needs_pydanticv1
-def test_inexistent_user(client):
+def test_nonexistent_user(client):
response = client.get("/users/999")
assert response.status_code == 404, response.text
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py
index b89b8b031..5a9106598 100644
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py
@@ -57,7 +57,7 @@ def test_get_user(client):
@needs_py310
# TODO: pv2 add version with Pydantic v2
@needs_pydanticv1
-def test_inexistent_user(client):
+def test_nonexistent_user(client):
response = client.get("/users/999")
assert response.status_code == 404, response.text
diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py
index 13351bc81..a354ba905 100644
--- a/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py
+++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py
@@ -57,7 +57,7 @@ def test_get_user(client):
@needs_py39
# TODO: pv2 add version with Pydantic v2
@needs_pydanticv1
-def test_inexistent_user(client):
+def test_nonexistent_user(client):
response = client.get("/users/999")
assert response.status_code == 404, response.text
diff --git a/tests/test_tutorial/test_testing/test_main_b.py b/tests/test_tutorial/test_testing/test_main_b.py
index fc1a832f9..1e1836f5b 100644
--- a/tests/test_tutorial/test_testing/test_main_b.py
+++ b/tests/test_tutorial/test_testing/test_main_b.py
@@ -5,6 +5,6 @@ def test_app():
test_main.test_create_existing_item()
test_main.test_create_item()
test_main.test_create_item_bad_token()
- test_main.test_read_inexistent_item()
+ test_main.test_read_nonexistent_item()
test_main.test_read_item()
test_main.test_read_item_bad_token()
diff --git a/tests/test_tutorial/test_testing/test_main_b_an.py b/tests/test_tutorial/test_testing/test_main_b_an.py
index b64c5f710..e53fc3224 100644
--- a/tests/test_tutorial/test_testing/test_main_b_an.py
+++ b/tests/test_tutorial/test_testing/test_main_b_an.py
@@ -5,6 +5,6 @@ def test_app():
test_main.test_create_existing_item()
test_main.test_create_item()
test_main.test_create_item_bad_token()
- test_main.test_read_inexistent_item()
+ test_main.test_read_nonexistent_item()
test_main.test_read_item()
test_main.test_read_item_bad_token()
diff --git a/tests/test_tutorial/test_testing/test_main_b_an_py310.py b/tests/test_tutorial/test_testing/test_main_b_an_py310.py
index 194700b6d..c974e5dc1 100644
--- a/tests/test_tutorial/test_testing/test_main_b_an_py310.py
+++ b/tests/test_tutorial/test_testing/test_main_b_an_py310.py
@@ -8,6 +8,6 @@ def test_app():
test_main.test_create_existing_item()
test_main.test_create_item()
test_main.test_create_item_bad_token()
- test_main.test_read_inexistent_item()
+ test_main.test_read_nonexistent_item()
test_main.test_read_item()
test_main.test_read_item_bad_token()
diff --git a/tests/test_tutorial/test_testing/test_main_b_an_py39.py b/tests/test_tutorial/test_testing/test_main_b_an_py39.py
index 2f8a13623..71f99726c 100644
--- a/tests/test_tutorial/test_testing/test_main_b_an_py39.py
+++ b/tests/test_tutorial/test_testing/test_main_b_an_py39.py
@@ -8,6 +8,6 @@ def test_app():
test_main.test_create_existing_item()
test_main.test_create_item()
test_main.test_create_item_bad_token()
- test_main.test_read_inexistent_item()
+ test_main.test_read_nonexistent_item()
test_main.test_read_item()
test_main.test_read_item_bad_token()
diff --git a/tests/test_tutorial/test_testing/test_main_b_py310.py b/tests/test_tutorial/test_testing/test_main_b_py310.py
index a504ed234..e30cdc073 100644
--- a/tests/test_tutorial/test_testing/test_main_b_py310.py
+++ b/tests/test_tutorial/test_testing/test_main_b_py310.py
@@ -8,6 +8,6 @@ def test_app():
test_main.test_create_existing_item()
test_main.test_create_item()
test_main.test_create_item_bad_token()
- test_main.test_read_inexistent_item()
+ test_main.test_read_nonexistent_item()
test_main.test_read_item()
test_main.test_read_item_bad_token()