Add missing tests for code examples (#14569)

Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nils-Hero Lindemann <nilsherolindemann@proton.me>
This commit is contained in:
Motov Yurii
2025-12-26 11:43:02 +01:00
committed by GitHub
parent 5eb8d6ed8a
commit 3063ada72f
183 changed files with 10459 additions and 86 deletions

View File

@@ -0,0 +1,161 @@
import importlib
from typing import Union
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.body.{request.param}")
client = TestClient(mod.app)
return client
@pytest.mark.parametrize("price", ["50.5", 50.5])
def test_post_with_tax(client: TestClient, price: Union[str, float]):
response = client.post(
"/items/",
json={"name": "Foo", "price": price, "description": "Some Foo", "tax": 0.3},
)
assert response.status_code == 200
assert response.json() == {
"name": "Foo",
"price": 50.5,
"description": "Some Foo",
"tax": 0.3,
"price_with_tax": 50.8,
}
@pytest.mark.parametrize("price", ["50.5", 50.5])
def test_post_without_tax(client: TestClient, price: Union[str, float]):
response = client.post(
"/items/", json={"name": "Foo", "price": price, "description": "Some Foo"}
)
assert response.status_code == 200
assert response.json() == {
"name": "Foo",
"price": 50.5,
"description": "Some Foo",
"tax": None,
}
def test_post_with_no_data(client: TestClient):
response = client.post("/items/", json={})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "missing",
"loc": ["body", "name"],
"msg": "Field required",
"input": {},
},
{
"type": "missing",
"loc": ["body", "price"],
"msg": "Field required",
"input": {},
},
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"post": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Create Item",
"operationId": "create_item_items__post",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"price": {"title": "Price", "type": "number"},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,171 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.body.{request.param}")
client = TestClient(mod.app)
return client
def test_put_all(client: TestClient):
response = client.put(
"/items/123",
json={"name": "Foo", "price": 50.1, "description": "Some Foo", "tax": 0.3},
)
assert response.status_code == 200
assert response.json() == {
"item_id": 123,
"name": "Foo",
"price": 50.1,
"description": "Some Foo",
"tax": 0.3,
}
def test_put_only_required(client: TestClient):
response = client.put(
"/items/123",
json={"name": "Foo", "price": 50.1},
)
assert response.status_code == 200
assert response.json() == {
"item_id": 123,
"name": "Foo",
"price": 50.1,
"description": None,
"tax": None,
}
def test_put_with_no_data(client: TestClient):
response = client.put("/items/123", json={})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "missing",
"loc": ["body", "name"],
"msg": "Field required",
"input": {},
},
{
"type": "missing",
"loc": ["body", "price"],
"msg": "Field required",
"input": {},
},
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"put": {
"parameters": [
{
"in": "path",
"name": "item_id",
"required": True,
"schema": {
"title": "Item Id",
"type": "integer",
},
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Update Item",
"operationId": "update_item_items__item_id__put",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"price": {"title": "Price", "type": "number"},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,182 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.body.{request.param}")
client = TestClient(mod.app)
return client
def test_put_all(client: TestClient):
response = client.put(
"/items/123",
json={"name": "Foo", "price": 50.1, "description": "Some Foo", "tax": 0.3},
params={"q": "somequery"},
)
assert response.status_code == 200
assert response.json() == {
"item_id": 123,
"name": "Foo",
"price": 50.1,
"description": "Some Foo",
"tax": 0.3,
"q": "somequery",
}
def test_put_only_required(client: TestClient):
response = client.put(
"/items/123",
json={"name": "Foo", "price": 50.1},
)
assert response.status_code == 200
assert response.json() == {
"item_id": 123,
"name": "Foo",
"price": 50.1,
"description": None,
"tax": None,
}
def test_put_with_no_data(client: TestClient):
response = client.put("/items/123", json={})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "missing",
"loc": ["body", "name"],
"msg": "Field required",
"input": {},
},
{
"type": "missing",
"loc": ["body", "price"],
"msg": "Field required",
"input": {},
},
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"put": {
"parameters": [
{
"in": "path",
"name": "item_id",
"required": True,
"schema": {
"title": "Item Id",
"type": "integer",
},
},
{
"required": False,
"schema": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Q",
},
"name": "q",
"in": "query",
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Update Item",
"operationId": "update_item_items__item_id__put",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"price": {"title": "Price", "type": "number"},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,361 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.body_multiple_params.{request.param}")
client = TestClient(mod.app)
return client
def test_post_all(client: TestClient):
response = client.put(
"/items/5",
json={
"item": {
"name": "Foo",
"price": 50.5,
"description": "Some Foo",
"tax": 0.1,
},
"user": {"username": "johndoe", "full_name": "John Doe"},
},
)
assert response.status_code == 200
assert response.json() == {
"item_id": 5,
"item": {
"name": "Foo",
"price": 50.5,
"description": "Some Foo",
"tax": 0.1,
},
"user": {"username": "johndoe", "full_name": "John Doe"},
}
def test_post_required(client: TestClient):
response = client.put(
"/items/5",
json={
"item": {"name": "Foo", "price": 50.5},
"user": {"username": "johndoe"},
},
)
assert response.status_code == 200
assert response.json() == {
"item_id": 5,
"item": {
"name": "Foo",
"price": 50.5,
"description": None,
"tax": None,
},
"user": {"username": "johndoe", "full_name": None},
}
def test_post_no_body(client: TestClient):
response = client.put("/items/5", json=None)
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"input": None,
"loc": [
"body",
"item",
],
"msg": "Field required",
"type": "missing",
},
{
"input": None,
"loc": [
"body",
"user",
],
"msg": "Field required",
"type": "missing",
},
],
}
def test_post_no_item(client: TestClient):
response = client.put("/items/5", json={"user": {"username": "johndoe"}})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"input": None,
"loc": [
"body",
"item",
],
"msg": "Field required",
"type": "missing",
},
],
}
def test_post_no_user(client: TestClient):
response = client.put("/items/5", json={"item": {"name": "Foo", "price": 50.5}})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"input": None,
"loc": [
"body",
"user",
],
"msg": "Field required",
"type": "missing",
},
],
}
def test_post_missing_required_field_in_item(client: TestClient):
response = client.put(
"/items/5", json={"item": {"name": "Foo"}, "user": {"username": "johndoe"}}
)
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"input": {"name": "Foo"},
"loc": [
"body",
"item",
"price",
],
"msg": "Field required",
"type": "missing",
},
],
}
def test_post_missing_required_field_in_user(client: TestClient):
response = client.put(
"/items/5",
json={"item": {"name": "Foo", "price": 50.5}, "user": {"ful_name": "John Doe"}},
)
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"input": {"ful_name": "John Doe"},
"loc": [
"body",
"user",
"username",
],
"msg": "Field required",
"type": "missing",
},
],
}
def test_post_id_foo(client: TestClient):
response = client.put(
"/items/foo",
json={
"item": {"name": "Foo", "price": 50.5},
"user": {"username": "johndoe"},
},
)
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "int_parsing",
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"input": "foo",
}
]
}
def test_openapi_schema(client: TestClient):
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": {
"/items/{item_id}": {
"put": {
"operationId": "update_item_items__item_id__put",
"parameters": [
{
"in": "path",
"name": "item_id",
"required": True,
"schema": {
"title": "Item Id",
"type": "integer",
},
},
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Body_update_item_items__item_id__put",
},
},
},
"required": True,
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {},
},
},
"description": "Successful Response",
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
"summary": "Update Item",
},
},
},
"components": {
"schemas": {
"Body_update_item_items__item_id__put": {
"properties": {
"item": {
"$ref": "#/components/schemas/Item",
},
"user": {
"$ref": "#/components/schemas/User",
},
},
"required": [
"item",
"user",
],
"title": "Body_update_item_items__item_id__put",
"type": "object",
},
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"Item": {
"properties": {
"name": {
"title": "Name",
"type": "string",
},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {"title": "Price", "type": "number"},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
},
"required": [
"name",
"price",
],
"title": "Item",
"type": "object",
},
"User": {
"properties": {
"username": {
"title": "Username",
"type": "string",
},
"full_name": {
"title": "Full Name",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
},
"required": [
"username",
],
"title": "User",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,290 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
pytest.param("tutorial004_an_py39"),
pytest.param("tutorial004_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.body_multiple_params.{request.param}")
client = TestClient(mod.app)
return client
def test_put_all(client: TestClient):
response = client.put(
"/items/5",
json={
"importance": 2,
"item": {"name": "Foo", "price": 50.5},
"user": {"username": "Dave"},
},
params={"q": "somequery"},
)
assert response.status_code == 200
assert response.json() == {
"item_id": 5,
"importance": 2,
"item": {
"name": "Foo",
"price": 50.5,
"description": None,
"tax": None,
},
"user": {"username": "Dave", "full_name": None},
"q": "somequery",
}
def test_put_only_required(client: TestClient):
response = client.put(
"/items/5",
json={
"importance": 2,
"item": {"name": "Foo", "price": 50.5},
"user": {"username": "Dave"},
},
)
assert response.status_code == 200
assert response.json() == {
"item_id": 5,
"importance": 2,
"item": {
"name": "Foo",
"price": 50.5,
"description": None,
"tax": None,
},
"user": {"username": "Dave", "full_name": None},
}
def test_put_missing_body(client: TestClient):
response = client.put("/items/5")
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"input": None,
"loc": [
"body",
"item",
],
"msg": "Field required",
"type": "missing",
},
{
"input": None,
"loc": [
"body",
"user",
],
"msg": "Field required",
"type": "missing",
},
{
"input": None,
"loc": [
"body",
"importance",
],
"msg": "Field required",
"type": "missing",
},
],
}
def test_put_empty_body(client: TestClient):
response = client.put("/items/5", json={})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "missing",
"loc": ["body", "item"],
"msg": "Field required",
"input": None,
},
{
"type": "missing",
"loc": ["body", "user"],
"msg": "Field required",
"input": None,
},
{
"type": "missing",
"loc": ["body", "importance"],
"msg": "Field required",
"input": None,
},
]
}
def test_put_invalid_importance(client: TestClient):
response = client.put(
"/items/5",
json={
"importance": 0,
"item": {"name": "Foo", "price": 50.5},
"user": {"username": "Dave"},
},
)
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"loc": ["body", "importance"],
"msg": "Input should be greater than 0",
"type": "greater_than",
"input": 0,
"ctx": {"gt": 0},
},
],
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"put": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Update Item",
"operationId": "update_item_items__item_id__put",
"parameters": [
{
"required": True,
"schema": {"title": "Item Id", "type": "integer"},
"name": "item_id",
"in": "path",
},
{
"required": False,
"schema": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Q",
},
"name": "q",
"in": "query",
},
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Body_update_item_items__item_id__put"
}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {"title": "Price", "type": "number"},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
},
},
"User": {
"title": "User",
"required": ["username"],
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
"full_name": {
"title": "Full Name",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
},
},
"Body_update_item_items__item_id__put": {
"title": "Body_update_item_items__item_id__put",
"required": ["item", "user", "importance"],
"type": "object",
"properties": {
"item": {"$ref": "#/components/schemas/Item"},
"user": {"$ref": "#/components/schemas/User"},
"importance": {
"title": "Importance",
"type": "integer",
"exclusiveMinimum": 0.0,
},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,272 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial005_py39"),
pytest.param("tutorial005_py310", marks=needs_py310),
pytest.param("tutorial005_an_py39"),
pytest.param("tutorial005_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.body_multiple_params.{request.param}")
client = TestClient(mod.app)
return client
def test_post_all(client: TestClient):
response = client.put(
"/items/5",
json={
"item": {
"name": "Foo",
"price": 50.5,
"description": "Some Foo",
"tax": 0.1,
},
},
)
assert response.status_code == 200
assert response.json() == {
"item_id": 5,
"item": {
"name": "Foo",
"price": 50.5,
"description": "Some Foo",
"tax": 0.1,
},
}
def test_post_required(client: TestClient):
response = client.put(
"/items/5",
json={
"item": {"name": "Foo", "price": 50.5},
},
)
assert response.status_code == 200
assert response.json() == {
"item_id": 5,
"item": {
"name": "Foo",
"price": 50.5,
"description": None,
"tax": None,
},
}
def test_post_no_body(client: TestClient):
response = client.put("/items/5", json=None)
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"input": None,
"loc": [
"body",
"item",
],
"msg": "Field required",
"type": "missing",
},
],
}
def test_post_like_not_embeded(client: TestClient):
response = client.put(
"/items/5",
json={
"name": "Foo",
"price": 50.5,
},
)
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"input": None,
"loc": [
"body",
"item",
],
"msg": "Field required",
"type": "missing",
},
],
}
def test_post_missing_required_field_in_item(client: TestClient):
response = client.put(
"/items/5", json={"item": {"name": "Foo"}, "user": {"username": "johndoe"}}
)
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"input": {"name": "Foo"},
"loc": [
"body",
"item",
"price",
],
"msg": "Field required",
"type": "missing",
},
],
}
def test_openapi_schema(client: TestClient):
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": {
"/items/{item_id}": {
"put": {
"operationId": "update_item_items__item_id__put",
"parameters": [
{
"in": "path",
"name": "item_id",
"required": True,
"schema": {
"title": "Item Id",
"type": "integer",
},
},
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Body_update_item_items__item_id__put",
},
},
},
"required": True,
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {},
},
},
"description": "Successful Response",
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
"summary": "Update Item",
},
},
},
"components": {
"schemas": {
"Body_update_item_items__item_id__put": {
"properties": {
"item": {
"$ref": "#/components/schemas/Item",
},
},
"required": ["item"],
"title": "Body_update_item_items__item_id__put",
"type": "object",
},
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"Item": {
"properties": {
"name": {
"title": "Name",
"type": "string",
},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {"title": "Price", "type": "number"},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
},
"required": [
"name",
"price",
],
"title": "Item",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,251 @@
import importlib
import pytest
from dirty_equals import IsList
from fastapi.testclient import TestClient
from ...utils import needs_py310
UNTYPED_LIST_SCHEMA = {"type": "array", "items": {}}
LIST_OF_STR_SCHEMA = {"type": "array", "items": {"type": "string"}}
SET_OF_STR_SCHEMA = {"type": "array", "items": {"type": "string"}, "uniqueItems": True}
@pytest.fixture(
name="mod_name",
params=[
pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
],
)
def get_mod_name(request: pytest.FixtureRequest):
return request.param
@pytest.fixture(name="client")
def get_client(mod_name: str):
mod = importlib.import_module(f"docs_src.body_nested_models.{mod_name}")
client = TestClient(mod.app)
return client
def test_put_all(client: TestClient, mod_name: str):
if mod_name.startswith("tutorial003"):
tags_expected = IsList("foo", "bar", check_order=False)
else:
tags_expected = ["foo", "bar", "foo"]
response = client.put(
"/items/123",
json={
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
"tags": ["foo", "bar", "foo"],
},
)
assert response.status_code == 200, response.text
assert response.json() == {
"item_id": 123,
"item": {
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
"tags": tags_expected,
},
}
def test_put_only_required(client: TestClient):
response = client.put(
"/items/5",
json={"name": "Foo", "price": 35.4},
)
assert response.status_code == 200, response.text
assert response.json() == {
"item_id": 5,
"item": {
"name": "Foo",
"description": None,
"price": 35.4,
"tax": None,
"tags": [],
},
}
def test_put_empty_body(client: TestClient):
response = client.put(
"/items/5",
json={},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "name"],
"input": {},
"msg": "Field required",
"type": "missing",
},
{
"loc": ["body", "price"],
"input": {},
"msg": "Field required",
"type": "missing",
},
]
}
def test_put_missing_required(client: TestClient):
response = client.put(
"/items/5",
json={"description": "A very nice Item"},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "name"],
"input": {"description": "A very nice Item"},
"msg": "Field required",
"type": "missing",
},
{
"loc": ["body", "price"],
"input": {"description": "A very nice Item"},
"msg": "Field required",
"type": "missing",
},
]
}
def test_openapi_schema(client: TestClient, mod_name: str):
tags_schema = {"default": [], "title": "Tags"}
if mod_name.startswith("tutorial001"):
tags_schema.update(UNTYPED_LIST_SCHEMA)
elif mod_name.startswith("tutorial002"):
tags_schema.update(LIST_OF_STR_SCHEMA)
elif mod_name.startswith("tutorial003"):
tags_schema.update(SET_OF_STR_SCHEMA)
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"put": {
"parameters": [
{
"in": "path",
"name": "item_id",
"required": True,
"schema": {
"title": "Item Id",
"type": "integer",
},
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Update Item",
"operationId": "update_item_items__item_id__put",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Item",
}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"Item": {
"properties": {
"name": {
"title": "Name",
"type": "string",
},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {
"title": "Price",
"type": "number",
},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tags": tags_schema,
},
"required": [
"name",
"price",
],
"title": "Item",
"type": "object",
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,275 @@
import importlib
import pytest
from dirty_equals import IsList
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.body_nested_models.{request.param}")
client = TestClient(mod.app)
return client
def test_put_all(client: TestClient):
response = client.put(
"/items/123",
json={
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
"tags": ["foo", "bar", "foo"],
"image": {"url": "http://example.com/image.png", "name": "example image"},
},
)
assert response.status_code == 200, response.text
assert response.json() == {
"item_id": 123,
"item": {
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
"tags": IsList("foo", "bar", check_order=False),
"image": {"url": "http://example.com/image.png", "name": "example image"},
},
}
def test_put_only_required(client: TestClient):
response = client.put(
"/items/5",
json={"name": "Foo", "price": 35.4},
)
assert response.status_code == 200, response.text
assert response.json() == {
"item_id": 5,
"item": {
"name": "Foo",
"description": None,
"price": 35.4,
"tax": None,
"tags": [],
"image": None,
},
}
def test_put_empty_body(client: TestClient):
response = client.put(
"/items/5",
json={},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "name"],
"input": {},
"msg": "Field required",
"type": "missing",
},
{
"loc": ["body", "price"],
"input": {},
"msg": "Field required",
"type": "missing",
},
]
}
def test_put_missing_required_in_item(client: TestClient):
response = client.put(
"/items/5",
json={"description": "A very nice Item"},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "name"],
"input": {"description": "A very nice Item"},
"msg": "Field required",
"type": "missing",
},
{
"loc": ["body", "price"],
"input": {"description": "A very nice Item"},
"msg": "Field required",
"type": "missing",
},
]
}
def test_put_missing_required_in_image(client: TestClient):
response = client.put(
"/items/5",
json={
"name": "Foo",
"price": 35.4,
"image": {"url": "http://example.com/image.png"},
},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "image", "name"],
"input": {"url": "http://example.com/image.png"},
"msg": "Field required",
"type": "missing",
},
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"put": {
"parameters": [
{
"in": "path",
"name": "item_id",
"required": True,
"schema": {
"title": "Item Id",
"type": "integer",
},
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Update Item",
"operationId": "update_item_items__item_id__put",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Item",
}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"Image": {
"properties": {
"url": {
"title": "Url",
"type": "string",
},
"name": {
"title": "Name",
"type": "string",
},
},
"required": ["url", "name"],
"title": "Image",
"type": "object",
},
"Item": {
"properties": {
"name": {
"title": "Name",
"type": "string",
},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {
"title": "Price",
"type": "number",
},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tags": {
"title": "Tags",
"default": [],
"type": "array",
"items": {"type": "string"},
"uniqueItems": True,
},
"image": {
"anyOf": [
{"$ref": "#/components/schemas/Image"},
{"type": "null"},
],
},
},
"required": [
"name",
"price",
],
"title": "Item",
"type": "object",
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,301 @@
import importlib
import pytest
from dirty_equals import IsList
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial005_py39"),
pytest.param("tutorial005_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.body_nested_models.{request.param}")
client = TestClient(mod.app)
return client
def test_put_all(client: TestClient):
response = client.put(
"/items/123",
json={
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
"tags": ["foo", "bar", "foo"],
"image": {"url": "http://example.com/image.png", "name": "example image"},
},
)
assert response.status_code == 200, response.text
assert response.json() == {
"item_id": 123,
"item": {
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
"tags": IsList("foo", "bar", check_order=False),
"image": {"url": "http://example.com/image.png", "name": "example image"},
},
}
def test_put_only_required(client: TestClient):
response = client.put(
"/items/5",
json={"name": "Foo", "price": 35.4},
)
assert response.status_code == 200, response.text
assert response.json() == {
"item_id": 5,
"item": {
"name": "Foo",
"description": None,
"price": 35.4,
"tax": None,
"tags": [],
"image": None,
},
}
def test_put_empty_body(client: TestClient):
response = client.put(
"/items/5",
json={},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "name"],
"input": {},
"msg": "Field required",
"type": "missing",
},
{
"loc": ["body", "price"],
"input": {},
"msg": "Field required",
"type": "missing",
},
]
}
def test_put_missing_required_in_item(client: TestClient):
response = client.put(
"/items/5",
json={"description": "A very nice Item"},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "name"],
"input": {"description": "A very nice Item"},
"msg": "Field required",
"type": "missing",
},
{
"loc": ["body", "price"],
"input": {"description": "A very nice Item"},
"msg": "Field required",
"type": "missing",
},
]
}
def test_put_missing_required_in_image(client: TestClient):
response = client.put(
"/items/5",
json={
"name": "Foo",
"price": 35.4,
"image": {"url": "http://example.com/image.png"},
},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "image", "name"],
"input": {"url": "http://example.com/image.png"},
"msg": "Field required",
"type": "missing",
},
]
}
def test_put_wrong_url(client: TestClient):
response = client.put(
"/items/5",
json={
"name": "Foo",
"price": 35.4,
"image": {"url": "not a valid url", "name": "example image"},
},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "image", "url"],
"input": "not a valid url",
"msg": "Input should be a valid URL, relative URL without a base",
"type": "url_parsing",
"ctx": {"error": "relative URL without a base"},
},
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"put": {
"parameters": [
{
"in": "path",
"name": "item_id",
"required": True,
"schema": {
"title": "Item Id",
"type": "integer",
},
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Update Item",
"operationId": "update_item_items__item_id__put",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Item",
}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"Image": {
"properties": {
"url": {
"title": "Url",
"type": "string",
"format": "uri",
"maxLength": 2083,
"minLength": 1,
},
"name": {
"title": "Name",
"type": "string",
},
},
"required": ["url", "name"],
"title": "Image",
"type": "object",
},
"Item": {
"properties": {
"name": {
"title": "Name",
"type": "string",
},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {
"title": "Price",
"type": "number",
},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tags": {
"title": "Tags",
"default": [],
"type": "array",
"items": {"type": "string"},
"uniqueItems": True,
},
"image": {
"anyOf": [
{"$ref": "#/components/schemas/Image"},
{"type": "null"},
],
},
},
"required": [
"name",
"price",
],
"title": "Item",
"type": "object",
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,269 @@
import importlib
import pytest
from dirty_equals import IsList
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial006_py39"),
pytest.param("tutorial006_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.body_nested_models.{request.param}")
client = TestClient(mod.app)
return client
def test_put_all(client: TestClient):
response = client.put(
"/items/123",
json={
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
"tags": ["foo", "bar", "foo"],
"images": [
{"url": "http://example.com/image.png", "name": "example image"}
],
},
)
assert response.status_code == 200, response.text
assert response.json() == {
"item_id": 123,
"item": {
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
"tags": IsList("foo", "bar", check_order=False),
"images": [
{"url": "http://example.com/image.png", "name": "example image"}
],
},
}
def test_put_only_required(client: TestClient):
response = client.put(
"/items/5",
json={"name": "Foo", "price": 35.4},
)
assert response.status_code == 200, response.text
assert response.json() == {
"item_id": 5,
"item": {
"name": "Foo",
"description": None,
"price": 35.4,
"tax": None,
"tags": [],
"images": None,
},
}
def test_put_empty_body(client: TestClient):
response = client.put(
"/items/5",
json={},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "name"],
"input": {},
"msg": "Field required",
"type": "missing",
},
{
"loc": ["body", "price"],
"input": {},
"msg": "Field required",
"type": "missing",
},
]
}
def test_put_images_not_list(client: TestClient):
response = client.put(
"/items/5",
json={
"name": "Foo",
"price": 35.4,
"images": {"url": "http://example.com/image.png", "name": "example image"},
},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "images"],
"input": {
"url": "http://example.com/image.png",
"name": "example image",
},
"msg": "Input should be a valid list",
"type": "list_type",
},
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"put": {
"parameters": [
{
"in": "path",
"name": "item_id",
"required": True,
"schema": {
"title": "Item Id",
"type": "integer",
},
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Update Item",
"operationId": "update_item_items__item_id__put",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Item",
}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"Image": {
"properties": {
"url": {
"title": "Url",
"type": "string",
"format": "uri",
"maxLength": 2083,
"minLength": 1,
},
"name": {
"title": "Name",
"type": "string",
},
},
"required": ["url", "name"],
"title": "Image",
"type": "object",
},
"Item": {
"properties": {
"name": {
"title": "Name",
"type": "string",
},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {
"title": "Price",
"type": "number",
},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tags": {
"title": "Tags",
"default": [],
"type": "array",
"items": {"type": "string"},
"uniqueItems": True,
},
"images": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/Image",
},
"type": "array",
},
{
"type": "null",
},
],
"title": "Images",
},
},
"required": [
"name",
"price",
],
"title": "Item",
"type": "object",
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,344 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial007_py39"),
pytest.param("tutorial007_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.body_nested_models.{request.param}")
client = TestClient(mod.app)
return client
def test_post_all(client: TestClient):
data = {
"name": "Special Offer",
"description": "This is a special offer",
"price": 38.6,
"items": [
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
"tags": ["foo"],
"images": [
{
"url": "http://example.com/image.png",
"name": "example image",
}
],
}
],
}
response = client.post(
"/offers/",
json=data,
)
assert response.status_code == 200, response.text
assert response.json() == data
def test_put_only_required(client: TestClient):
response = client.post(
"/offers/",
json={
"name": "Special Offer",
"price": 38.6,
"items": [
{
"name": "Foo",
"price": 35.4,
"images": [
{
"url": "http://example.com/image.png",
"name": "example image",
}
],
}
],
},
)
assert response.status_code == 200, response.text
assert response.json() == {
"name": "Special Offer",
"description": None,
"price": 38.6,
"items": [
{
"name": "Foo",
"description": None,
"price": 35.4,
"tax": None,
"tags": [],
"images": [
{
"url": "http://example.com/image.png",
"name": "example image",
}
],
}
],
}
def test_put_empty_body(client: TestClient):
response = client.post(
"/offers/",
json={},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "name"],
"input": {},
"msg": "Field required",
"type": "missing",
},
{
"loc": ["body", "price"],
"input": {},
"msg": "Field required",
"type": "missing",
},
{
"loc": ["body", "items"],
"input": {},
"msg": "Field required",
"type": "missing",
},
]
}
def test_put_missing_required_in_items(client: TestClient):
response = client.post(
"/offers/",
json={
"name": "Special Offer",
"price": 38.6,
"items": [{}],
},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "items", 0, "name"],
"input": {},
"msg": "Field required",
"type": "missing",
},
{
"loc": ["body", "items", 0, "price"],
"input": {},
"msg": "Field required",
"type": "missing",
},
]
}
def test_put_missing_required_in_images(client: TestClient):
response = client.post(
"/offers/",
json={
"name": "Special Offer",
"price": 38.6,
"items": [
{"name": "Foo", "price": 35.4, "images": [{}]},
],
},
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", "items", 0, "images", 0, "url"],
"input": {},
"msg": "Field required",
"type": "missing",
},
{
"loc": ["body", "items", 0, "images", 0, "name"],
"input": {},
"msg": "Field required",
"type": "missing",
},
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/offers/": {
"post": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Create Offer",
"operationId": "create_offer_offers__post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Offer",
}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"Image": {
"properties": {
"url": {
"title": "Url",
"type": "string",
"format": "uri",
"maxLength": 2083,
"minLength": 1,
},
"name": {
"title": "Name",
"type": "string",
},
},
"required": ["url", "name"],
"title": "Image",
"type": "object",
},
"Item": {
"properties": {
"name": {
"title": "Name",
"type": "string",
},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {
"title": "Price",
"type": "number",
},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tags": {
"title": "Tags",
"default": [],
"type": "array",
"items": {"type": "string"},
"uniqueItems": True,
},
"images": {
"anyOf": [
{
"items": {
"$ref": "#/components/schemas/Image",
},
"type": "array",
},
{
"type": "null",
},
],
"title": "Images",
},
},
"required": [
"name",
"price",
],
"title": "Item",
"type": "object",
},
"Offer": {
"properties": {
"name": {
"title": "Name",
"type": "string",
},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"price": {
"title": "Price",
"type": "number",
},
"items": {
"title": "Items",
"type": "array",
"items": {"$ref": "#/components/schemas/Item"},
},
},
"required": ["name", "price", "items"],
"title": "Offer",
"type": "object",
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,157 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial008_py39"),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.body_nested_models.{request.param}")
client = TestClient(mod.app)
return client
def test_post_body(client: TestClient):
data = [
{"url": "http://example.com/", "name": "Example"},
{"url": "http://fastapi.tiangolo.com/", "name": "FastAPI"},
]
response = client.post("/images/multiple", json=data)
assert response.status_code == 200, response.text
assert response.json() == data
def test_post_invalid_list_item(client: TestClient):
data = [{"url": "not a valid url", "name": "Example"}]
response = client.post("/images/multiple", json=data)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", 0, "url"],
"input": "not a valid url",
"msg": "Input should be a valid URL, relative URL without a base",
"type": "url_parsing",
"ctx": {"error": "relative URL without a base"},
},
]
}
def test_post_not_a_list(client: TestClient):
data = {"url": "http://example.com/", "name": "Example"}
response = client.post("/images/multiple", json=data)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body"],
"input": {
"name": "Example",
"url": "http://example.com/",
},
"msg": "Input should be a valid list",
"type": "list_type",
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/images/multiple/": {
"post": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Create Multiple Images",
"operationId": "create_multiple_images_images_multiple__post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"title": "Images",
"type": "array",
"items": {"$ref": "#/components/schemas/Image"},
}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"Image": {
"properties": {
"url": {
"title": "Url",
"type": "string",
"format": "uri",
"maxLength": 2083,
"minLength": 1,
},
"name": {
"title": "Name",
"type": "string",
},
},
"required": ["url", "name"],
"title": "Image",
"type": "object",
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,207 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.body_updates.{request.param}")
client = TestClient(mod.app)
return client
def test_get(client: TestClient):
response = client.get("/items/baz")
assert response.status_code == 200, response.text
assert response.json() == {
"name": "Baz",
"description": None,
"price": 50.2,
"tax": 10.5,
"tags": [],
}
def test_patch_all(client: TestClient):
response = client.patch(
"/items/foo",
json={
"name": "Fooz",
"description": "Item description",
"price": 3,
"tax": 10.5,
"tags": ["tag1", "tag2"],
},
)
assert response.json() == {
"name": "Fooz",
"description": "Item description",
"price": 3,
"tax": 10.5,
"tags": ["tag1", "tag2"],
}
def test_patch_name(client: TestClient):
response = client.patch(
"/items/bar",
json={"name": "Barz"},
)
assert response.json() == {
"name": "Barz",
"description": "The bartenders",
"price": 62,
"tax": 20.2,
"tags": [],
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Item",
"operationId": "read_item_items__item_id__get",
"parameters": [
{
"required": True,
"schema": {"title": "Item Id", "type": "string"},
"name": "item_id",
"in": "path",
}
],
},
"patch": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Update Item",
"operationId": "update_item_items__item_id__patch",
"parameters": [
{
"required": True,
"schema": {"title": "Item Id", "type": "string"},
"name": "item_id",
"in": "path",
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
},
}
},
"components": {
"schemas": {
"Item": {
"type": "object",
"title": "Item",
"properties": {
"name": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Name",
},
"description": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Description",
},
"price": {
"anyOf": [{"type": "number"}, {"type": "null"}],
"title": "Price",
},
"tax": {"title": "Tax", "type": "number", "default": 10.5},
"tags": {
"title": "Tags",
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -1,17 +1,29 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from docs_src.custom_response.tutorial001_py39 import app
client = TestClient(app)
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial001_py39"),
pytest.param("tutorial010_py39"),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.custom_response.{request.param}")
client = TestClient(mod.app)
return client
def test_get_custom_response():
def test_get_custom_response(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [{"item_id": "Foo"}]
def test_openapi_schema():
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {

View File

@@ -0,0 +1,68 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="mod_name",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial003_py39"),
pytest.param("tutorial004_py39"),
],
)
def get_mod_name(request: pytest.FixtureRequest) -> str:
return request.param
@pytest.fixture(name="client")
def get_client(mod_name: str) -> TestClient:
mod = importlib.import_module(f"docs_src.custom_response.{mod_name}")
return TestClient(mod.app)
html_contents = """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
def test_get_custom_response(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.text == html_contents
def test_openapi_schema(client: TestClient, mod_name: str):
if mod_name.startswith("tutorial003"):
response_content = {"application/json": {"schema": {}}}
else:
response_content = {"text/html": {"schema": {"type": "string"}}}
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": response_content,
}
},
"summary": "Read Items",
"operationId": "read_items_items__get",
}
}
},
}

View File

@@ -15,7 +15,7 @@ from tests.utils import needs_py310
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.dataclasses.{request.param}")
mod = importlib.import_module(f"docs_src.dataclasses_.{request.param}")
client = TestClient(mod.app)
client.headers.clear()

View File

@@ -15,7 +15,7 @@ from tests.utils import needs_py310
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.dataclasses.{request.param}")
mod = importlib.import_module(f"docs_src.dataclasses_.{request.param}")
client = TestClient(mod.app)
client.headers.clear()

View File

@@ -14,7 +14,7 @@ from ...utils import needs_py310
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.dataclasses.{request.param}")
mod = importlib.import_module(f"docs_src.dataclasses_.{request.param}")
client = TestClient(mod.app)
client.headers.clear()

View File

View File

@@ -0,0 +1,64 @@
import importlib
import runpy
import sys
import unittest
import pytest
from fastapi.testclient import TestClient
MOD_NAME = "docs_src.debugging.tutorial001_py39"
@pytest.fixture(name="client")
def get_client():
mod = importlib.import_module(MOD_NAME)
client = TestClient(mod.app)
return client
def test_uvicorn_run_is_not_called_on_import():
if sys.modules.get(MOD_NAME):
del sys.modules[MOD_NAME] # pragma: no cover
with unittest.mock.patch("uvicorn.run") as uvicorn_run_mock:
importlib.import_module(MOD_NAME)
uvicorn_run_mock.assert_not_called()
def test_get_root(client: TestClient):
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"hello world": "ba"}
def test_uvicorn_run_called_when_run_as_main(): # Just for coverage
if sys.modules.get(MOD_NAME):
del sys.modules[MOD_NAME]
with unittest.mock.patch("uvicorn.run") as uvicorn_run_mock:
runpy.run_module(MOD_NAME, run_name="__main__")
uvicorn_run_mock.assert_called_once_with(
unittest.mock.ANY, host="0.0.0.0", port=8000
)
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
"get": {
"summary": "Root",
"operationId": "root__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
},
}
}
},
}

View File

@@ -1,7 +1,6 @@
import importlib
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
from ...utils import needs_py310
@@ -14,6 +13,8 @@ from ...utils import needs_py310
pytest.param("tutorial001_py310", marks=needs_py310),
pytest.param("tutorial001_an_py39"),
pytest.param("tutorial001_an_py310", marks=needs_py310),
pytest.param("tutorial001_02_an_py39"),
pytest.param("tutorial001_02_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
@@ -69,16 +70,10 @@ def test_openapi_schema(client: TestClient):
"parameters": [
{
"required": False,
"schema": IsDict(
{
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Q",
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Q", "type": "string"}
),
"schema": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Q",
},
"name": "q",
"in": "query",
},
@@ -128,16 +123,10 @@ def test_openapi_schema(client: TestClient):
"parameters": [
{
"required": False,
"schema": IsDict(
{
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Q",
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Q", "type": "string"}
),
"schema": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Q",
},
"name": "q",
"in": "query",
},

View File

@@ -1,7 +1,6 @@
import importlib
import pytest
from dirty_equals import IsDict
from fastapi.testclient import TestClient
from ...utils import needs_py310
@@ -10,6 +9,14 @@ from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=needs_py310),
pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
pytest.param("tutorial003_an_py39"),
pytest.param("tutorial003_an_py310", marks=needs_py310),
pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
pytest.param("tutorial004_an_py39"),
@@ -107,16 +114,10 @@ def test_openapi_schema(client: TestClient):
"parameters": [
{
"required": False,
"schema": IsDict(
{
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Q",
}
)
| IsDict(
# TODO: remove when deprecating Pydantic v1
{"title": "Q", "type": "string"}
),
"schema": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Q",
},
"name": "q",
"in": "query",
},

View File

@@ -0,0 +1,139 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial005_py39"),
pytest.param("tutorial005_py310", marks=needs_py310),
pytest.param("tutorial005_an_py39"),
pytest.param("tutorial005_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.dependencies.{request.param}")
client = TestClient(mod.app)
return client
@pytest.mark.parametrize(
"path,cookie,expected_status,expected_response",
[
(
"/items",
"from_cookie",
200,
{"q_or_cookie": "from_cookie"},
),
(
"/items?q=foo",
"from_cookie",
200,
{"q_or_cookie": "foo"},
),
(
"/items",
None,
200,
{"q_or_cookie": None},
),
],
)
def test_get(path, cookie, expected_status, expected_response, client: TestClient):
if cookie is not None:
client.cookies.set("last_query", cookie)
else:
client.cookies.clear()
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Query",
"operationId": "read_query_items__get",
"parameters": [
{
"required": False,
"schema": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Q",
},
"name": "q",
"in": "query",
},
{
"required": False,
"schema": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Last Query",
},
"name": "last_query",
"in": "cookie",
},
],
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,24 @@
import asyncio
from contextlib import asynccontextmanager
from unittest.mock import Mock, patch
from docs_src.dependencies.tutorial007_py39 import get_db
def test_get_db(): # Just for coverage
async def test_async_gen():
cm = asynccontextmanager(get_db)
async with cm() as db_session:
return db_session
dbsession_moock = Mock()
with patch(
"docs_src.dependencies.tutorial007_py39.DBSession",
return_value=dbsession_moock,
create=True,
):
value = asyncio.run(test_async_gen())
assert value is dbsession_moock
dbsession_moock.close.assert_called_once()

View File

@@ -0,0 +1,58 @@
import importlib
from types import ModuleType
from typing import Annotated, Any
from unittest.mock import Mock, patch
import pytest
from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient
@pytest.fixture(
name="module",
params=[
"tutorial008_py39",
# Fails with `NameError: name 'DepA' is not defined`
pytest.param("tutorial008_an_py39", marks=pytest.mark.xfail),
],
)
def get_module(request: pytest.FixtureRequest):
mod_name = f"docs_src.dependencies.{request.param}"
mod = importlib.import_module(mod_name)
return mod
def test_get_db(module: ModuleType):
app = FastAPI()
@app.get("/")
def read_root(c: Annotated[Any, Depends(module.dependency_c)]):
return {"c": str(c)}
client = TestClient(app)
a_mock = Mock()
b_mock = Mock()
c_mock = Mock()
with (
patch(
f"{module.__name__}.generate_dep_a",
return_value=a_mock,
create=True,
),
patch(
f"{module.__name__}.generate_dep_b",
return_value=b_mock,
create=True,
),
patch(
f"{module.__name__}.generate_dep_c",
return_value=c_mock,
create=True,
),
):
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"c": str(c_mock)}

View File

@@ -0,0 +1,29 @@
from typing import Annotated, Any
from unittest.mock import Mock, patch
from fastapi import Depends, FastAPI
from fastapi.testclient import TestClient
from docs_src.dependencies.tutorial010_py39 import get_db
def test_get_db():
app = FastAPI()
@app.get("/")
def read_root(c: Annotated[Any, Depends(get_db)]):
return {"c": str(c)}
client = TestClient(app)
dbsession_mock = Mock()
with patch(
"docs_src.dependencies.tutorial010_py39.DBSession",
return_value=dbsession_mock,
create=True,
):
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"c": str(dbsession_mock)}

View File

@@ -0,0 +1,120 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
"tutorial011_py39",
pytest.param("tutorial011_an_py39"),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.dependencies.{request.param}")
client = TestClient(mod.app)
return client
@pytest.mark.parametrize(
"path,expected_status,expected_response",
[
(
"/query-checker/",
200,
{"fixed_content_in_query": False},
),
(
"/query-checker/?q=qwerty",
200,
{"fixed_content_in_query": False},
),
(
"/query-checker/?q=foobar",
200,
{"fixed_content_in_query": True},
),
],
)
def test_get(path, expected_status, expected_response, client: TestClient):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/query-checker/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Query Check",
"operationId": "read_query_check_query_checker__get",
"parameters": [
{
"required": False,
"schema": {
"type": "string",
"default": "",
"title": "Q",
},
"name": "q",
"in": "query",
},
],
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

View File

@@ -0,0 +1,208 @@
import importlib
from types import ModuleType
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="mod",
params=[
pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
def get_module(request: pytest.FixtureRequest):
module = importlib.import_module(f"docs_src.encoder.{request.param}")
return module
@pytest.fixture(name="client")
def get_client(mod: ModuleType):
client = TestClient(mod.app)
return client
def test_put(client: TestClient, mod: ModuleType):
fake_db = mod.fake_db
response = client.put(
"/items/123",
json={
"title": "Foo",
"timestamp": "2023-01-01T12:00:00",
"description": "An optional description",
},
)
assert response.status_code == 200
assert "123" in fake_db
assert fake_db["123"] == {
"title": "Foo",
"timestamp": "2023-01-01T12:00:00",
"description": "An optional description",
}
def test_put_invalid_data(client: TestClient, mod: ModuleType):
fake_db = mod.fake_db
response = client.put(
"/items/345",
json={
"title": "Foo",
"timestamp": "not a date",
},
)
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"loc": ["body", "timestamp"],
"msg": "Input should be a valid datetime or date, invalid character in year",
"type": "datetime_from_date_parsing",
"input": "not a date",
"ctx": {"error": "invalid character in year"},
}
]
}
assert "345" not in fake_db
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{id}": {
"put": {
"operationId": "update_item_items__id__put",
"parameters": [
{
"in": "path",
"name": "id",
"required": True,
"schema": {
"title": "Id",
"type": "string",
},
},
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Item",
},
},
},
"required": True,
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {},
},
},
"description": "Successful Response",
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
"summary": "Update Item",
},
},
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"Item": {
"properties": {
"description": {
"anyOf": [
{
"type": "string",
},
{
"type": "null",
},
],
"title": "Description",
},
"timestamp": {
"format": "date-time",
"title": "Timestamp",
"type": "string",
},
"title": {
"title": "Title",
"type": "string",
},
},
"required": [
"title",
"timestamp",
],
"title": "Item",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,156 @@
import importlib
import pytest
from dirty_equals import IsList
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.extra_models.{request.param}")
client = TestClient(mod.app)
return client
def test_post(client: TestClient):
response = client.post(
"/user/",
json={
"username": "johndoe",
"password": "secret",
"email": "johndoe@example.com",
"full_name": "John Doe",
},
)
assert response.status_code == 200, response.text
assert response.json() == {
"username": "johndoe",
"email": "johndoe@example.com",
"full_name": "John Doe",
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/user/": {
"post": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserOut",
}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Create User",
"operationId": "create_user_user__post",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/UserIn"}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"UserIn": {
"title": "UserIn",
"required": IsList(
"username", "password", "email", check_order=False
),
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
"password": {"title": "Password", "type": "string"},
"email": {
"title": "Email",
"type": "string",
"format": "email",
},
"full_name": {
"title": "Full Name",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
},
},
"UserOut": {
"title": "UserOut",
"required": ["username", "email"],
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
"email": {
"title": "Email",
"type": "string",
"format": "email",
},
"full_name": {
"title": "Full Name",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -1,9 +1,20 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from docs_src.first_steps.tutorial001_py39 import app
client = TestClient(app)
@pytest.fixture(
name="client",
params=[
"tutorial001_py39",
"tutorial003_py39",
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.first_steps.{request.param}")
client = TestClient(mod.app)
return client
@pytest.mark.parametrize(
@@ -13,13 +24,13 @@ client = TestClient(app)
("/nonexistent", 404, {"detail": "Not Found"}),
],
)
def test_get_path(path, expected_status, expected_response):
def test_get_path(client: TestClient, path, expected_status, expected_response):
response = client.get(path)
assert response.status_code == expected_status
assert response.json() == expected_response
def test_openapi_schema():
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {

View File

@@ -0,0 +1,142 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial001_py39"),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.generate_clients.{request.param}")
client = TestClient(mod.app)
return client
def test_post_items(client: TestClient):
response = client.post("/items/", json={"name": "Foo", "price": 5})
assert response.status_code == 200, response.text
assert response.json() == {"message": "item received"}
def test_get_items(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [
{"name": "Plumbus", "price": 3},
{"name": "Portal Gun", "price": 9001},
]
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"summary": "Get Items",
"operationId": "get_items_items__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"title": "Response Get Items Items Get",
"type": "array",
"items": {"$ref": "#/components/schemas/Item"},
}
}
},
}
},
},
"post": {
"summary": "Create Item",
"operationId": "create_item_items__post",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResponseMessage"
}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
},
},
},
"components": {
"schemas": {
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
"Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"price": {"title": "Price", "type": "number"},
},
},
"ResponseMessage": {
"title": "ResponseMessage",
"required": ["message"],
"type": "object",
"properties": {"message": {"title": "Message", "type": "string"}},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
}
},
}

View File

@@ -0,0 +1,187 @@
from fastapi.testclient import TestClient
from docs_src.generate_clients.tutorial002_py39 import app
client = TestClient(app)
def test_post_items():
response = client.post("/items/", json={"name": "Foo", "price": 5})
assert response.status_code == 200, response.text
assert response.json() == {"message": "Item received"}
def test_post_users():
response = client.post(
"/users/", json={"username": "Foo", "email": "foo@example.com"}
)
assert response.status_code == 200, response.text
assert response.json() == {"message": "User received"}
def test_get_items():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [
{"name": "Plumbus", "price": 3},
{"name": "Portal Gun", "price": 9001},
]
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"tags": ["items"],
"summary": "Get Items",
"operationId": "get_items_items__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"title": "Response Get Items Items Get",
"type": "array",
"items": {"$ref": "#/components/schemas/Item"},
}
}
},
}
},
},
"post": {
"tags": ["items"],
"summary": "Create Item",
"operationId": "create_item_items__post",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResponseMessage"
}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
},
},
"/users/": {
"post": {
"tags": ["users"],
"summary": "Create User",
"operationId": "create_user_users__post",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/User"}
}
},
"required": True,
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResponseMessage"
}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
}
},
},
"components": {
"schemas": {
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
"Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"price": {"title": "Price", "type": "number"},
},
},
"ResponseMessage": {
"title": "ResponseMessage",
"required": ["message"],
"type": "object",
"properties": {"message": {"title": "Message", "type": "string"}},
},
"User": {
"title": "User",
"required": ["username", "email"],
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
"email": {"title": "Email", "type": "string"},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
}
},
}

View File

@@ -0,0 +1,230 @@
import importlib
import json
import pathlib
from unittest.mock import patch
from docs_src.generate_clients import tutorial003_py39
def test_remove_tags(tmp_path: pathlib.Path):
tmp_file = tmp_path / "openapi.json"
openapi_json = tutorial003_py39.app.openapi()
tmp_file.write_text(json.dumps(openapi_json))
with patch("pathlib.Path", return_value=tmp_file):
importlib.import_module("docs_src.generate_clients.tutorial004_py39")
modified_openapi = json.loads(tmp_file.read_text())
assert modified_openapi == {
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"Item": {
"properties": {
"name": {
"title": "Name",
"type": "string",
},
"price": {
"title": "Price",
"type": "number",
},
},
"required": [
"name",
"price",
],
"title": "Item",
"type": "object",
},
"ResponseMessage": {
"properties": {
"message": {
"title": "Message",
"type": "string",
},
},
"required": [
"message",
],
"title": "ResponseMessage",
"type": "object",
},
"User": {
"properties": {
"email": {
"title": "Email",
"type": "string",
},
"username": {
"title": "Username",
"type": "string",
},
},
"required": [
"username",
"email",
],
"title": "User",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
"info": {
"title": "FastAPI",
"version": "0.1.0",
},
"openapi": "3.1.0",
"paths": {
"/items/": {
"get": {
"operationId": "get_items",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/Item",
},
"title": "Response Items-Get Items",
"type": "array",
},
},
},
"description": "Successful Response",
},
},
"summary": "Get Items",
"tags": [
"items",
],
},
"post": {
"operationId": "create_item",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Item",
},
},
},
"required": True,
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResponseMessage",
},
},
},
"description": "Successful Response",
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
"summary": "Create Item",
"tags": [
"items",
],
},
},
"/users/": {
"post": {
"operationId": "create_user",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User",
},
},
},
"required": True,
},
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResponseMessage",
},
},
},
"description": "Successful Response",
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
"summary": "Create User",
"tags": [
"users",
],
},
},
},
}

View File

View File

@@ -0,0 +1,70 @@
import warnings
import pytest
from starlette.testclient import TestClient
warnings.filterwarnings(
"ignore",
message=r"The 'lia' package has been renamed to 'cross_web'\..*",
category=DeprecationWarning,
)
from docs_src.graphql_.tutorial001_py39 import app # noqa: E402
@pytest.fixture(name="client")
def get_client() -> TestClient:
return TestClient(app)
def test_query(client: TestClient):
response = client.post("/graphql", json={"query": "{ user { name, age } }"})
assert response.status_code == 200
assert response.json() == {"data": {"user": {"name": "Patrick", "age": 100}}}
def test_openapi(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
"info": {
"title": "FastAPI",
"version": "0.1.0",
},
"openapi": "3.1.0",
"paths": {
"/graphql": {
"get": {
"operationId": "handle_http_get_graphql_get",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {},
},
},
"description": "The GraphiQL integrated development environment.",
},
"404": {
"description": "Not found if GraphiQL or query via GET are not enabled.",
},
},
"summary": "Handle Http Get",
},
"post": {
"operationId": "handle_http_post_graphql_post",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {},
},
},
"description": "Successful Response",
},
},
"summary": "Handle Http Post",
},
},
},
}

View File

@@ -1,45 +1,41 @@
from fastapi.testclient import TestClient
from docs_src.custom_response.tutorial004_py39 import app
from docs_src.metadata.tutorial002_py39 import app
client = TestClient(app)
html_contents = """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
def test_get_custom_response():
def test_items():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.text == html_contents
assert response.json() == [{"name": "Foo"}]
def test_get_openapi_json_default_url():
response = client.get("/openapi.json")
assert response.status_code == 404, response.text
def test_openapi_schema():
response = client.get("/openapi.json")
response = client.get("/api/v1/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"info": {
"title": "FastAPI",
"version": "0.1.0",
},
"paths": {
"/items/": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"text/html": {"schema": {"type": "string"}}},
"content": {"application/json": {"schema": {}}},
}
},
"summary": "Read Items",
"operationId": "read_items_items__get",
}
}
},

View File

@@ -0,0 +1,53 @@
from fastapi.testclient import TestClient
from docs_src.metadata.tutorial003_py39 import app
client = TestClient(app)
def test_items():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [{"name": "Foo"}]
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0",
},
"paths": {
"/items/": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
}
}
},
}
def test_swagger_ui_default_url():
response = client.get("/docs")
assert response.status_code == 404, response.text
def test_swagger_ui_custom_url():
response = client.get("/documentation")
assert response.status_code == 200, response.text
assert "<title>FastAPI - Swagger UI</title>" in response.text
def test_redoc_ui_default_url():
response = client.get("/redoc")
assert response.status_code == 404, response.text

View File

View File

@@ -0,0 +1,24 @@
from fastapi.testclient import TestClient
from docs_src.middleware.tutorial001_py39 import app
client = TestClient(app)
def test_response_headers():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert "X-Process-Time" in response.headers
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0",
},
"paths": {},
}

View File

@@ -0,0 +1,186 @@
import importlib
import pytest
from dirty_equals import IsList
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest) -> TestClient:
mod = importlib.import_module(
f"docs_src.path_operation_configuration.{request.param}"
)
return TestClient(mod.app)
def test_post_items(client: TestClient):
response = client.post(
"/items/",
json={
"name": "Foo",
"description": "Item description",
"price": 42.0,
"tax": 3.2,
"tags": ["bar", "baz"],
},
)
assert response.status_code == 201, response.text
assert response.json() == {
"name": "Foo",
"description": "Item description",
"price": 42.0,
"tax": 3.2,
"tags": IsList("bar", "baz", check_order=False),
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"post": {
"summary": "Create Item",
"operationId": "create_item_items__post",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
"responses": {
"201": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
},
},
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"Item": {
"properties": {
"description": {
"anyOf": [
{
"type": "string",
},
{
"type": "null",
},
],
"title": "Description",
},
"name": {
"title": "Name",
"type": "string",
},
"price": {
"title": "Price",
"type": "number",
},
"tags": {
"default": [],
"items": {
"type": "string",
},
"title": "Tags",
"type": "array",
"uniqueItems": True,
},
"tax": {
"anyOf": [
{
"type": "number",
},
{
"type": "null",
},
],
"title": "Tax",
},
},
"required": [
"name",
"price",
],
"title": "Item",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,223 @@
import importlib
import pytest
from dirty_equals import IsList
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest) -> TestClient:
mod = importlib.import_module(
f"docs_src.path_operation_configuration.{request.param}"
)
return TestClient(mod.app)
def test_post_items(client: TestClient):
response = client.post(
"/items/",
json={
"name": "Foo",
"description": "Item description",
"price": 42.0,
"tax": 3.2,
"tags": ["bar", "baz"],
},
)
assert response.status_code == 200, response.text
assert response.json() == {
"name": "Foo",
"description": "Item description",
"price": 42.0,
"tax": 3.2,
"tags": IsList("bar", "baz", check_order=False),
}
def test_get_items(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [{"name": "Foo", "price": 42}]
def test_get_users(client: TestClient):
response = client.get("/users/")
assert response.status_code == 200, response.text
assert response.json() == [{"username": "johndoe"}]
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"tags": ["items"],
"summary": "Read Items",
"operationId": "read_items_items__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
},
"post": {
"tags": ["items"],
"summary": "Create Item",
"operationId": "create_item_items__post",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
},
},
"/users/": {
"get": {
"tags": ["users"],
"summary": "Read Users",
"operationId": "read_users_users__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
}
},
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"Item": {
"properties": {
"description": {
"anyOf": [
{
"type": "string",
},
{
"type": "null",
},
],
"title": "Description",
},
"name": {
"title": "Name",
"type": "string",
},
"price": {
"title": "Price",
"type": "number",
},
"tags": {
"default": [],
"items": {
"type": "string",
},
"title": "Tags",
"type": "array",
"uniqueItems": True,
},
"tax": {
"anyOf": [
{
"type": "number",
},
{
"type": "null",
},
],
"title": "Tax",
},
},
"required": [
"name",
"price",
],
"title": "Item",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,208 @@
import importlib
from textwrap import dedent
import pytest
from dirty_equals import IsList
from fastapi.testclient import TestClient
from ...utils import needs_py310
DESCRIPTIONS = {
"tutorial003": "Create an item with all the information, name, description, price, tax and a set of unique tags",
"tutorial004": dedent("""
Create an item with all the information:
- **name**: each item must have a name
- **description**: a long description
- **price**: required
- **tax**: if the item doesn't have tax, you can omit this
- **tags**: a set of unique tag strings for this item
""").strip(),
}
@pytest.fixture(
name="mod_name",
params=[
pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
],
)
def get_mod_name(request: pytest.FixtureRequest) -> str:
return request.param
@pytest.fixture(name="client")
def get_client(mod_name: str) -> TestClient:
mod = importlib.import_module(f"docs_src.path_operation_configuration.{mod_name}")
return TestClient(mod.app)
def test_post_items(client: TestClient):
response = client.post(
"/items/",
json={
"name": "Foo",
"description": "Item description",
"price": 42.0,
"tax": 3.2,
"tags": ["bar", "baz"],
},
)
assert response.status_code == 200, response.text
assert response.json() == {
"name": "Foo",
"description": "Item description",
"price": 42.0,
"tax": 3.2,
"tags": IsList("bar", "baz", check_order=False),
}
def test_openapi_schema(client: TestClient, mod_name: str):
mod_name = mod_name[:11]
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"post": {
"summary": "Create an item",
"description": DESCRIPTIONS[mod_name],
"operationId": "create_item_items__post",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
"required": True,
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
},
},
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"Item": {
"properties": {
"description": {
"anyOf": [
{
"type": "string",
},
{
"type": "null",
},
],
"title": "Description",
},
"name": {
"title": "Name",
"type": "string",
},
"price": {
"title": "Price",
"type": "number",
},
"tags": {
"default": [],
"items": {
"type": "string",
},
"title": "Tags",
"type": "array",
"uniqueItems": True,
},
"tax": {
"anyOf": [
{
"type": "number",
},
{
"type": "null",
},
],
"title": "Tax",
},
},
"required": [
"name",
"price",
],
"title": "Item",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,116 @@
import pytest
from fastapi.testclient import TestClient
from docs_src.path_params.tutorial001_py39 import app
client = TestClient(app)
@pytest.mark.parametrize(
("item_id", "expected_response"),
[
(1, {"item_id": "1"}),
("alice", {"item_id": "alice"}),
],
)
def test_get_items(item_id, expected_response):
response = client.get(f"/items/{item_id}")
assert response.status_code == 200, response.text
assert response.json() == expected_response
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"get": {
"operationId": "read_item_items__item_id__get",
"parameters": [
{
"in": "path",
"name": "item_id",
"required": True,
"schema": {
"title": "Item Id",
},
},
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {},
},
},
"description": "Successful Response",
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
"summary": "Read Item",
},
},
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,124 @@
from fastapi.testclient import TestClient
from docs_src.path_params.tutorial002_py39 import app
client = TestClient(app)
def test_get_items():
response = client.get("/items/1")
assert response.status_code == 200, response.text
assert response.json() == {"item_id": 1}
def test_get_items_invalid_id():
response = client.get("/items/item1")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"input": "item1",
"loc": ["path", "item_id"],
"msg": "Input should be a valid integer, unable to parse string as an integer",
"type": "int_parsing",
}
]
}
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"get": {
"operationId": "read_item_items__item_id__get",
"parameters": [
{
"in": "path",
"name": "item_id",
"required": True,
"schema": {
"title": "Item Id",
"type": "integer",
},
},
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {},
},
},
"description": "Successful Response",
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
"summary": "Read Item",
},
},
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,133 @@
import pytest
from fastapi.testclient import TestClient
from docs_src.path_params.tutorial003_py39 import app
client = TestClient(app)
@pytest.mark.parametrize(
("user_id", "expected_response"),
[
("me", {"user_id": "the current user"}),
("alice", {"user_id": "alice"}),
],
)
def test_get_users(user_id: str, expected_response: dict):
response = client.get(f"/users/{user_id}")
assert response.status_code == 200, response.text
assert response.json() == expected_response
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
"get": {
"operationId": "read_user_me_users_me_get",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {},
},
},
"description": "Successful Response",
},
},
"summary": "Read User Me",
},
},
"/users/{user_id}": {
"get": {
"operationId": "read_user_users__user_id__get",
"parameters": [
{
"in": "path",
"name": "user_id",
"required": True,
"schema": {
"title": "User Id",
"type": "string",
},
},
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {},
},
},
"description": "Successful Response",
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
"summary": "Read User",
},
},
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,44 @@
import asyncio
from fastapi.testclient import TestClient
from docs_src.path_params.tutorial003b_py39 import app, read_users2
client = TestClient(app)
def test_get_users():
response = client.get("/users")
assert response.status_code == 200, response.text
assert response.json() == ["Rick", "Morty"]
def test_read_users2(): # Just for coverage
assert asyncio.run(read_users2()) == ["Bean", "Elfo"]
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users": {
"get": {
"operationId": "read_users2_users_get",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {},
},
},
"description": "Successful Response",
},
},
"summary": "Read Users2",
},
},
},
}

View File

@@ -0,0 +1,164 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
pytest.param("tutorial001_an_py39"),
pytest.param("tutorial001_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest) -> TestClient:
mod = importlib.import_module(
f"docs_src.path_params_numeric_validations.{request.param}"
)
return TestClient(mod.app)
@pytest.mark.parametrize(
"path,expected_response",
[
("/items/42", {"item_id": 42}),
("/items/123?item-query=somequery", {"item_id": 123, "q": "somequery"}),
],
)
def test_read_items(client: TestClient, path, expected_response):
response = client.get(path)
assert response.status_code == 200, response.text
assert response.json() == expected_response
def test_read_items_invalid_item_id(client: TestClient):
response = client.get("/items/invalid_id")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["path", "item_id"],
"input": "invalid_id",
"msg": "Input should be a valid integer, unable to parse string as an integer",
"type": "int_parsing",
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__item_id__get",
"parameters": [
{
"required": True,
"schema": {
"title": "The ID of the item to get",
"type": "integer",
},
"name": "item_id",
"in": "path",
},
{
"required": False,
"schema": {
"anyOf": [
{
"type": "string",
},
{
"type": "null",
},
],
"title": "Item-Query",
},
"name": "item-query",
"in": "query",
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {},
}
},
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,170 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_an_py39"),
pytest.param("tutorial003_py39"),
pytest.param("tutorial003_an_py39"),
],
)
def get_client(request: pytest.FixtureRequest) -> TestClient:
mod = importlib.import_module(
f"docs_src.path_params_numeric_validations.{request.param}"
)
return TestClient(mod.app)
@pytest.mark.parametrize(
"path,expected_response",
[
("/items/42?q=", {"item_id": 42}),
("/items/123?q=somequery", {"item_id": 123, "q": "somequery"}),
],
)
def test_read_items(client: TestClient, path, expected_response):
response = client.get(path)
assert response.status_code == 200, response.text
assert response.json() == expected_response
def test_read_items_invalid_item_id(client: TestClient):
response = client.get("/items/invalid_id?q=somequery")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["path", "item_id"],
"input": "invalid_id",
"msg": "Input should be a valid integer, unable to parse string as an integer",
"type": "int_parsing",
}
]
}
def test_read_items_missing_q(client: TestClient):
response = client.get("/items/42")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["query", "q"],
"input": None,
"msg": "Field required",
"type": "missing",
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__item_id__get",
"parameters": [
{
"required": True,
"schema": {
"title": "The ID of the item to get",
"type": "integer",
},
"name": "item_id",
"in": "path",
},
{
"required": True,
"schema": {
"type": "string",
"title": "Q",
},
"name": "q",
"in": "query",
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {},
}
},
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,185 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial004_py39"),
pytest.param("tutorial004_an_py39"),
],
)
def get_client(request: pytest.FixtureRequest) -> TestClient:
mod = importlib.import_module(
f"docs_src.path_params_numeric_validations.{request.param}"
)
return TestClient(mod.app)
@pytest.mark.parametrize(
"path,expected_response",
[
("/items/42?q=", {"item_id": 42}),
("/items/1?q=somequery", {"item_id": 1, "q": "somequery"}),
],
)
def test_read_items(client: TestClient, path, expected_response):
response = client.get(path)
assert response.status_code == 200, response.text
assert response.json() == expected_response
def test_read_items_non_int_item_id(client: TestClient):
response = client.get("/items/invalid_id?q=somequery")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["path", "item_id"],
"input": "invalid_id",
"msg": "Input should be a valid integer, unable to parse string as an integer",
"type": "int_parsing",
}
]
}
def test_read_items_item_id_less_than_one(client: TestClient):
response = client.get("/items/0?q=somequery")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["path", "item_id"],
"input": "0",
"msg": "Input should be greater than or equal to 1",
"type": "greater_than_equal",
"ctx": {"ge": 1},
}
]
}
def test_read_items_missing_q(client: TestClient):
response = client.get("/items/42")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["query", "q"],
"input": None,
"msg": "Field required",
"type": "missing",
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__item_id__get",
"parameters": [
{
"required": True,
"schema": {
"title": "The ID of the item to get",
"type": "integer",
"minimum": 1,
},
"name": "item_id",
"in": "path",
},
{
"required": True,
"schema": {
"type": "string",
"title": "Q",
},
"name": "q",
"in": "query",
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {},
}
},
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,202 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial005_py39"),
pytest.param("tutorial005_an_py39"),
],
)
def get_client(request: pytest.FixtureRequest) -> TestClient:
mod = importlib.import_module(
f"docs_src.path_params_numeric_validations.{request.param}"
)
return TestClient(mod.app)
@pytest.mark.parametrize(
"path,expected_response",
[
("/items/1?q=", {"item_id": 1}),
("/items/1000?q=somequery", {"item_id": 1000, "q": "somequery"}),
],
)
def test_read_items(client: TestClient, path, expected_response):
response = client.get(path)
assert response.status_code == 200, response.text
assert response.json() == expected_response
def test_read_items_non_int_item_id(client: TestClient):
response = client.get("/items/invalid_id?q=somequery")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["path", "item_id"],
"input": "invalid_id",
"msg": "Input should be a valid integer, unable to parse string as an integer",
"type": "int_parsing",
}
]
}
def test_read_items_item_id_less_than_one(client: TestClient):
response = client.get("/items/0?q=somequery")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["path", "item_id"],
"input": "0",
"msg": "Input should be greater than 0",
"type": "greater_than",
"ctx": {"gt": 0},
}
]
}
def test_read_items_item_id_greater_than_one_thousand(client: TestClient):
response = client.get("/items/1001?q=somequery")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["path", "item_id"],
"input": "1001",
"msg": "Input should be less than or equal to 1000",
"type": "less_than_equal",
"ctx": {"le": 1000},
}
]
}
def test_read_items_missing_q(client: TestClient):
response = client.get("/items/42")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["query", "q"],
"input": None,
"msg": "Field required",
"type": "missing",
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__item_id__get",
"parameters": [
{
"required": True,
"schema": {
"title": "The ID of the item to get",
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 1000,
},
"name": "item_id",
"in": "path",
},
{
"required": True,
"schema": {
"type": "string",
"title": "Q",
},
"name": "q",
"in": "query",
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {},
}
},
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

@@ -0,0 +1,221 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial006_py39"),
pytest.param("tutorial006_an_py39"),
],
)
def get_client(request: pytest.FixtureRequest) -> TestClient:
mod = importlib.import_module(
f"docs_src.path_params_numeric_validations.{request.param}"
)
return TestClient(mod.app)
@pytest.mark.parametrize(
"path,expected_response",
[
(
"/items/0?q=&size=0.1",
{"item_id": 0, "size": 0.1},
),
(
"/items/1000?q=somequery&size=10.4",
{"item_id": 1000, "q": "somequery", "size": 10.4},
),
],
)
def test_read_items(client: TestClient, path, expected_response):
response = client.get(path)
assert response.status_code == 200, response.text
assert response.json() == expected_response
def test_read_items_item_id_less_than_zero(client: TestClient):
response = client.get("/items/-1?q=somequery&size=5")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["path", "item_id"],
"input": "-1",
"msg": "Input should be greater than or equal to 0",
"type": "greater_than_equal",
"ctx": {"ge": 0},
}
]
}
def test_read_items_item_id_greater_than_one_thousand(client: TestClient):
response = client.get("/items/1001?q=somequery&size=5")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["path", "item_id"],
"input": "1001",
"msg": "Input should be less than or equal to 1000",
"type": "less_than_equal",
"ctx": {"le": 1000},
}
]
}
def test_read_items_size_too_small(client: TestClient):
response = client.get("/items/1?q=somequery&size=0.0")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["query", "size"],
"input": "0.0",
"msg": "Input should be greater than 0",
"type": "greater_than",
"ctx": {"gt": 0.0},
}
]
}
def test_read_items_size_too_large(client: TestClient):
response = client.get("/items/1?q=somequery&size=10.5")
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["query", "size"],
"input": "10.5",
"msg": "Input should be less than 10.5",
"type": "less_than",
"ctx": {"lt": 10.5},
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__item_id__get",
"parameters": [
{
"required": True,
"schema": {
"title": "The ID of the item to get",
"type": "integer",
"minimum": 0,
"maximum": 1000,
},
"name": "item_id",
"in": "path",
},
{
"required": True,
"schema": {
"type": "string",
"title": "Q",
},
"name": "q",
"in": "query",
},
{
"in": "query",
"name": "size",
"required": True,
"schema": {
"exclusiveMaximum": 10.5,
"exclusiveMinimum": 0,
"title": "Size",
"type": "number",
},
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {},
}
},
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError",
},
"title": "Detail",
"type": "array",
},
},
"title": "HTTPValidationError",
"type": "object",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string",
},
{
"type": "integer",
},
],
},
"title": "Location",
"type": "array",
},
"msg": {
"title": "Message",
"type": "string",
},
"type": {
"title": "Error Type",
"type": "string",
},
},
"required": [
"loc",
"msg",
"type",
],
"title": "ValidationError",
"type": "object",
},
},
},
}

View File

View File

@@ -0,0 +1,18 @@
import runpy
from unittest.mock import patch
import pytest
@pytest.mark.parametrize(
"module_name",
[
"tutorial001_py39",
"tutorial002_py39",
],
)
def test_run_module(module_name: str):
with patch("builtins.print") as mock_print:
runpy.run_module(f"docs_src.python_types.{module_name}", run_name="__main__")
mock_print.assert_called_with("John Doe")

View File

@@ -0,0 +1,12 @@
import pytest
from docs_src.python_types.tutorial003_py39 import get_name_with_age
def test_get_name_with_age_pass_int():
with pytest.raises(TypeError):
get_name_with_age("John", 30)
def test_get_name_with_age_pass_str():
assert get_name_with_age("John", "30") == "John is this old: 30"

View File

@@ -0,0 +1,5 @@
from docs_src.python_types.tutorial004_py39 import get_name_with_age
def test_get_name_with_age_pass_int():
assert get_name_with_age("John", 30) == "John is this old: 30"

View File

@@ -0,0 +1,12 @@
from docs_src.python_types.tutorial005_py39 import get_items
def test_get_items():
res = get_items(
"item_a",
"item_b",
"item_c",
"item_d",
"item_e",
)
assert res == ("item_a", "item_b", "item_c", "item_d", "item_e")

View File

@@ -0,0 +1,16 @@
from unittest.mock import patch
from docs_src.python_types.tutorial006_py39 import process_items
def test_process_items():
with patch("builtins.print") as mock_print:
process_items(["item_a", "item_b", "item_c"])
assert mock_print.call_count == 3
call_args = [arg.args for arg in mock_print.call_args_list]
assert call_args == [
("item_a",),
("item_b",),
("item_c",),
]

View File

@@ -0,0 +1,8 @@
from docs_src.python_types.tutorial007_py39 import process_items
def test_process_items():
items_t = (1, 2, "foo")
items_s = {b"a", b"b", b"c"}
assert process_items(items_t, items_s) == (items_t, items_s)

View File

@@ -0,0 +1,17 @@
from unittest.mock import patch
from docs_src.python_types.tutorial008_py39 import process_items
def test_process_items():
with patch("builtins.print") as mock_print:
process_items({"a": 1.0, "b": 2.5})
assert mock_print.call_count == 4
call_args = [arg.args for arg in mock_print.call_args_list]
assert call_args == [
("a",),
(1.0,),
("b",),
(2.5,),
]

View File

@@ -0,0 +1,27 @@
import importlib
from types import ModuleType
from unittest.mock import patch
import pytest
from ...utils import needs_py310
@pytest.fixture(
name="module",
params=[
pytest.param("tutorial008b_py39"),
pytest.param("tutorial008b_py310", marks=needs_py310),
],
)
def get_module(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.python_types.{request.param}")
return mod
def test_process_items(module: ModuleType):
with patch("builtins.print") as mock_print:
module.process_item("a")
assert mock_print.call_count == 1
mock_print.assert_called_with("a")

View File

@@ -0,0 +1,33 @@
import importlib
from types import ModuleType
from unittest.mock import patch
import pytest
from ...utils import needs_py310
@pytest.fixture(
name="module",
params=[
pytest.param("tutorial009_py39"),
pytest.param("tutorial009_py310", marks=needs_py310),
pytest.param("tutorial009b_py39"),
],
)
def get_module(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.python_types.{request.param}")
return mod
def test_say_hi(module: ModuleType):
with patch("builtins.print") as mock_print:
module.say_hi("FastAPI")
module.say_hi()
assert mock_print.call_count == 2
call_args = [arg.args for arg in mock_print.call_args_list]
assert call_args == [
("Hey FastAPI!",),
("Hello World",),
]

View File

@@ -0,0 +1,33 @@
import importlib
import re
from types import ModuleType
from unittest.mock import patch
import pytest
from ...utils import needs_py310
@pytest.fixture(
name="module",
params=[
pytest.param("tutorial009c_py39"),
pytest.param("tutorial009c_py310", marks=needs_py310),
],
)
def get_module(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.python_types.{request.param}")
return mod
def test_say_hi(module: ModuleType):
with patch("builtins.print") as mock_print:
module.say_hi("FastAPI")
mock_print.assert_called_once_with("Hey FastAPI!")
with pytest.raises(
TypeError,
match=re.escape("say_hi() missing 1 required positional argument: 'name'"),
):
module.say_hi()

View File

@@ -0,0 +1,5 @@
from docs_src.python_types.tutorial010_py39 import Person, get_person_name
def test_get_person_name():
assert get_person_name(Person("John Doe")) == "John Doe"

View File

@@ -0,0 +1,25 @@
import runpy
from unittest.mock import patch
import pytest
from ...utils import needs_py310
@pytest.mark.parametrize(
"module_name",
[
pytest.param("tutorial011_py39"),
pytest.param("tutorial011_py310", marks=needs_py310),
],
)
def test_run_module(module_name: str):
with patch("builtins.print") as mock_print:
runpy.run_module(f"docs_src.python_types.{module_name}", run_name="__main__")
assert mock_print.call_count == 2
call_args = [str(arg.args[0]) for arg in mock_print.call_args_list]
assert call_args == [
"id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]",
"123",
]

View File

@@ -0,0 +1,7 @@
from docs_src.python_types.tutorial012_py39 import User
def test_user():
user = User(name="John Doe", age=30)
assert user.name == "John Doe"
assert user.age == 30

View File

@@ -0,0 +1,5 @@
from docs_src.python_types.tutorial013_py39 import say_hello
def test_say_hello():
assert say_hello("FastAPI") == "Hello FastAPI"

View File

@@ -0,0 +1,126 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial001_py39"),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.query_params.{request.param}")
client = TestClient(mod.app)
return client
@pytest.mark.parametrize(
("path", "expected_json"),
[
(
"/items/",
[{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}],
),
(
"/items/?skip=1",
[{"item_name": "Bar"}, {"item_name": "Baz"}],
),
(
"/items/?skip=1&limit=1",
[{"item_name": "Bar"}],
),
],
)
def test_read_user_item(client: TestClient, path, expected_json):
response = client.get(path)
assert response.status_code == 200
assert response.json() == expected_json
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"summary": "Read Item",
"operationId": "read_item_items__get",
"parameters": [
{
"required": False,
"schema": {
"title": "Skip",
"type": "integer",
"default": 0,
},
"name": "skip",
"in": "query",
},
{
"required": False,
"schema": {
"title": "Limit",
"type": "integer",
"default": 10,
},
"name": "limit",
"in": "query",
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,127 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.query_params.{request.param}")
client = TestClient(mod.app)
return client
@pytest.mark.parametrize(
("path", "expected_json"),
[
(
"/items/foo",
{"item_id": "foo"},
),
(
"/items/bar?q=somequery",
{"item_id": "bar", "q": "somequery"},
),
],
)
def test_read_user_item(client: TestClient, path, expected_json):
response = client.get(path)
assert response.status_code == 200
assert response.json() == expected_json
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"get": {
"summary": "Read Item",
"operationId": "read_item_items__item_id__get",
"parameters": [
{
"required": True,
"schema": {"title": "Item Id", "type": "string"},
"name": "item_id",
"in": "path",
},
{
"required": False,
"schema": {
"title": "Q",
"anyOf": [
{
"type": "string",
},
{
"type": "null",
},
],
},
"name": "q",
"in": "query",
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,148 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.query_params.{request.param}")
client = TestClient(mod.app)
return client
@pytest.mark.parametrize(
("path", "expected_json"),
[
(
"/items/foo",
{
"item_id": "foo",
"description": "This is an amazing item that has a long description",
},
),
(
"/items/bar?q=somequery",
{
"item_id": "bar",
"q": "somequery",
"description": "This is an amazing item that has a long description",
},
),
(
"/items/baz?short=true",
{"item_id": "baz"},
),
],
)
def test_read_user_item(client: TestClient, path, expected_json):
response = client.get(path)
assert response.status_code == 200
assert response.json() == expected_json
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"get": {
"summary": "Read Item",
"operationId": "read_item_items__item_id__get",
"parameters": [
{
"required": True,
"schema": {"title": "Item Id", "type": "string"},
"name": "item_id",
"in": "path",
},
{
"required": False,
"schema": {
"title": "Q",
"anyOf": [
{
"type": "string",
},
{
"type": "null",
},
],
},
"name": "q",
"in": "query",
},
{
"required": False,
"schema": {
"title": "Short",
"type": "boolean",
"default": False,
},
"name": "short",
"in": "query",
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,156 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.query_params.{request.param}")
client = TestClient(mod.app)
return client
@pytest.mark.parametrize(
("path", "expected_json"),
[
(
"/users/123/items/foo",
{
"item_id": "foo",
"owner_id": 123,
"description": "This is an amazing item that has a long description",
},
),
(
"/users/1/items/bar?q=somequery",
{
"item_id": "bar",
"owner_id": 1,
"q": "somequery",
"description": "This is an amazing item that has a long description",
},
),
(
"/users/42/items/baz?short=true",
{"item_id": "baz", "owner_id": 42},
),
],
)
def test_read_user_item(client: TestClient, path, expected_json):
response = client.get(path)
assert response.status_code == 200
assert response.json() == expected_json
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/{user_id}/items/{item_id}": {
"get": {
"summary": "Read User Item",
"operationId": "read_user_item_users__user_id__items__item_id__get",
"parameters": [
{
"required": True,
"schema": {"title": "User Id", "type": "integer"},
"name": "user_id",
"in": "path",
},
{
"required": True,
"schema": {"title": "Item Id", "type": "string"},
"name": "item_id",
"in": "path",
},
{
"required": False,
"schema": {
"title": "Q",
"anyOf": [
{
"type": "string",
},
{
"type": "null",
},
],
},
"name": "q",
"in": "query",
},
{
"required": False,
"schema": {
"title": "Short",
"type": "boolean",
"default": False,
},
"name": "short",
"in": "query",
},
],
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError",
},
},
},
"description": "Validation Error",
},
},
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,121 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(
f"docs_src.query_params_str_validations.{request.param}"
)
client = TestClient(mod.app)
return client
def test_query_params_str_validations_no_query(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200
assert response.json() == {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
def test_query_params_str_validations_q_empty_str(client: TestClient):
response = client.get("/items/", params={"q": ""})
assert response.status_code == 200
assert response.json() == {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
def test_query_params_str_validations_q_query(client: TestClient):
response = client.get("/items/", params={"q": "query"})
assert response.status_code == 200
assert response.json() == {
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
"q": "query",
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Items",
"operationId": "read_items_items__get",
"parameters": [
{
"required": False,
"schema": {
"anyOf": [
{"type": "string"},
{"type": "null"},
],
"title": "Q",
},
"name": "q",
"in": "query",
}
],
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,142 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(
f"docs_src.query_params_str_validations.{request.param}"
)
client = TestClient(mod.app)
return client
def test_query_params_str_validations_no_query(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200
assert response.json() == {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
def test_query_params_str_validations_q_empty_str(client: TestClient):
response = client.get("/items/", params={"q": ""})
assert response.status_code == 200
assert response.json() == {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
def test_query_params_str_validations_q_query(client: TestClient):
response = client.get("/items/", params={"q": "query"})
assert response.status_code == 200
assert response.json() == {
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
"q": "query",
}
def test_query_params_str_validations_q_too_long(client: TestClient):
response = client.get("/items/", params={"q": "q" * 51})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "string_too_long",
"loc": ["query", "q"],
"msg": "String should have at most 50 characters",
"input": "q" * 51,
"ctx": {"max_length": 50},
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Items",
"operationId": "read_items_items__get",
"parameters": [
{
"required": False,
"schema": {
"anyOf": [
{
"type": "string",
"maxLength": 50,
},
{"type": "null"},
],
"title": "Q",
},
"name": "q",
"in": "query",
}
],
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,153 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
pytest.param("tutorial003_an_py39"),
pytest.param("tutorial003_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(
f"docs_src.query_params_str_validations.{request.param}"
)
client = TestClient(mod.app)
return client
def test_query_params_str_validations_no_query(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200
assert response.json() == {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
def test_query_params_str_validations_q_query(client: TestClient):
response = client.get("/items/", params={"q": "query"})
assert response.status_code == 200
assert response.json() == {
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
"q": "query",
}
def test_query_params_str_validations_q_too_short(client: TestClient):
response = client.get("/items/", params={"q": "qu"})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "string_too_short",
"loc": ["query", "q"],
"msg": "String should have at least 3 characters",
"input": "qu",
"ctx": {"min_length": 3},
}
]
}
def test_query_params_str_validations_q_too_long(client: TestClient):
response = client.get("/items/", params={"q": "q" * 51})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "string_too_long",
"loc": ["query", "q"],
"msg": "String should have at most 50 characters",
"input": "q" * 51,
"ctx": {"max_length": 50},
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Items",
"operationId": "read_items_items__get",
"parameters": [
{
"required": False,
"schema": {
"anyOf": [
{
"type": "string",
"minLength": 3,
"maxLength": 50,
},
{"type": "null"},
],
"title": "Q",
},
"name": "q",
"in": "query",
}
],
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,147 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
pytest.param("tutorial004_an_py39"),
pytest.param("tutorial004_an_py310", marks=needs_py310),
pytest.param(
"tutorial004_regex_an_py310",
marks=(
needs_py310,
pytest.mark.filterwarnings(
"ignore:`regex` has been deprecated, please use `pattern` instead:DeprecationWarning"
),
),
),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(
f"docs_src.query_params_str_validations.{request.param}"
)
client = TestClient(mod.app)
return client
def test_query_params_str_validations_no_query(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200
assert response.json() == {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
def test_query_params_str_validations_q_fixedquery(client: TestClient):
response = client.get("/items/", params={"q": "fixedquery"})
assert response.status_code == 200
assert response.json() == {
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
"q": "fixedquery",
}
def test_query_params_str_validations_q_nonregexquery(client: TestClient):
response = client.get("/items/", params={"q": "nonregexquery"})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "string_pattern_mismatch",
"loc": ["query", "q"],
"msg": "String should match pattern '^fixedquery$'",
"input": "nonregexquery",
"ctx": {"pattern": "^fixedquery$"},
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Items",
"operationId": "read_items_items__get",
"parameters": [
{
"required": False,
"schema": {
"anyOf": [
{
"type": "string",
"minLength": 3,
"maxLength": 50,
"pattern": "^fixedquery$",
},
{"type": "null"},
],
"title": "Q",
},
"name": "q",
"in": "query",
}
],
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,131 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial005_py39"),
pytest.param("tutorial005_an_py39"),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(
f"docs_src.query_params_str_validations.{request.param}"
)
client = TestClient(mod.app)
return client
def test_query_params_str_validations_no_query(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200
assert response.json() == {
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
"q": "fixedquery",
}
def test_query_params_str_validations_q_query(client: TestClient):
response = client.get("/items/", params={"q": "query"})
assert response.status_code == 200
assert response.json() == {
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
"q": "query",
}
def test_query_params_str_validations_q_short(client: TestClient):
response = client.get("/items/", params={"q": "fa"})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "string_too_short",
"loc": ["query", "q"],
"msg": "String should have at least 3 characters",
"input": "fa",
"ctx": {"min_length": 3},
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Items",
"operationId": "read_items_items__get",
"parameters": [
{
"required": False,
"schema": {
"type": "string",
"default": "fixedquery",
"minLength": 3,
"title": "Q",
},
"name": "q",
"in": "query",
}
],
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,136 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial006_py39"),
pytest.param("tutorial006_an_py39"),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(
f"docs_src.query_params_str_validations.{request.param}"
)
client = TestClient(mod.app)
return client
def test_query_params_str_validations_no_query(client: TestClient):
response = client.get("/items/")
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "missing",
"loc": ["query", "q"],
"msg": "Field required",
"input": None,
}
]
}
def test_query_params_str_validations_q_fixedquery(client: TestClient):
response = client.get("/items/", params={"q": "fixedquery"})
assert response.status_code == 200
assert response.json() == {
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
"q": "fixedquery",
}
def test_query_params_str_validations_q_fixedquery_too_short(client: TestClient):
response = client.get("/items/", params={"q": "fa"})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "string_too_short",
"loc": ["query", "q"],
"msg": "String should have at least 3 characters",
"input": "fa",
"ctx": {"min_length": 3},
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Items",
"operationId": "read_items_items__get",
"parameters": [
{
"required": True,
"schema": {
"type": "string",
"minLength": 3,
"title": "Q",
},
"name": "q",
"in": "query",
}
],
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,148 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial006c_py39"),
pytest.param("tutorial006c_py310", marks=needs_py310),
pytest.param("tutorial006c_an_py39"),
pytest.param("tutorial006c_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(
f"docs_src.query_params_str_validations.{request.param}"
)
client = TestClient(mod.app)
return client
@pytest.mark.xfail(
reason="Code example is not valid. See https://github.com/fastapi/fastapi/issues/12419"
)
def test_query_params_str_validations_no_query(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200
assert response.json() == { # pragma: no cover
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
}
@pytest.mark.xfail(
reason="Code example is not valid. See https://github.com/fastapi/fastapi/issues/12419"
)
def test_query_params_str_validations_empty_str(client: TestClient):
response = client.get("/items/?q=")
assert response.status_code == 200
assert response.json() == { # pragma: no cover
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
}
def test_query_params_str_validations_q_query(client: TestClient):
response = client.get("/items/", params={"q": "query"})
assert response.status_code == 200
assert response.json() == {
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
"q": "query",
}
def test_query_params_str_validations_q_short(client: TestClient):
response = client.get("/items/", params={"q": "fa"})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "string_too_short",
"loc": ["query", "q"],
"msg": "String should have at least 3 characters",
"input": "fa",
"ctx": {"min_length": 3},
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Items",
"operationId": "read_items_items__get",
"parameters": [
{
"required": True,
"schema": {
"anyOf": [
{"type": "string", "minLength": 3},
{"type": "null"},
],
"title": "Q",
},
"name": "q",
"in": "query",
}
],
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,136 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial007_py39"),
pytest.param("tutorial007_py310", marks=needs_py310),
pytest.param("tutorial007_an_py39"),
pytest.param("tutorial007_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(
f"docs_src.query_params_str_validations.{request.param}"
)
client = TestClient(mod.app)
return client
def test_query_params_str_validations_no_query(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200
assert response.json() == {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
def test_query_params_str_validations_q_fixedquery(client: TestClient):
response = client.get("/items/", params={"q": "fixedquery"})
assert response.status_code == 200
assert response.json() == {
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
"q": "fixedquery",
}
def test_query_params_str_validations_q_fixedquery_too_short(client: TestClient):
response = client.get("/items/", params={"q": "fa"})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "string_too_short",
"loc": ["query", "q"],
"msg": "String should have at least 3 characters",
"input": "fa",
"ctx": {"min_length": 3},
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Items",
"operationId": "read_items_items__get",
"parameters": [
{
"required": False,
"schema": {
"anyOf": [
{
"type": "string",
"minLength": 3,
},
{"type": "null"},
],
"title": "Query string",
},
"name": "q",
"in": "query",
}
],
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,138 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial008_py39"),
pytest.param("tutorial008_py310", marks=needs_py310),
pytest.param("tutorial008_an_py39"),
pytest.param("tutorial008_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(
f"docs_src.query_params_str_validations.{request.param}"
)
client = TestClient(mod.app)
return client
def test_query_params_str_validations_no_query(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200
assert response.json() == {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
def test_query_params_str_validations_q_fixedquery(client: TestClient):
response = client.get("/items/", params={"q": "fixedquery"})
assert response.status_code == 200
assert response.json() == {
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
"q": "fixedquery",
}
def test_query_params_str_validations_q_fixedquery_too_short(client: TestClient):
response = client.get("/items/", params={"q": "fa"})
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"type": "string_too_short",
"loc": ["query", "q"],
"msg": "String should have at least 3 characters",
"input": "fa",
"ctx": {"min_length": 3},
}
]
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Items",
"operationId": "read_items_items__get",
"parameters": [
{
"description": "Query string for the items to search in the database that have a good match",
"required": False,
"schema": {
"anyOf": [
{
"type": "string",
"minLength": 3,
},
{"type": "null"},
],
"title": "Query string",
"description": "Query string for the items to search in the database that have a good match",
},
"name": "q",
"in": "query",
}
],
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,123 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial009_py39"),
pytest.param("tutorial009_py310", marks=needs_py310),
pytest.param("tutorial009_an_py39"),
pytest.param("tutorial009_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(
f"docs_src.query_params_str_validations.{request.param}"
)
client = TestClient(mod.app)
return client
def test_query_params_str_validations_no_query(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200
assert response.json() == {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
def test_query_params_str_validations_item_query_fixedquery(client: TestClient):
response = client.get("/items/", params={"item-query": "fixedquery"})
assert response.status_code == 200
assert response.json() == {
"items": [{"item_id": "Foo"}, {"item_id": "Bar"}],
"q": "fixedquery",
}
def test_query_params_str_validations_q_fixedquery(client: TestClient):
response = client.get("/items/", params={"q": "fixedquery"})
assert response.status_code == 200
assert response.json() == {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Read Items",
"operationId": "read_items_items__get",
"parameters": [
{
"schema": {
"anyOf": [
{"type": "string"},
{"type": "null"},
],
"title": "Item-Query",
},
"required": False,
"name": "item-query",
"in": "query",
}
],
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,65 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39"),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.response_directly.{request.param}")
client = TestClient(mod.app)
return client
def test_path_operation(client: TestClient):
expected_content = """<?xml version="1.0"?>
<shampoo>
<Header>
Apply shampoo here.
</Header>
<Body>
You'll have to use soap here.
</Body>
</shampoo>
"""
response = client.get("/legacy/")
assert response.status_code == 200, response.text
assert response.headers["content-type"] == "application/xml"
assert response.text == expected_content
def test_openapi_schema(client: TestClient):
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": {
"/legacy/": {
"get": {
"operationId": "get_legacy_data_legacy__get",
"responses": {
"200": {
"content": {
"application/json": {
"schema": {},
},
},
"description": "Successful Response",
},
},
"summary": "Get Legacy Data",
},
},
},
}

View File

@@ -0,0 +1,193 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial001_py39"),
pytest.param("tutorial001_py310", marks=needs_py310),
pytest.param("tutorial001_01_py39"),
pytest.param("tutorial001_01_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.response_model.{request.param}")
client = TestClient(mod.app)
return client
def test_read_items(client: TestClient):
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [
{
"name": "Portal Gun",
"description": None,
"price": 42.0,
"tags": [],
"tax": None,
},
{
"name": "Plumbus",
"description": None,
"price": 32.0,
"tags": [],
"tax": None,
},
]
def test_create_item(client: TestClient):
item_data = {
"name": "Test Item",
"description": "A test item",
"price": 10.5,
"tax": 1.5,
"tags": ["test", "item"],
}
response = client.post("/items/", json=item_data)
assert response.status_code == 200, response.text
assert response.json() == item_data
def test_create_item_only_required(client: TestClient):
response = client.post(
"/items/",
json={
"name": "Test Item",
"price": 10.5,
},
)
assert response.status_code == 200, response.text
assert response.json() == {
"name": "Test Item",
"price": 10.5,
"description": None,
"tax": None,
"tags": [],
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {"$ref": "#/components/schemas/Item"},
"title": "Response Read Items Items Get",
}
}
},
},
},
"summary": "Read Items",
"operationId": "read_items_items__get",
},
"post": {
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Item",
},
},
},
"required": True,
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"},
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Create Item",
"operationId": "create_item_items__post",
},
}
},
"components": {
"schemas": {
"Item": {
"title": "Item",
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"title": "Name", "type": "string"},
"price": {"title": "Price", "type": "number"},
"description": {
"title": "Description",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"tax": {
"title": "Tax",
"anyOf": [{"type": "number"}, {"type": "null"}],
},
"tags": {
"title": "Tags",
"type": "array",
"items": {"type": "string"},
"default": [],
},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,129 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.response_model.{request.param}")
client = TestClient(mod.app)
return client
def test_post_user(client: TestClient):
user_data = {
"username": "foo",
"password": "fighter",
"email": "foo@example.com",
"full_name": "Grave Dohl",
}
response = client.post(
"/user/",
json=user_data,
)
assert response.status_code == 200, response.text
assert response.json() == user_data
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/user/": {
"post": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/UserIn"}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Create User",
"operationId": "create_user_user__post",
"requestBody": {
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/UserIn"}
}
},
"required": True,
},
}
}
},
"components": {
"schemas": {
"UserIn": {
"title": "UserIn",
"required": ["username", "password", "email"],
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
"password": {"title": "Password", "type": "string"},
"email": {
"title": "Email",
"type": "string",
"format": "email",
},
"full_name": {
"title": "Full Name",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

View File

@@ -0,0 +1,96 @@
import importlib
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial001_py39"),
pytest.param("tutorial002_py39"),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.response_status_code.{request.param}")
client = TestClient(mod.app)
return client
def test_create_item(client: TestClient):
response = client.post("/items/", params={"name": "Test Item"})
assert response.status_code == 201, response.text
assert response.json() == {"name": "Test Item"}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/": {
"post": {
"parameters": [
{
"name": "name",
"in": "query",
"required": True,
"schema": {"title": "Name", "type": "string"},
}
],
"summary": "Create Item",
"operationId": "create_item_items__post",
"responses": {
"201": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
}
}
},
"components": {
"schemas": {
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
}
},
}

View File

@@ -0,0 +1,141 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.schema_extra_example.{request.param}")
client = TestClient(mod.app)
return client
def test_post_body_example(client: TestClient):
response = client.put(
"/items/5",
json={
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
)
assert response.status_code == 200
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
# insert_assert(response.json())
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"put": {
"summary": "Update Item",
"operationId": "update_item_items__item_id__put",
"parameters": [
{
"name": "item_id",
"in": "path",
"required": True,
"schema": {"type": "integer", "title": "Item Id"},
}
],
"requestBody": {
"required": True,
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Item"}
}
},
},
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {"$ref": "#/components/schemas/ValidationError"},
"type": "array",
"title": "Detail",
}
},
"type": "object",
"title": "HTTPValidationError",
},
"Item": {
"properties": {
"name": {
"type": "string",
"title": "Name",
"examples": ["Foo"],
},
"description": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Description",
"examples": ["A very nice Item"],
},
"price": {
"type": "number",
"title": "Price",
"examples": [35.4],
},
"tax": {
"anyOf": [{"type": "number"}, {"type": "null"}],
"title": "Tax",
"examples": [3.2],
},
},
"type": "object",
"required": ["name", "price"],
"title": "Item",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
"type": "array",
"title": "Location",
},
"msg": {"type": "string", "title": "Message"},
"type": {"type": "string", "title": "Error Type"},
},
"type": "object",
"required": ["loc", "msg", "type"],
"title": "ValidationError",
},
}
},
}

View File

@@ -0,0 +1,143 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial003_py39"),
pytest.param("tutorial003_py310", marks=needs_py310),
pytest.param("tutorial003_an_py39"),
pytest.param("tutorial003_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.schema_extra_example.{request.param}")
client = TestClient(mod.app)
return client
def test_post_body_example(client: TestClient):
response = client.put(
"/items/5",
json={
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
)
assert response.status_code == 200
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
# insert_assert(response.json())
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/items/{item_id}": {
"put": {
"summary": "Update Item",
"operationId": "update_item_items__item_id__put",
"parameters": [
{
"name": "item_id",
"in": "path",
"required": True,
"schema": {"type": "integer", "title": "Item Id"},
}
],
"requestBody": {
"required": True,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Item",
"examples": [
{
"description": "A very nice Item",
"name": "Foo",
"price": 35.4,
"tax": 3.2,
}
],
},
}
},
},
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {"$ref": "#/components/schemas/ValidationError"},
"type": "array",
"title": "Detail",
}
},
"type": "object",
"title": "HTTPValidationError",
},
"Item": {
"properties": {
"name": {"type": "string", "title": "Name"},
"description": {
"anyOf": [{"type": "string"}, {"type": "null"}],
"title": "Description",
},
"price": {"type": "number", "title": "Price"},
"tax": {
"anyOf": [{"type": "number"}, {"type": "null"}],
"title": "Tax",
},
},
"type": "object",
"required": ["name", "price"],
"title": "Item",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
"type": "array",
"title": "Location",
},
"msg": {"type": "string", "title": "Message"},
"type": {"type": "string", "title": "Error Type"},
},
"type": "object",
"required": ["loc", "msg", "type"],
"title": "ValidationError",
},
}
},
}

View File

@@ -0,0 +1,71 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial002_py39"),
pytest.param("tutorial002_py310", marks=needs_py310),
pytest.param("tutorial002_an_py39"),
pytest.param("tutorial002_an_py310", marks=needs_py310),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.security.{request.param}")
client = TestClient(mod.app)
return client
def test_no_token(client: TestClient):
response = client.get("/users/me")
assert response.status_code == 401, response.text
assert response.json() == {"detail": "Not authenticated"}
assert response.headers["WWW-Authenticate"] == "Bearer"
def test_token(client: TestClient):
response = client.get("/users/me", headers={"Authorization": "Bearer testtoken"})
assert response.status_code == 200, response.text
assert response.json() == {
"username": "testtokenfakedecoded",
"email": "john@example.com",
"full_name": "John Doe",
"disabled": None,
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
"summary": "Read Users Me",
"operationId": "read_users_me_users_me_get",
"security": [{"OAuth2PasswordBearer": []}],
}
}
},
"components": {
"securitySchemes": {
"OAuth2PasswordBearer": {
"type": "oauth2",
"flows": {"password": {"scopes": {}, "tokenUrl": "token"}},
}
},
},
}

View File

@@ -0,0 +1,363 @@
import importlib
from types import ModuleType
from unittest.mock import patch
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py310
@pytest.fixture(
name="mod",
params=[
pytest.param("tutorial004_py39"),
pytest.param("tutorial004_py310", marks=needs_py310),
pytest.param("tutorial004_an_py39"),
pytest.param("tutorial004_an_py310", marks=needs_py310),
],
)
def get_mod(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.security.{request.param}")
return mod
def get_access_token(*, username="johndoe", password="secret", client: TestClient):
data = {"username": username, "password": password}
response = client.post("/token", data=data)
content = response.json()
access_token = content.get("access_token")
return access_token
def test_login(mod: ModuleType):
client = TestClient(mod.app)
response = client.post("/token", data={"username": "johndoe", "password": "secret"})
assert response.status_code == 200, response.text
content = response.json()
assert "access_token" in content
assert content["token_type"] == "bearer"
def test_login_incorrect_password(mod: ModuleType):
client = TestClient(mod.app)
response = client.post(
"/token", data={"username": "johndoe", "password": "incorrect"}
)
assert response.status_code == 401, response.text
assert response.json() == {"detail": "Incorrect username or password"}
def test_login_incorrect_username(mod: ModuleType):
client = TestClient(mod.app)
response = client.post("/token", data={"username": "foo", "password": "secret"})
assert response.status_code == 401, response.text
assert response.json() == {"detail": "Incorrect username or password"}
def test_no_token(mod: ModuleType):
client = TestClient(mod.app)
response = client.get("/users/me")
assert response.status_code == 401, response.text
assert response.json() == {"detail": "Not authenticated"}
assert response.headers["WWW-Authenticate"] == "Bearer"
def test_token(mod: ModuleType):
client = TestClient(mod.app)
access_token = get_access_token(client=client)
response = client.get(
"/users/me", headers={"Authorization": f"Bearer {access_token}"}
)
assert response.status_code == 200, response.text
assert response.json() == {
"username": "johndoe",
"full_name": "John Doe",
"email": "johndoe@example.com",
"disabled": False,
}
def test_incorrect_token(mod: ModuleType):
client = TestClient(mod.app)
response = client.get("/users/me", headers={"Authorization": "Bearer nonexistent"})
assert response.status_code == 401, response.text
assert response.json() == {"detail": "Could not validate credentials"}
assert response.headers["WWW-Authenticate"] == "Bearer"
def test_incorrect_token_type(mod: ModuleType):
client = TestClient(mod.app)
response = client.get(
"/users/me", headers={"Authorization": "Notexistent testtoken"}
)
assert response.status_code == 401, response.text
assert response.json() == {"detail": "Not authenticated"}
assert response.headers["WWW-Authenticate"] == "Bearer"
def test_verify_password(mod: ModuleType):
assert mod.verify_password(
"secret", mod.fake_users_db["johndoe"]["hashed_password"]
)
def test_get_password_hash(mod: ModuleType):
assert mod.get_password_hash("johndoe")
def test_create_access_token(mod: ModuleType):
access_token = mod.create_access_token(data={"data": "foo"})
assert access_token
def test_token_no_sub(mod: ModuleType):
client = TestClient(mod.app)
response = client.get(
"/users/me",
headers={
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjoiZm9vIn0.9ynBhuYb4e6aW3oJr_K_TBgwcMTDpRToQIE25L57rOE"
},
)
assert response.status_code == 401, response.text
assert response.json() == {"detail": "Could not validate credentials"}
assert response.headers["WWW-Authenticate"] == "Bearer"
def test_token_no_username(mod: ModuleType):
client = TestClient(mod.app)
response = client.get(
"/users/me",
headers={
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmb28ifQ.NnExK_dlNAYyzACrXtXDrcWOgGY2JuPbI4eDaHdfK5Y"
},
)
assert response.status_code == 401, response.text
assert response.json() == {"detail": "Could not validate credentials"}
assert response.headers["WWW-Authenticate"] == "Bearer"
def test_token_nonexistent_user(mod: ModuleType):
client = TestClient(mod.app)
response = client.get(
"/users/me",
headers={
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VybmFtZTpib2IifQ.HcfCW67Uda-0gz54ZWTqmtgJnZeNem0Q757eTa9EZuw"
},
)
assert response.status_code == 401, response.text
assert response.json() == {"detail": "Could not validate credentials"}
assert response.headers["WWW-Authenticate"] == "Bearer"
def test_token_inactive_user(mod: ModuleType):
client = TestClient(mod.app)
alice_user_data = {
"username": "alice",
"full_name": "Alice Wonderson",
"email": "alice@example.com",
"hashed_password": mod.get_password_hash("secretalice"),
"disabled": True,
}
with patch.dict(f"{mod.__name__}.fake_users_db", {"alice": alice_user_data}):
access_token = get_access_token(
username="alice", password="secretalice", client=client
)
response = client.get(
"/users/me", headers={"Authorization": f"Bearer {access_token}"}
)
assert response.status_code == 400, response.text
assert response.json() == {"detail": "Inactive user"}
def test_read_items(mod: ModuleType):
client = TestClient(mod.app)
access_token = get_access_token(client=client)
response = client.get(
"/users/me/items/", headers={"Authorization": f"Bearer {access_token}"}
)
assert response.status_code == 200, response.text
assert response.json() == [{"item_id": "Foo", "owner": "johndoe"}]
def test_openapi_schema(mod: ModuleType):
client = TestClient(mod.app)
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/token": {
"post": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/Token"}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
"summary": "Login For Access Token",
"operationId": "login_for_access_token_token_post",
"requestBody": {
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/Body_login_for_access_token_token_post"
}
}
},
"required": True,
},
}
},
"/users/me/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/User"}
}
},
}
},
"summary": "Read Users Me",
"operationId": "read_users_me_users_me__get",
"security": [{"OAuth2PasswordBearer": []}],
}
},
"/users/me/items/": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
"summary": "Read Own Items",
"operationId": "read_own_items_users_me_items__get",
"security": [{"OAuth2PasswordBearer": []}],
}
},
},
"components": {
"schemas": {
"User": {
"title": "User",
"required": ["username"],
"type": "object",
"properties": {
"username": {"title": "Username", "type": "string"},
"email": {
"title": "Email",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"full_name": {
"title": "Full Name",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"disabled": {
"title": "Disabled",
"anyOf": [{"type": "boolean"}, {"type": "null"}],
},
},
},
"Token": {
"title": "Token",
"required": ["access_token", "token_type"],
"type": "object",
"properties": {
"access_token": {"title": "Access Token", "type": "string"},
"token_type": {"title": "Token Type", "type": "string"},
},
},
"Body_login_for_access_token_token_post": {
"title": "Body_login_for_access_token_token_post",
"required": ["username", "password"],
"type": "object",
"properties": {
"grant_type": {
"title": "Grant Type",
"anyOf": [
{"pattern": "^password$", "type": "string"},
{"type": "null"},
],
},
"username": {"title": "Username", "type": "string"},
"password": {
"title": "Password",
"type": "string",
"format": "password",
},
"scope": {"title": "Scope", "type": "string", "default": ""},
"client_id": {
"title": "Client Id",
"anyOf": [{"type": "string"}, {"type": "null"}],
},
"client_secret": {
"title": "Client Secret",
"anyOf": [{"type": "string"}, {"type": "null"}],
"format": "password",
},
},
},
"ValidationError": {
"title": "ValidationError",
"required": ["loc", "msg", "type"],
"type": "object",
"properties": {
"loc": {
"title": "Location",
"type": "array",
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
},
"msg": {"title": "Message", "type": "string"},
"type": {"title": "Error Type", "type": "string"},
},
},
"HTTPValidationError": {
"title": "HTTPValidationError",
"type": "object",
"properties": {
"detail": {
"title": "Detail",
"type": "array",
"items": {"$ref": "#/components/schemas/ValidationError"},
}
},
},
},
"securitySchemes": {
"OAuth2PasswordBearer": {
"type": "oauth2",
"flows": {
"password": {
"scopes": {},
"tokenUrl": "token",
}
},
}
},
},
}

View File

@@ -0,0 +1,89 @@
import importlib
from base64 import b64encode
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(
name="client",
params=[
pytest.param("tutorial007_py39"),
pytest.param("tutorial007_an_py39"),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.security.{request.param}")
return TestClient(mod.app)
def test_security_http_basic(client: TestClient):
response = client.get("/users/me", auth=("stanleyjobson", "swordfish"))
assert response.status_code == 200, response.text
assert response.json() == {"username": "stanleyjobson"}
def test_security_http_basic_no_credentials(client: TestClient):
response = client.get("/users/me")
assert response.json() == {"detail": "Not authenticated"}
assert response.status_code == 401, response.text
assert response.headers["WWW-Authenticate"] == "Basic"
def test_security_http_basic_invalid_credentials(client: TestClient):
response = client.get(
"/users/me", headers={"Authorization": "Basic notabase64token"}
)
assert response.status_code == 401, response.text
assert response.headers["WWW-Authenticate"] == "Basic"
assert response.json() == {"detail": "Not authenticated"}
def test_security_http_basic_non_basic_credentials(client: TestClient):
payload = b64encode(b"johnsecret").decode("ascii")
auth_header = f"Basic {payload}"
response = client.get("/users/me", headers={"Authorization": auth_header})
assert response.status_code == 401, response.text
assert response.headers["WWW-Authenticate"] == "Basic"
assert response.json() == {"detail": "Not authenticated"}
def test_security_http_basic_invalid_username(client: TestClient):
response = client.get("/users/me", auth=("alice", "swordfish"))
assert response.status_code == 401, response.text
assert response.json() == {"detail": "Incorrect username or password"}
assert response.headers["WWW-Authenticate"] == "Basic"
def test_security_http_basic_invalid_password(client: TestClient):
response = client.get("/users/me", auth=("stanleyjobson", "wrongpassword"))
assert response.status_code == 401, response.text
assert response.json() == {"detail": "Incorrect username or password"}
assert response.headers["WWW-Authenticate"] == "Basic"
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/users/me": {
"get": {
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
"summary": "Read Current User",
"operationId": "read_current_user_users_me_get",
"security": [{"HTTPBasic": []}],
}
}
},
"components": {
"securitySchemes": {"HTTPBasic": {"type": "http", "scheme": "basic"}}
},
}

View File

@@ -0,0 +1,78 @@
import importlib
import sys
import pytest
from dirty_equals import IsAnyStr
from fastapi.testclient import TestClient
from pydantic import ValidationError
from pytest import MonkeyPatch
@pytest.fixture(
name="mod_name",
params=[
pytest.param("app01_py39"),
],
)
def get_mod_name(request: pytest.FixtureRequest):
return f"docs_src.settings.{request.param}.main"
@pytest.fixture(name="client")
def get_test_client(mod_name: str, monkeypatch: MonkeyPatch) -> TestClient:
if mod_name in sys.modules:
del sys.modules[mod_name]
monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com")
main_mod = importlib.import_module(mod_name)
return TestClient(main_mod.app)
def test_settings_validation_error(mod_name: str, monkeypatch: MonkeyPatch):
monkeypatch.delenv("ADMIN_EMAIL", raising=False)
if mod_name in sys.modules:
del sys.modules[mod_name] # pragma: no cover
with pytest.raises(ValidationError) as exc_info:
importlib.import_module(mod_name)
assert exc_info.value.errors() == [
{
"loc": ("admin_email",),
"msg": "Field required",
"type": "missing",
"input": {},
"url": IsAnyStr,
}
]
def test_app(client: TestClient):
response = client.get("/info")
data = response.json()
assert data == {
"app_name": "Awesome API",
"admin_email": "admin@example.com",
"items_per_user": 50,
}
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
"/info": {
"get": {
"operationId": "info_info_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
"summary": "Info",
}
}
},
}

View File

View File

@@ -0,0 +1,40 @@
import os
from pathlib import Path
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(scope="module")
def client():
static_dir: Path = Path(os.getcwd()) / "static"
static_dir.mkdir(exist_ok=True)
sample_file = static_dir / "sample.txt"
sample_file.write_text("This is a sample static file.")
from docs_src.static_files.tutorial001_py39 import app
with TestClient(app) as client:
yield client
sample_file.unlink()
static_dir.rmdir()
def test_static_files(client: TestClient):
response = client.get("/static/sample.txt")
assert response.status_code == 200, response.text
assert response.text == "This is a sample static file."
def test_static_files_not_found(client: TestClient):
response = client.get("/static/non_existent_file.txt")
assert response.status_code == 404, response.text
def test_openapi_schema(client: TestClient):
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == {
"openapi": "3.1.0",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {},
}